JDK动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
CGLib动态代理:利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1. JDK动态代理
1.1 角色
- Interface:对于JDK Proxy,业务类是需要一个Interface的。
- Proxy:Proxy类是动态产生的,这个类在调用Proxy.newProxyInstance()方法之后,产生一个Proxy类的实力。实际上,这个Proxy类也是存在的,不仅仅是类的实例,这个Proxy类可以保存在硬盘上。
- Method:对于业务委托类的每个方法,现在Proxy类里面都不用静态显示出来。
- InvocationHandler:这个类在业务委托类执行时,会先调用invoke方法。invoke方法在执行想要的代理操作,可以实现对业务方法的再包装。
1.2 总结
- JDK动态代理类实现了InvocationHandler接口,重写的invoke方法。
- JDK动态代理的基础是反射机制(method.invoke(对象,参数))Proxy.newProxyInstance()。
1.3 动态代理步骤
- 创建被代理类及接口(JDK代理是接口代理)
- 创建Handle类实现 InvocationHandler接口 ,重写invoke方法
- 通过Proxy的newProxyInstance()方法获取代理类对象
- 通过代理类对象调用被代理类的方法
1.4 代码实现
//接口类 public interface FoodService { public void makeNoodle(); public void makeChicken(); } //代理类,实现定义的接口 public class FoodServiceImpl implements FoodService { @Override public void makeNoodle() { System.out.println("make noodle"); } @Override public void makeChicken() { System.out.println("make Chicken"); } }
public class JDKProxyFactory implements InvocationHandler { private Object target; public JDKProxyFactory(Object target) { super(); this.target = target; } // 创建代理对象 public Object createProxy() { // 1.得到目标对象的类加载器 ClassLoader classLoader = target.getClass().getClassLoader(); // 2.得到目标对象的实现接口 Class<?>[] interfaces = target.getClass().getInterfaces(); // 3.第三个参数需要一个实现invocationHandler接口的对象 Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this); return newProxyInstance; } // 第一个参数:代理对象.一般不使用;第二个参数:需要增强的方法;第三个参数:方法中的参数 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("这是增强方法前......"); Object invoke = method.invoke(target, args); System.out.println("这是增强方法后......"); return invoke; } public static void main(String[] args) { // 1.创建对象 FoodServiceImpl foodService = new FoodServiceImpl(); // 2.创建代理对象 JDKProxyFactory proxy = new JDKProxyFactory(foodService); // 3.调用代理对象的增强方法,得到增强后的对象 FoodService createProxy = (FoodService) proxy.createProxy(); createProxy.makeChicken(); } }
2. CGLib动态代理
强制使用CGLib
<!-- proxy-target-class="false"默认使用JDK动态代理 --> <aop:aspectj-autoproxy proxy-target-class="true"/> <aop-config proxy-target-class="true"> <!-- 切面详细配置 --> </aop-config>
public class CglibProxyFactory implements MethodInterceptor { //得到目标对象 private Object target; //使用构造方法传递目标对象 public CglibProxyFactory(Object target) { super(); this.target = target; } //创建代理对象 public Object createProxy(){ //1.创建Enhancer Enhancer enhancer = new Enhancer(); //2.传递目标对象的class enhancer.setSuperclass(target.getClass()); //3.设置回调操作 enhancer.setCallback(this); return enhancer.create(); } //参数一:代理对象;参数二:需要增强的方法;参数三:需要增强方法的参数;参数四:需要增强的方法的代理 public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("这是增强方法前......"); Object invoke = methodProxy.invoke(target, args); System.out.println("这是增强方法后......"); return invoke; } public static void main(String[] args) { // 1.创建对象 FoodServiceImpl foodService = new FoodServiceImpl(); // 2.创建代理对象 CglibProxyFactory proxy = new CglibProxyFactory(foodService); // 3.调用代理对象的增强方法,得到增强后的对象 FoodService createProxy = (FoodService) proxy.createProxy(); createProxy.makeChicken(); } }
3. 两者区别
- JDK代理只能对实现接口的类生成代理;CGLib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式,不能代理final修饰的类。
- JDK代理使用的是反射机制实现aop的动态代理,CGLib代理使用字节码处理框架ASM,通过修改字节码生成子类。所以jdk动态代理的方式创建代理对象效率较高,执行效率较低,CGLib创建效率较低,执行效率高。
- JDK动态代理机制是委托机制,具体说动态实现接口类,在动态生成的实现类里面委托hanlder去调用原始实现类方法,CGLib则使用的继承机制,具体说被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。