问题
另一篇博文中的问题
CGLib动态代理和JDK动态代理的区别
我们知道使用JDK创建代理时只能为接口创建代理实例。我们从Proxy的newProxyInstance方法中可以看出
@CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
第二个参数interfaces就是需要代理实例实现的接口列表。
对于没有通用接口定义业务方法的类,该如何动态创建代理实例呢?
JDK动态代理技术显然无能为力了,CGLib作为一个替代者,很好地解决了这个问题
CGLib概述
CGLib采用底层的字节码技术,可以为一个类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势织入横切逻辑。
改造
代码已托管到Github—> https://github.com/yangshangwei/SpringMaster
首先在我们的java maven工程中 添加依赖
<!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>${cglib.version}</version> </dependency>
使用的版本为 3.2.5
package com.xgj.aop.base.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CglibProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); public Object getProxy(Class clazz) { // 设置需要创建的子类的类 enhancer.setSuperclass(clazz); enhancer.setCallback(this); // 通过字节码动态创建子类实例 return enhancer.create(); } // 拦截父类所有方法的调用 @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 横切逻辑代码 PerformanceMonitor.begin(obj.getClass().getName() + "." + method.getName()); // 业务逻辑,通过代理类调用父类中的方法 Object result = proxy.invokeSuper(obj, args); // 横切逻辑代码 PerformanceMonitor.end(); return result; } }
上述代码,我们通过getProxy(Class clazz)方法为一个类创建动态代理对象,该代理对象通过扩展clazz实现代理。
在这个代理对象中,织入性能监视的横切逻辑。
public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) 是CGLib定义的Interceptor接口方法,它拦截所有目标类方法中的调用。
其中
obj表述目标类的实例
method为目标类方法的反射对象
args为方法的动态入参
proxy为代理类的实例
测试类
通过CglibProxy为ForumSerivceImpl类创建代理对象,并测试代理对象的方法
package com.xgj.aop.base.cglib; public class ForumServiceTest { public static void main(String[] args) { CglibProxy cglibProxy = new CglibProxy(); // 通过动态生成子类的方式创建代理类 ForumServiceImpl forumService = (ForumServiceImpl) cglibProxy .getProxy(ForumServiceImpl.class); // 调用代理类的业务方法 forumService.removeTopic(1); forumService.removeForum(2); } }
运行结果
通过输出,可以看到除了两个业务方法中都织入了性能监控的逻辑外,还发现代理类的名字变成了
com.xgj.aop.base.cglib.ForumServiceImpl$$EnhancerByCGLIB$$2088954a
这个特殊的类就是CGLib为ForumServiceImpl动态创建的子类。
注意:由于cglib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final或者private方法进行代理