cglib是一种动态代理技术,可以针对类来生成一个代理对象。
比如,我们现有一个UserService类:
public class UserService {public void test(){System.out.println("test");}}
现在利用cglib对UserService类中的test()方法进行增强:
public class Main {public static void main(String[] args) {final UserService target = new UserService();Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class);enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {// test方法增加了其他逻辑if (method.getName().equals("test")) {System.out.println("before...");Object result = method.invoke(target, objects);System.out.println("after...");return result;}// 其他方法正常执行return method.invoke(target, objects);}}});UserService userService = (UserService) enhancer.create();userService.test();}}
在分析底层源码实现之前,我们先来试试,cglib能否代理接口,定义一个UserInterface接口:
public interface UserInterface {public void test();}
然后利用cglib来代理一个接口:
public class Main {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserInterface.class);enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {if (method.getName().equals("test")) {System.out.println("切面逻辑...");}return null;}}});UserInterface userInterface = (UserInterface) enhancer.create();userInterface.test();}}
也是可以正常运行的,那么用cglib代理一个类和代理一个接口的底层有什么区别呢?我们继续分析。
我们知道,既然要生成一个代理对象,那么就肯定需要一个代理类,只不过当我们用cglib时,这个代理类是由cglib生成的,那么我们能不能看到这个代理类是怎么生成的呢?
可以!我们只需要在运行时加上:
-Dcglib.debugLocation=D:\IdeaProjects\cglib\cglib\target\classes
cglib就会将生成的代理类放到上面所指定的路径上。那么我们分别来看看cglib代理类和接口时所产生的代理类是怎样的。
UserService的代理类,我保留了类中比较关键的信息:
public class UserService$$EnhancerByCGLIB$$4d890297 extends UserService implements Factory {final void CGLIB$test$0() {super.test();}public final void test() {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}if (var10000 != null) {var10000.intercept(this, CGLIB$test$0$Method, CGLIB$emptyArgs, CGLIB$test$0$Proxy);} else {super.test();}}}
UserInterface的代理类,我保留了类中比较关键的信息:
public class UserInterface$$EnhancerByCGLIB$$20ecfdd implements UserInterface, Factory {final void CGLIB$test$4() {super.test();}public final void test() {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}if (var10000 != null) {var10000.intercept(this, CGLIB$test$4$Method, CGLIB$emptyArgs, CGLIB$test$4$Proxy);} else {super.test();}}}
可以发现这两种情况所产生的类区别不大,无非就是UserService代理类是UserService的子类,UserInterface代理类实现了UserInterface。
我们可以发现在代理类中(以上两个任选一个),都存在一个test()方法和CGLIB$test$0()(以UserService代理类举例子):
test()方法内会去调用所设置的Callbacks中的intercept(),相当于执行增强逻辑,如果没有Callbacks,则会执行super.test(),那么我们自然能想到,如果不设置Callbacks,那是不是就能正常执行呢?比如这样:
Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class);UserService userService = (UserService) enhancer.create();userService.test();
不好意思,运行这段代码时,cglib在构造代理对象时就会报一个没有Callbacks的空指针异常,所以我们无法看到我们想看到的效果。
但是这并不影响我们继续研究,我们再来看代理类中的另外一个方法:
final void CGLIB$test$0() {super.test();}
这个方法我们并不能直接调用,要通过所设置的Callback,也就是MethodInterceptor中的MethodProxy对象来调用,MethodProxy对象表示方法代理,举个例子,假如UserService代理对象在执行test()方法,那么当执行流程进入到intercept()方法时,MethodProxy对象表示的就是test()方法,但是我们现在知道了在UserService类和UserService代理类中都有test()方法,所以MethodProxy对象代理的就是这两个test(),比如:
// o表示当前代理对象,target表示被代理对象// 执行UserService代理对象的CGLIB$test$0()方法,也就是执行UserService代理对象的父类的test()Object result = methodProxy.invokeSuper(o, objects);// 执行UserService对象的CGLIB$test$0()方法,会报错,调用invokerSuper只能传入代理对象Object result = methodProxy.invokeSuper(target, objects);// 执行UserService对象的test()Object result = methodProxy.invoke(target, objects);// 执行UserService代理对象的test(); 又会进到拦截器,栈溢出Object result = methodProxy.invoke(o, objects);
所以在执行methodProxy.invokeSuper()方法时,就会去执行CGLIB$test$0()方法。
我们来总结一下cglib的大概工作原理是:cglib会根据所设置的Superclass,生成代理类作为其子类,并且会重写Superclass中的方法,Superclass中的某一个方法,比如test(),相应的在代理类中会对应两个方法,一个是重写的test(),用来执行增强逻辑,一个是CGLIB$test$0(),会直接调用super.test(),是让MethodProxy对象来用的。
那接下来的问题就是:
- 代理类是怎么生成的?
- MethodProxy是怎么实现的?
我们下篇文章见。
