java的动态代理底层解析
1.说明
代理模式的解释:为其他对象提供一种代理以控制对这个对象的访问,增强一个类中的某个方法,对程序进行扩展。
2.类型:
CGLib动态代理和JDK动态代理
3.使用介绍
(1)CGLib动态代理的使用
使用示例:
1、针对代理类的示例
//构建代理对象 public class TestObject { public void test(){ System.out.println("test"); } public void test1(){ System.out.println("test1"); } } //构建方法拦截器 public class MyMethodInterceptor implements MethodInterceptor {
//Object为由CGLib生成的代理类实例;Method为上文中实体类所调用的被代理的方法引用;Object[]为参数值列表;MethodProxy 为生成的代理类对方法的代理引用 @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("before.."); Object result = methodProxy.invokeSuper(o,objects); System.out.println("after.."); return result; } } //生成代理步骤 public static void main(String[] args) { Enhancer enhancer = new Enhancer(); //构造出加强器对象 enhancer.setSuperclass(TestObject.class); //将代理类设置进去 enhancer.setCallback(new MyMethodInterceptor()); TestObject testObject= (TestObject)enhancer.create(); testObject.test(); }
2、针对代理接口的示例
public interface UserInterface { public void test(); public void test1(); } public class User implements UserInterface { @Override public void test() { System.out.println("test"); } @Override public void test1() { System.out.println("test1"); } } public class MyInterfaceMyMethodInterceptor implements MethodInterceptor { Object object; public MyInterfaceMyMethodInterceptor(Object object) { this.object = object; } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("before.."); Object result = methodProxy.invoke(object,objects); System.out.println("after.."); return result; } } public static void main(final String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserInterface.class); enhancer.setCallback(new MyInterfaceMyMethodInterceptor(new User())); UserInterface userInterface = (UserInterface) enhancer.create(); userInterface.test(); }
(2)JDK动态代理的使用
public interface UserInterface { public void test(); public void test1(); } public class User implements UserInterface { @Override public void test() { System.out.println("test"); } @Override public void test1() { System.out.println("test1"); } } public class MyInvocationHandler implements InvocationHandler { Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before.."); Object result = method.invoke(target,args); System.out.println("after.."); return result; } } public static void main(String[] args) { System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); MyInvocationHandler myInvocationHandler = new MyInvocationHandler(new User()); UserInterface userInterface = (UserInterface) Proxy.newProxyInstance(JDKDemo.class.getClassLoader(), new Class[]{UserInterface.class}, myInvocationHandler); userInterface.test(); }
4.底层分析(通过JVM添加参数 -Dcglib.debugLocation=D:\IdeaProjects\cglib\cglib\target\classes【这个便是代理对象的存储路径】)
代理类的class类(依据文件TestObject$$EnhancerByCGLIB$$783a36a0.class)
(1)代码展示
//继承了代理类 public class TestObject$$EnhancerByCGLIB$$783a36a0 extends TestObject 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$test$0$Method; private static final MethodProxy CGLIB$test$0$Proxy; private static final Object[] CGLIB$emptyArgs; private static final Method CGLIB$test1$1$Method; private static final MethodProxy CGLIB$test1$1$Proxy; private static final Method CGLIB$equals$2$Method; private static final MethodProxy CGLIB$equals$2$Proxy; private static final Method CGLIB$toString$3$Method; private static final MethodProxy CGLIB$toString$3$Proxy; private static final Method CGLIB$hashCode$4$Method; private static final MethodProxy CGLIB$hashCode$4$Proxy; private static final Method CGLIB$clone$5$Method; private static final MethodProxy CGLIB$clone$5$Proxy; static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; Class var0 = Class.forName("com.xiangxue.jack.aop.daili.TestObject$$EnhancerByCGLIB$$783a36a0"); Class var1; //从目标类中拿出对应的方法构建成方法对象 Method[] var10000 = ReflectUtils.findMethods(new String[]{"test", "()V", "test1", "()V"}, (var1 = Class.forName("com.xiangxue.jack.aop.daili.TestObject")).getDeclaredMethods()); CGLIB$test$0$Method = var10000[0]; //针对方法对象构建出代理对象 CGLIB$test$0$Proxy = MethodProxy.create(var1, var0, "()V", "test", "CGLIB$test$0"); CGLIB$test1$1$Method = var10000[1]; CGLIB$test1$1$Proxy = MethodProxy.create(var1, var0, "()V", "test1", "CGLIB$test1$1"); var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods()); CGLIB$equals$2$Method = var10000[0]; CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2"); CGLIB$toString$3$Method = var10000[1]; CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3"); CGLIB$hashCode$4$Method = var10000[2]; CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4"); CGLIB$clone$5$Method = var10000[3]; CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5"); } //去执行父类的test()方法 final void CGLIB$test$0() { super.test(); } //重写了父类的test()方法 public final void test() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); //给 CGLIB$CALLBACK_0 属性赋值 var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { //四个参数分别为(当前的代理对象,方法,参数,未知) var10000.intercept(this, CGLIB$test$0$Method, CGLIB$emptyArgs, CGLIB$test$0$Proxy); } else { super.test(); } } final void CGLIB$test1$1() { super.test1(); } public final void test1() { 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$test1$1$Method, CGLIB$emptyArgs, CGLIB$test1$1$Proxy); } else { super.test1(); } } final boolean CGLIB$equals$2(Object var1) { return super.equals(var1); } public final boolean equals(Object var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { Object var2 = var10000.intercept(this, CGLIB$equals$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy); return var2 == null ? false : (Boolean)var2; } else { return super.equals(var1); } } final String CGLIB$toString$3() { return super.toString(); } public final String toString() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy) : super.toString(); } final int CGLIB$hashCode$4() { return super.hashCode(); } public final int hashCode() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { Object var1 = var10000.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy); return var1 == null ? 0 : ((Number)var1).intValue(); } else { return super.hashCode(); } } final Object CGLIB$clone$5() throws CloneNotSupportedException { return super.clone(); } protected final Object clone() throws CloneNotSupportedException { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? var10000.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy) : super.clone(); } public static MethodProxy CGLIB$findMethodProxy(Signature var0) { String var10000 = var0.toString(); switch(var10000.hashCode()) { case -1422510685: if (var10000.equals("test()V")) { return CGLIB$test$0$Proxy; } break; case -1147892426: if (var10000.equals("test1()V")) { return CGLIB$test1$1$Proxy; } break; case -508378822: if (var10000.equals("clone()Ljava/lang/Object;")) { return CGLIB$clone$5$Proxy; } break; case 1826985398: if (var10000.equals("equals(Ljava/lang/Object;)Z")) { return CGLIB$equals$2$Proxy; } break; case 1913648695: if (var10000.equals("toString()Ljava/lang/String;")) { return CGLIB$toString$3$Proxy; } break; case 1984935277: if (var10000.equals("hashCode()I")) { return CGLIB$hashCode$4$Proxy; } } return null; } public TestObject$$EnhancerByCGLIB$$783a36a0() { CGLIB$BIND_CALLBACKS(this); } public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) { CGLIB$THREAD_CALLBACKS.set(var0); } public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) { CGLIB$STATIC_CALLBACKS = var0; } private static final void CGLIB$BIND_CALLBACKS(Object var0) { TestObject$$EnhancerByCGLIB$$783a36a0 var1 = (TestObject$$EnhancerByCGLIB$$783a36a0)var0; if (!var1.CGLIB$BOUND) { //一开始为false,布尔值的默认值 var1.CGLIB$BOUND = true; Object var10000 = CGLIB$THREAD_CALLBACKS.get(); //从当前线程的ThreadLocal中获取 if (var10000 == null) { var10000 = CGLIB$STATIC_CALLBACKS; //拦截器数组存储的地方 if (var10000 == null) { return; } } var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0]; //取出数组第一位元素赋值过去 } } public Object newInstance(Callback[] var1) { CGLIB$SET_THREAD_CALLBACKS(var1); TestObject$$EnhancerByCGLIB$$783a36a0 var10000 = new TestObject$$EnhancerByCGLIB$$783a36a0(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Callback var1) { CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1}); TestObject$$EnhancerByCGLIB$$783a36a0 var10000 = new TestObject$$EnhancerByCGLIB$$783a36a0(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) { CGLIB$SET_THREAD_CALLBACKS(var3); TestObject$$EnhancerByCGLIB$$783a36a0 var10000 = new TestObject$$EnhancerByCGLIB$$783a36a0; switch(var1.length) { case 0: var10000.<init>(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; default: throw new IllegalArgumentException("Constructor not found"); } } public Callback getCallback(int var1) { CGLIB$BIND_CALLBACKS(this); MethodInterceptor var10000; switch(var1) { case 0: var10000 = this.CGLIB$CALLBACK_0; break; default: var10000 = null; } return var10000; } public void setCallback(int var1, Callback var2) { switch(var1) { case 0: this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2; default: } } public Callback[] getCallbacks() { CGLIB$BIND_CALLBACKS(this); return new Callback[]{this.CGLIB$CALLBACK_0}; } public void setCallbacks(Callback[] var1) { this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0]; } static { CGLIB$STATICHOOK1(); } }
(2)调用流程说明
当代理对象被调用的时候【假设为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(); } }
CGLIB$CALLBACK_0该属性一开始是没有值的(因为初始化过程没有赋值的步骤),而获取值得步骤在于 CGLIB$BIND_CALLBACKS(this);这一步。
private static final void CGLIB$BIND_CALLBACKS(Object var0) { TestObject$$EnhancerByCGLIB$$783a36a0 var1 = (TestObject$$EnhancerByCGLIB$$783a36a0)var0; if (!var1.CGLIB$BOUND) { var1.CGLIB$BOUND = true; Object var10000 = CGLIB$THREAD_CALLBACKS.get(); if (var10000 == null) { var10000 = CGLIB$STATIC_CALLBACKS; if (var10000 == null) { return; } } var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0]; } }
这里面var1明显是指类本身,故CGLIB$BOUND会发现是布尔值类型,默认是false。而CGLIB$THREAD_CALLBACKS在静态代码块中被赋予了ThreadLocal,所以是打算从当前线程的ThreadLocal中获取。而CGLIB$STATIC_CALLBACKS类属性值中存放拦截方法数组的地方。然后返回数组的第一个元素过去。(1.这里有个问题ThreadLocal是什么时候被赋值的?)
(3)问题汇总
1.这里有个问题ThreadLocal是什么时候被赋值的?
是在 CGLIB$SET_THREAD_CALLBACKS 这个方法中被赋值的,CGLIB$SET_THREAD_CALLBACKS这个方法又是在newInstance方法【生成代理对象的方法】中被执行。
2.test()⽅法内会去调⽤所设置的Callbacks中的intercept(),相当于执⾏增强逻辑,如果没有Callbacks,则会执⾏super.test(),那么我们⾃然能想到,如果不设置Callbacks,那是不是就能正常执⾏呢?(是不能正常执行的)
-
-
- 情况1,enhancer.setCallback(null);
-
异常出现在:createHelper()方法#preValidate()#CallbackInfo.determineTypes(callbacks, false);
会报java.lang.IllegalStateException: Callback is null
-
-
- 情况2,不设置enhancer.setCallback
-
createHelper()方法#preValidate()#CallbackInfo.determineTypes(callbacks, false);
会报java.lang.NullPointerException
(4)分析说明
- 明显会继承代理类,还会实现Factory接口。
- 动态代理类持有
MethodInterceptor
- 动态代理类会重写父类的非 final、private 方法【 如test() 】,也会构建自己的方法(cglib 方法),构建方式:
CGLIB”+“$父类方法名$
【 如CGLIB$test$0 】。 - cglib 方法的方法体:
super.方法名
,直接调用父类;重写方法:它会调用拦截器中的intercept()
方法。 methodProxy.invokeSuper()
方法会调用动态代理类中的 cglib 方法;methodProxy.invoke()
方法会调用动态代理类中的重写方法
5.JDK动态代理源码分析(还未写全,待续)
(1)Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
@CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } //去拿到代理类 Class<?> cl = getProxyClass0(loader, intfs); try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } //拿到代理类的构造方法 final Constructor<?> cons = cl.getConstructor(constructorParams); //拿到拦截器对象 final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } //然后把拦截器传给构造方法 return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) {..} catch (InvocationTargetException e) {...} catch (NoSuchMethodException e) {... } }
6.CGLib源码分析
(1)Enhancer.create()
public Object create() { classOnly = false; argumentTypes = null; //执行创建 return createHelper(); }
(2)Enhancer.createHelper()
private Object createHelper() { //校验callbackTypes,filter是否为空,已经为空的处理 preValidate(); // 通过newInstance方法生成了一个EnhancerKey代理对象,该代理对象里面保存了用户所设置的代理信息 Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null, ReflectUtils.getNames(interfaces), filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter), callbackTypes, useFactory, interceptDuringConstruction, serialVersionUID); //设置当前Enhancer的代理类的key标识 this.currentKey = key; // 调用父类AbstractClassGenerator的方法去创建代理对象 Object result = super.create(key); return result; }
(3)AbstractClassGenerator.create(Object key)
protected Object create(Object key) { try { ClassLoader loader = getClassLoader(); Map<ClassLoader, ClassLoaderData> cache = CACHE; ClassLoaderData data = cache.get(loader); if (data == null) { synchronized (AbstractClassGenerator.class) { cache = CACHE; data = cache.get(loader); if (data == null) { Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache); // 构造方法中会生成一个生成代理类的lambda表达式 data = new ClassLoaderData(loader); newCache.put(loader, data); CACHE = newCache; } } } this.key = key; // 利用ClassLoaderData拿到代理类,ClassLoaderData中有一个generatedClasses用来缓存生成好的代理类 // this就是Enhancer Object obj = data.get(this, getUseCache()); if (obj instanceof Class) { // 调用代理类的构造方法生成一个代理对象 return firstInstance((Class) obj); } return nextInstance(obj); } catch (RuntimeException e) {...} catch (Error e) {...} catch (Exception e) {...} }
(4)Enhancer.firstInstance((Class) obj) 与 Enhancer.createUsingReflection(type)
protected Object firstInstance(Class type) throws Exception { if (classOnly) { return type; } else { return createUsingReflection(type); } } private Object createUsingReflection(Class type) { // 设置callbacks到代理类中 setThreadCallbacks(type, callbacks); try{ if (argumentTypes != null) { //根据代理类创建代理对象 return ReflectUtils.newInstance(type, argumentTypes, arguments); } else { return ReflectUtils.newInstance(type); } }finally{ setThreadCallbacks(type, null); } } private static void setThreadCallbacks(Class type, Callback[] callbacks) { //private static final String SET_THREAD_CALLBACKS_NAME = "CGLIB$SET_THREAD_CALLBACKS"; //这里便是调用将callbacks设置进入ThreadLocal里面 //也就是利用反射区执行 setCallbacksHelper(type, callbacks, SET_THREAD_CALLBACKS_NAME); }
(5)ClassLoaderData.get(this, getUseCache())
public Object get(AbstractClassGenerator gen, boolean useCache) { if (!useCache) {//也就是enhancer.setUseCache(false);会起到作用的地方, // gen是Enhancer, ClassLoaderData.this中存储了EnhancerKey代理对象 return gen.generate(ClassLoaderData.this); } else {//这里使用到缓存useCache=true Object cachedValue = generatedClasses.get(gen); return gen.unwrapCachedValue(cachedValue); } } //Enhancer.generate protected Class generate(ClassLoaderData data) { validate(); //类的名字(可参考文件的名字) if (superclass != null) { setNamePrefix(superclass.getName()); } else if (interfaces != null) { setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName()); } //AbstractClassGenerator.generate return super.generate(data); } //AbstractClassGenerator.generate protected Class generate(ClassLoaderData data) { Class gen; Object save = CURRENT.get(); CURRENT.set(this); try { ClassLoader classLoader = data.getClassLoader(); if (classLoader == null) { throw ex..;} synchronized (classLoader) { String name = generateClassName(data.getUniqueNamePredicate()); data.reserveName(name); this.setClassName(name); } if (attemptLoad) { try { gen = classLoader.loadClass(getClassName()); return gen; } catch (ClassNotFoundException e) {..} } // this就是Enhancer,主要是在这个方法里面利用ASM技术,生成代理类里面的东西 byte[] b = strategy.generate(this); String className = ClassNameReader.getClassName(new ClassReader(b)); ProtectionDomain protectionDomain = getProtectionDomain(); synchronized (classLoader) { // just in case if (protectionDomain == null) { gen = ReflectUtils.defineClass(className, b, classLoader); } else { gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain); } } return gen; } catch (RuntimeException e) {..} catch (Error e) {..} catch (Exception e) {..} finally { CURRENT.set(save); } } //代码generatedClasses.get(gen)进入 public V get(K key) { // 这里得到就是EnhancerKey的代理对象 final KK cacheKey = keyMapper.apply(key); Object v = map.get(cacheKey); if (v != null && !(v instanceof FutureTask)) { return (V) v; } // 传进去的key为Enhancer对象,cacheKey为EnhancerKey的代理对象,表示所设置的代理信息 return createEntry(key, cacheKey, v); } protected V createEntry(final K key, KK cacheKey, Object v) { FutureTask<V> task; boolean creator = false; if (v != null) { // Another thread is already loading an instance task = (FutureTask<V>) v; } else { // loader.apply(key)就会去创建代理对象 task = new FutureTask<V>(new Callable<V>() { public V call() throws Exception { // 这里就会去创建代理类了,实际上也是调用gen.generate(ClassLoaderData.this); return loader.apply(key); } }); Object prevTask = map.putIfAbsent(cacheKey, task); if (prevTask == null) { // creator does the load creator = true; task.run(); } else if (prevTask instanceof FutureTask) { task = (FutureTask<V>) prevTask; } else { return (V) prevTask; } } V result; try { result = task.get(); } catch (InterruptedException e) {...} catch (ExecutionException e) {...} if (creator) { // 代理类创建完之后会进行缓存 map.put(cacheKey, result); } return result; }
7.MethodProxy源码分析
代码展示
public class UserService { public void test(){ System.out.println("test"); } } public static void main(String[] args) { final UserService target = new UserService(); Enhancer enhancer = new Enhancer(); enhancer.setUseCache(false); enhancer.setSuperclass(UserService.class); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { //为什么会存在有些报错有些不报错的问题? if (method.getName().equals("test")) { System.out.println("before..."); methodProxy.invoke(o, objects); //报栈溢出错误 methodProxy.invoke(target, objects); methodProxy.invokeSuper(o, objects); methodProxy.invokeSuper(target, objects); //报调⽤invokerSuper只能传⼊代理对象的错误 System.out.println("after..."); return null; } return method.invoke(target, objects); } }); UserService userService = (UserService) enhancer.create(); userService.test(); }
代码说明
在使用过程,我们常常遇到methodProxy上的方法使用问题,然而根本不知道为什么会这样。(虽然也不怎么会这样用)
进行分析
(1)MethodProxy是什么时候创建出来的?
从上面的字节码文件可以看到是在静态方法CGLIB$STATICHOOK1()中生成的。
源代码为(MethodProxy类#create方法)
create(Class c1, Class c2, String desc, String name1, String name2) { // c1是TestObject // c2是TestObject代理类[TestObject$$EnhancerByCGLIB$$783a36a0] // desc被代理方法的返回值类型 // name1是被代理方法名比如test // name2是代理类中的CGLIB$test$0方法,会调用super.test() MethodProxy proxy = new MethodProxy(); proxy.sig1 = new Signature(name1, desc); // 被代理方法签名,也就是代表void test() proxy.sig2 = new Signature(name2, desc); // 代理方法签名,也就是void CGLIB$test$0() proxy.createInfo = new CreateInfo(c1, c2); // CreateInfo中表示的就是被代理类和代理类的信息 return proxy; }
(2)MethodProxy的invoke方法与invokeSuper方法的区别?
先上代码:
public Object invoke(Object obj, Object[] args) throws Throwable { try { init(); FastClassInfo fci = fastClassInfo; // f1表示被代理类的FastClass代理类,i1表示被代理方法的下标,这里就是去执行test()方法,具体执行的是哪个对象就看obj return fci.f1.invoke(fci.i1, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } catch (IllegalArgumentException e) { if (fastClassInfo.i1 < 0) throw new IllegalArgumentException("Protected method: " + sig1); throw e; } } public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { init(); FastClassInfo fci = fastClassInfo; // f2表示UserService代理类的FastClass代理类,i2表示代理方法的下标,这里就是去执行CGLIB$test$0方法,具体执行的是哪个对象就看obj return fci.f2.invoke(fci.i2, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } }
说明
1.说白了,这个两个方法本身是根据不同的索引文件去找对应的方法,然后用传入对象,调用返回的方法。
2.这里面涉及了另外的两个字节码文件(便是上面存储路径下的):
TestObject$$EnhancerByCGLIB$$783a36a0$$FastClassByCGLIB$$626f6578.class(这里面是代理类的方法索引)
TestObject$$FastClassByCGLIB$$a3bbba2f.class(这里面是目标类的方法索引)
(3)FastClassInfo的生成过程
private void init(){ if (fastClassInfo == null) { //采用双重判断+加锁达到只生成一次 synchronized (initLock) { if (fastClassInfo == null) { // CreateInfo中存储了代理类和被代理类 CreateInfo ci = createInfo; FastClassInfo fci = new FastClassInfo(); fci.f1 = helper(ci, ci.c1); // 被代理类的FastClass代理类,也就是TestObject$$FastClassByCGLIB$$a3bbba2f.class fci.f2 = helper(ci, ci.c2); // 代理类的FastClass代理类,也就是TestObject$$EnhancerByCGLIB$$783a36a0$$FastClassByCGLIB$$626f6578.class //被代理方法签名,也就是代表void test() //代理方法签名,也就是void CGLIB$test$0() // 预先生成每个方法所对应的下标,调用时就可以直接利用下标找到方法了,性能高 fci.i1 = fci.f1.getIndex(sig1); // 获取方法签名sig1在被代理类的FastClass代理类中的下标,后续根据下标找到对应的方法,sig1表示被代理方法test() fci.i2 = fci.f2.getIndex(sig2); // 获取方法签名sigsig2在代理类的FastClass代理类中的下标,后续根据下标找到对应的方法,sig2表示代理方法CGLIB$test$0() fastClassInfo = fci; createInfo = null; } } } }
TestObject$$EnhancerByCGLIB$$783a36a0$$FastClassByCGLIB$$626f6578.class代码展示(已经进行了部分删减,可以尝试自己去调试生产厂)
public class TestObject$$EnhancerByCGLIB$$783a36a0$$FastClassByCGLIB$$626f6578 extends FastClass { public TestObject$$EnhancerByCGLIB$$783a36a0$$FastClassByCGLIB$$626f6578(Class var1) { super(var1); } public int getIndex(Signature var1) { String var10000 = var1.toString(); switch(var10000.hashCode()) { case -1870561232: if (var10000.equals("CGLIB$findMethodProxy(Lorg/springframework/cglib/core/Signature;)Lorg/springframework/cglib/proxy/MethodProxy;")) { return 16; } break; ... case -1422510685: if (var10000.equals("test()V")) { return 7; } break; case -1411812934: if (var10000.equals("CGLIB$hashCode$4()I")) { return 18; } break; case -1147892426: if (var10000.equals("test1()V")) { return 9; } break; ... case 446872140: if (var10000.equals("CGLIB$test1$1()V")) { return 21; } break; ... } return -1; } public int getIndex(String var1, Class[] var2) { switch(var1.hashCode()) { case -1776922004: if (var1.equals("toString")) { switch(var2.length) { case 0: return 1; } } break; ... case -336910199: if (var1.equals("CGLIB$test1$1")) { switch(var2.length) { case 0: return 21; } } break; .. case 3556498: if (var1.equals("test")) { switch(var2.length) { case 0: return 7; } } break; .... case 1951977611: if (var1.equals("CGLIB$clone$5")) { switch(var2.length) { case 0: return 19; } } } return -1; } public int getIndex(Class[] var1) { switch(var1.length) { case 0: return 0; default: return -1; } } public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException { 783a36a0 var10000 = (783a36a0)var2; int var10001 = var1; try { switch(var10001) { case 0: return new Boolean(var10000.equals(var3[0])); case 1: return var10000.toString(); ... case 20: return var10000.CGLIB$toString$3(); case 21: var10000.CGLIB$test1$1(); return null; case 22: var10000.CGLIB$test$0(); return null; } } catch (Throwable var4) { throw new InvocationTargetException(var4); } throw new IllegalArgumentException("Cannot find matching method/constructor"); } public Object newInstance(int var1, Object[] var2) throws InvocationTargetException { 783a36a0 var10000 = new 783a36a0; 783a36a0 var10001 = var10000; int var10002 = var1; try { switch(var10002) { case 0: var10001.<init>(); return var10000; } } catch (Throwable var3) { throw new InvocationTargetException(var3); } throw new IllegalArgumentException("Cannot find matching method/constructor"); } public int getMaxIndex() { return 22; } }
8.拓展内容
ASM技术
引入包类
<dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>7.1</version> </dependency>
代码示例
public static void main(String[] args) throws IOException { ClassWriter classWriter = new ClassWriter(0); // 通过visit方法确定类的头部信息 classWriter.visit(Opcodes.V1_8,// java版本 Opcodes.ACC_PUBLIC,// 类修饰符 "Person", // 类的全限定名 null, "java/lang/Object", null); //创建构造函数 MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>","()V"); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); // 定义test方法 MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "test", "()V", null, null); methodVisitor.visitCode(); methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); methodVisitor.visitLdcInsn("hello zyu"); methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); methodVisitor.visitInsn(Opcodes.RETURN); methodVisitor.visitMaxs(2, 2); methodVisitor.visitEnd(); classWriter.visitEnd(); // 使classWriter类已经完成 // 将classWriter转换成字节数组写到文件里面去 byte[] data = classWriter.toByteArray(); //注:在Windows操作系统下必须保证文件夹要存在。 File file = new File("D:\\IdeaProjects\\AsmDemo\\src\\main\\java\\Person.class"); FileOutputStream fout = new FileOutputStream(file); fout.write(data); fout.close(); }
说明
- 运行完后会生成一个Person.class的字节码文件。
- 本质上有点类似于生成TXT文件的感觉,但是需要熟悉字节码指令等(其实本质上作为开发用到的不多,了解一下,知道个大概,以后用到在慢慢翻吧)
Javassist技术
引入包类
<dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.25.0-GA</version> </dependency>
代码示例
public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { ClassPool pool = ClassPool.getDefault(); // 1. 创建一个空类 CtClass cc = pool.makeClass("com.zyu.Person"); // 2. 新增一个字段 private String name; // 字段名为name CtField param = new CtField(pool.get("java.lang.String"), "name", cc); // 访问级别是 private param.setModifiers(Modifier.PRIVATE); // 初始值是 "zyu" cc.addField(param, CtField.Initializer.constant("zyu")); // 3. 生成 getter、setter 方法 cc.addMethod(CtNewMethod.setter("setName", param)); cc.addMethod(CtNewMethod.getter("getName", param)); // 4. 添加无参的构造函数 CtConstructor cons = new CtConstructor(new CtClass[]{}, cc); cons.setBody("{name = \"zyu\";}"); cc.addConstructor(cons); // 5. 添加有参的构造函数 cons = new CtConstructor(new CtClass[]{pool.get("java.lang.String")}, cc); // $0=this / $1,$2,$3... 代表方法参数 cons.setBody("{$0.name = $1;}"); cc.addConstructor(cons); // 6. 创建一个名为printName方法,无参数,无返回值,输出name值 CtMethod ctMethod = new CtMethod(CtClass.voidType, "printName", new CtClass[]{}, cc); ctMethod.setModifiers(Modifier.PUBLIC); ctMethod.setBody("{System.out.println(name);}"); cc.addMethod(ctMethod); //这里会将这个创建的类对象编译为.class文件 cc.writeFile("D:\\IdeaProjects\\JavassistDemo\\src\\main\\java"); // 这里不写入文件,直接实例化 // Object person = cc.toClass().newInstance(); // // 设置值 // Method setName = person.getClass().getMethod("setName", String.class); // setName.invoke(person, "dadududu"); // // 输出值 // Method execute = person.getClass().getMethod("printName"); // execute.invoke(person); }
说明
- 相较于ASM技术,Javassist技术提供了更多的API,减少了我们对指令的关心,相对来说更好用。