基于动态代理的两种方式(JDK动态代理,cglib动态代理)一直是心里的一个梗,每次看到动态代理,脑海中都会想到这两种方式,也仅仅只是想到这两种方式。至于里面的实现方式和实现思路还是很模糊。所以今天想借助该平台对这两种方式以案例形式来进行一个详细的解说,方便自己,奉献你们。
Brandy现在想要买一台联想电脑,联想公司总部在北京,它不仅卖电脑,还生产电脑。由于距北京距离太远,直接去北京总部买一台联想电脑,不划算。这时候,在西安有一家联想电脑专卖店,也是卖联想电脑,从北京联想公司进货。然后销售给客户,他们从中间赚取一些差价。当用户从西安联想代理商购买一台联想电脑时,西安联想代理商还是要从北京总部进货。由于代理商从中间专区用户的一些差价,用户心里肯定很不平衡,为了不让客户失落,西安联想代理商在给用户送电脑时,可以赠送一些小礼品,抚慰用户。下图是对本需求的描述,针对此需求,使用动态代理的两种技术来实现此需求。
JDK动态代理是一套基于接口的动态代理技术,目标(真实)对象和代理对象实现相同的接口,动态增强目标对象,下图是对基于JDK动态代理的一个描述。
Step 1:创建卖电脑接口
public interface SaleComputer {
public String sale(double money);
public void show();
}
Step 2:创建联想对象(目标对象)
public class Lenovo implements SaleComputer {
@Override
public String sale(double money) {
System.out.println("花了" + money + "元买了一台联想电脑...");
return "联想电脑";
}
@Override
public void show() {
System.out.println("展示电脑....");
}
}
Step 3:创建增强对象
public class Advice {
public void before(){
System.out.println("专车接你....");
}
public void after(){
System.out.println("免费送货...");
}
}
Step 4:创建代理测试类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
//1.创建真实对象
final Lenovo lenovo = new Lenovo();
//2.创建增强对象
final Advice advice = new Advice();
//2.动态代理增强lenovo对象
/*
三个参数:
1. 类加载器:真实对象.getClass().getClassLoader()
2. 接口数组:真实对象.getClass().getInterfaces()
3. 处理器:new InvocationHandler()
*/
SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
/*
代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法执行
参数:
1. proxy:代理对象
2. method:代理对象调用的方法,被封装为的对象
3. args:代理对象调用的方法时,传递的实际参数
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*System.out.println("该方法执行了....");
System.out.println(method.getName());
System.out.println(args[0]);
*/
//判断是否是sale方法
if(method.getName().equals("sale")){
//1.增强参数
Double money = (Double) args[0];
money = money * 0.85;
//前置增强
advice.before();
//使用真实对象调用该方法
String obj = (String) method.invoke(lenovo, money);
//后置增强
advice.after();
//2.增强返回值
return obj+"_鼠标垫";
}else{
Object obj = method.invoke(lenovo, args);
return obj;
}
}
});
//3.调用方法
String computer = proxy_lenovo.sale(8000);
System.out.println(computer);
//proxy_lenovo.show();
}
}
cglib的动态代理是基于父类的动态代理技术,为目标对象动态生成一个代理对象,增强目标对象的功能,下图是对基于cglib动态代理的一个描述。
Step1:创建联想对象(目标对象)
public class Lenovo{
public String sale(double money) {
System.out.println("花了" + money + "元买了一台联想电脑...");
return "联想电脑";
}
public void show() {
System.out.println("展示电脑....");
}
}
Step 2:创建增强对象
public class Advice {
public void before(){
System.out.println("专车接你....");
}
public void after(){
System.out.println("免费送货...");
}
}
Step 3:创建代理对象测试类
import com.itheima.proxy.jdk1.Advice;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class ProxyTest {
public static void main(String[] args) {
//1.创建真实对象
final Lenovo lenovo = new Lenovo();
//创建增强对象
final Advice advice = new Advice();
//2.动态代理增强lenovo对象 基于cglib
//创建增强器
Enhancer enhancer = new Enhancer();
//设置父类(目标)
enhancer.setSuperclass(Lenovo.class);
//设置回调
enhancer.setCallback(new MethodInterceptor() {
/*
代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法执行
参数:
1. proxy:代理对象
2. method:代理对象调用的方法,被封装为的对象
3. args:代理对象调用的方法时,传递的实际参数
*/
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if(method.getName().equals("sale")){
Double money = (Double) args[0];
money = money * 0.85;
//执行前置
advice.before();
//执行目标
Object invoke = method.invoke(lenovo, money);
//执行后置
advice.after();
return invoke+"_鼠标垫";
}else {
Object invoke = method.invoke(lenovo, args);
return invoke;
}
}
});
//创建代理对象
Lenovo proxy = (Lenovo) enhancer.create();
String computer = proxy.sale(8000);
System.out.println(computer);
//proxy.show();
}
}
基于以上两种动态代理模式运行的结果:
D:\Develop\JDK\bin\java ...
专车接你....
花了6800.0元买了一台联想电脑...
免费送货...
联想电脑_鼠标垫
Process finished with exit code 0