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)分析说明

    1. 明显会继承代理类,还会实现Factory接口。
    2. 动态代理类持有 MethodInterceptor
    3. 动态代理类会重写父类的非 final、private 方法【 如test() 】,也会构建自己的方法(cglib 方法),构建方式:CGLIB”+“$父类方法名$【 如CGLIB$test$0 】。
    4. cglib 方法的方法体:super.方法名,直接调用父类;重写方法:它会调用拦截器中的 intercept() 方法
    5. 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();
}

    说明

    1. 运行完后会生成一个Person.class的字节码文件。
    2. 本质上有点类似于生成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);
    
}

    说明

    1. 相较于ASM技术,Javassist技术提供了更多的API,减少了我们对指令的关心,相对来说更好用。

 

 

MethodInterceptor

posted @ 2022-09-21 06:28  忧愁的chafry  阅读(122)  评论(0编辑  收藏  举报