环境:Java8
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E://cglib"); Enhancer enhancer = new Enhancer() ; enhancer.setSuperclass(PersonDAOImpl.class) ; enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("执行前...") ; Object result = proxy.invokeSuper(obj, args) ; System.out.println("执行后...") ; return result ; } }); PersonDAOImpl dao = (PersonDAOImpl) enhancer.create() ; dao.save(new Person()) ;
System.setProperty(
DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E://cglib");这行代码用来生成cglib生成的代理类,输出到指定目录
工具使用的是Luyten
由于代码量比较大,这里只贴出重要的代码
public class PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7 extends PersonDAOImpl implements Factory { private boolean CGLIB$BOUND; public static Object CGLIB$FACTORY_DATA; private static final ThreadLocal CGLIB$THREAD_CALLBACKS; private static final Callback[] CGLIB$STATIC_CALLBACKS; private MethodInterceptor CGLIB$CALLBACK_0; private static Object CGLIB$CALLBACK_FILTER; private static final Method CGLIB$save$0$Method; private static final MethodProxy CGLIB$save$0$Proxy; private static final Object[] CGLIB$emptyArgs; private static final Method CGLIB$equals$1$Method; private static final MethodProxy CGLIB$equals$1$Proxy; private static final Method CGLIB$toString$2$Method; private static final MethodProxy CGLIB$toString$2$Proxy; private static final Method CGLIB$hashCode$3$Method; private static final MethodProxy CGLIB$hashCode$3$Proxy; private static final Method CGLIB$clone$4$Method; private static final MethodProxy CGLIB$clone$4$Proxy; static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; final Class<?> forName = Class.forName("com.pack.dao.PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7"); final Class<?> forName2; final Method[] methods = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (forName2 = Class.forName("java.lang.Object")).getDeclaredMethods()); CGLIB$equals$1$Method = methods[0]; CGLIB$equals$1$Proxy = MethodProxy.create((Class)forName2, (Class)forName, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1"); CGLIB$toString$2$Method = methods[1]; CGLIB$toString$2$Proxy = MethodProxy.create((Class)forName2, (Class)forName, "()Ljava/lang/String;", "toString", "CGLIB$toString$2"); CGLIB$hashCode$3$Method = methods[2]; CGLIB$hashCode$3$Proxy = MethodProxy.create((Class)forName2, (Class)forName, "()I", "hashCode", "CGLIB$hashCode$3"); CGLIB$clone$4$Method = methods[3]; CGLIB$clone$4$Proxy = MethodProxy.create((Class)forName2, (Class)forName, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4"); final Class<?> forName3; CGLIB$save$0$Method = ReflectUtils.findMethods(new String[] { "save", "(Lcom/pack/anno/config/Person;)V" }, (forName3 = Class.forName("com.pack.dao.PersonDAOImpl")).getDeclaredMethods())[0]; CGLIB$save$0$Proxy = MethodProxy.create((Class)forName3, (Class)forName, "(Lcom/pack/anno/config/Person;)V", "save", "CGLIB$save$0"); } final void CGLIB$save$0(final Person person) { super.save(person); } public final void save(final Person person) { MethodInterceptor cglib$CALLBACK_2; MethodInterceptor cglib$CALLBACK_0; if ((cglib$CALLBACK_0 = (cglib$CALLBACK_2 = this.CGLIB$CALLBACK_0)) == null) { CGLIB$BIND_CALLBACKS(this); cglib$CALLBACK_2 = (cglib$CALLBACK_0 = this.CGLIB$CALLBACK_0); } if (cglib$CALLBACK_0 != null) { cglib$CALLBACK_2.intercept((Object)this, PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7.CGLIB$save$0$Method, new Object[] { person }, PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7.CGLIB$save$0$Proxy); return; } super.save(person); } public PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7() { CGLIB$BIND_CALLBACKS(this); } public static void CGLIB$SET_THREAD_CALLBACKS(final Callback[] array) { PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7.CGLIB$THREAD_CALLBACKS.set(array); } private static final void CGLIB$BIND_CALLBACKS(final Object o) { final PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7 personDAOImpl$$EnhancerByCGLIB$$6f07c3f7 = (PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7)o; if (!personDAOImpl$$EnhancerByCGLIB$$6f07c3f7.CGLIB$BOUND) { personDAOImpl$$EnhancerByCGLIB$$6f07c3f7.CGLIB$BOUND = true; Object o2; if ((o2 = PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7.CGLIB$THREAD_CALLBACKS.get()) != null || (o2 = PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7.CGLIB$STATIC_CALLBACKS) != null) { personDAOImpl$$EnhancerByCGLIB$$6f07c3f7.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])o2)[0]; } } } static { CGLIB$STATICHOOK1(); } }
生成的代理类继承了PersonDAOImpl;PersonDAOImpl中有几个方法就会生成对应的两个方法,一个方法是直接调用父类对象方法CGLIB$save$0,一个是save方法而这个save方法是通过Callback来调用
当在执行save方法的时候先判断CGLIB$CALLBACK_0是否为空,如果为空则会执行初始化方法
CGLIB$BIND_CALLBACKS(this);
在该方法中,会从CGLIB$THREAD_CALLBACKS对象(ThreadLocal)中获取回调方法(Callback),这个ThreadLocal对象是如何设置值的?
在执行enhancer.create()方法时会通过反射来调用代理类PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7的CGLIB$SET_THREAD_CALLBACKS方法
在创建代理类的时候时:
public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) { setThreadCallbacks(callbacks); try { // Explicit reference equality is added here just in case Arrays.equals does not have one if (primaryConstructorArgTypes == argumentTypes || Arrays.equals(primaryConstructorArgTypes, argumentTypes)) { // If we have relevant Constructor instance at hand, just call it // This skips "get constructors" machinery return ReflectUtils.newInstance(primaryConstructor, arguments); } // Take a slow path if observing unexpected argument types return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments); } finally { // clear thread callbacks to allow them to be gc'd setThreadCallbacks(null); } }
setThreadCallbacks(callbacks);这行代码就是用来执行代理类中的CGLIB$SET_THREAD_CALLBACKS方法。
private void setThreadCallbacks(Callback[] callbacks) { try { setThreadCallbacks.invoke(generatedClass, (Object) callbacks); } catch (IllegalAccessException e) { throw new CodeGenerationException(e); } catch (InvocationTargetException e) { throw new CodeGenerationException(e.getTargetException()); } }
在这代理类中的MethodInterceptor 就设置完成,接下来会执行代理类中save方法的如下代码:
cglib$CALLBACK_2.intercept((Object)this, PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7.CGLIB$save$0$Method, new Object[] { person }, PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7.CGLIB$save$0$Proxy);
intercept方法
@Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("执行前...") ; Object result = proxy.invokeSuper(obj, args) ; System.out.println("执行后...") ; return result ; }
这里的MethodProxy proxy对象又是从哪里来的?这需要回到代理类中的静态代码段中的如下一行代码:
CGLIB$save$0$Proxy = MethodProxy.create((Class)forName3, (Class)forName, "(Lcom/pack/anno/config/Person;)V", "save", "CGLIB$save$0");
进入MethodProxy.create方法:
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) { MethodProxy proxy = new MethodProxy(); proxy.sig1 = new Signature(name1, desc); proxy.sig2 = new Signature(name2, desc); proxy.createInfo = new CreateInfo(c1, c2); return proxy; }
进入invokeSuper方法
public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { init(); FastClassInfo fci = fastClassInfo; return fci.f2.invoke(fci.i2, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } }
init方法用来初始化一个fastClassInfo对象
private void init() { if (fastClassInfo == null) { synchronized (initLock) { if (fastClassInfo == null) { CreateInfo ci = createInfo; FastClassInfo fci = new FastClassInfo(); fci.f1 = helper(ci, ci.c1); fci.f2 = helper(ci, ci.c2); fci.i1 = fci.f1.getIndex(sig1); fci.i2 = fci.f2.getIndex(sig2); fastClassInfo = fci; createInfo = null; } } } } // FastClassInfo private static class FastClassInfo { FastClass f1; FastClass f2; int i1; int i2; }
f1为对应的是CreateInfo中的c1,f2对应的是CreateInfo中的c2;这里结合代理类中的静态代码段来看看分别执行的是谁
final Class<?> forName = Class.forName("com.pack.dao.PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7"); final Class<?> forName3; CGLIB$save$0$Method = ReflectUtils.findMethods(new String[] { "save", "(Lcom/pack/anno/config/Person;)V" }, (forName3 = Class.forName("com.pack.dao.PersonDAOImpl")).getDeclaredMethods())[0]; CGLIB$save$0$Proxy = MethodProxy.create((Class)forName3, (Class)forName, "(Lcom/pack/anno/config/Person;)V", "save", "CGLIB$save$0");
结合上面的代码已经很清楚了。
f1表示的目标类的快速访问类,f2表示的代理类的快速访问类;i1表示的是目标类方法对应的索引,i2表示的是代理类方法对应的索引。
快速访问类是继承了FastClass类,其目的就是能快速地调用执行,因为通过反射性能不高。
原理就是通过每个方法的签名信息(方法名,参数)来为每个方法生成一个索引值,然后调用方法的时候就根据这个索引值直接调用目标方法。
目标类的快速访问类
继续回到invokeSuper方法执行
FastClassInfo fci = fastClassInfo; return fci.f2.invoke(fci.i2, obj, args);
此时fci对象完整信息如下:
fci.f2.invoke(fci.i2, obj, args);这行代码才是真正执行目标类的代码,注意这里的i2=19
进入到PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7$$FastClassByCGLIB$$8343b7a5.class中查看invoke方法
PersonDAOImpl$$EnhancerByCGLIB$$6f07c3f7类中的CGLIB$save$0方法
直接调用父类PersonDAOImpl中的save方法。
到这里也就明白cglib生成的3个class。
完毕!!!
给个关注+转发呗谢谢
公众:Springboot实战案例锦集
Spring Cloud链路追踪zipkin及整合Elasticsearch存储
Springboot整合MyBatis参数传值方式
Springboot整合MyBatis复杂查询应用
SpringCloud Nacos 服务消费者
Springboot接口幂等性基于token实现方案
Springboot项目使用docker部署
Springboot中接口参数校验N种方法你会几个?
SpringBoot一个提升N倍性能的操作
SpringBoot整合Quartz实现任务调度
Springboot之Actuator详解
SpringCloud zuul 动态网关配置
SpringMVC内嵌Tomcat零配置
SpringMVC请求原理源码分析
SpringMVC自定义注解实现接口调用
Springboot整合ELK日志收集详解步骤
SpringBoot开发中几个实用小技巧