天天看点

JDK动态代理和CGLIB动态代理的剖析对比

JDK动态代理

现象

实现类两方法

public class TargetServiceImpl implements TargetService {
    @Override
    public void a() {
        System.out.println("a");
        b();
        System.out.println("-------------------------------------------------------");
    }
    @Override
    public void b() {
        System.out.println("b");
    }
}
           

拦截部分

@Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("enter JDK method:"+method.getName()+"()");
        if (method.getName() == "b") {
            System.out.println("c");
        }
        return method.invoke(target, args); //调用原生方法
    }
           
TargetService proxy = (TargetService) getProxy(new TargetServiceImpl());
        proxy.a();
        proxy.b();
           
JDK动态代理和CGLIB动态代理的剖析对比

也就是说a里的b方法没被拦截,因为内部的this是原始对象:[email protected]

源码分析

核心代码分析

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
    {
        final Class<?>[] intfs = interfaces.clone();
        Class<?> cl = getProxyClass0(loader, intfs);  // 获取代理类的Class对象
    	final Constructor<?> cons = cl.getConstructor(constructorParams);//根据参数获取构造函数
        return cons.newInstance(new Object[]{h});//生成代理类的实例
    }
           

getProxyClass0(loader, intfs); ->return proxyClassCache.get(loader, interfaces);

其中 proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
           

首先会在缓存中查到是否该类加载器已经加载过该代理类,如果找到则直接返回,否则使用 ProxyClassFactory来生成代理类

public V get(K key, P parameter) {
		// 从缓存中获取supplier
		
        while (true) {
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)	
           

使用 ProxyClassFactory来生成代理类

private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
        {
        // prefix for all proxy class names
        private static final String proxyClassNamePrefix = "$Proxy";
        // next number to use for generation of unique proxy class names
        private static final AtomicLong nextUniqueNumber = new AtomicLong();
        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
         	/*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;
            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass( //生成代理的字节码
                proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
           

字节码反编译

private static void createProxyClassFile(Class clazz){
        String name = "Proxy"+clazz.getSimpleName();
        byte[] data = ProxyGenerator.generateProxyClass(name,clazz.getInterfaces()); 
        
        FileOutputStream out =null;
        try {
            out = new FileOutputStream(name+".class");
            System.out.println((new File("proxyOutput")).getAbsolutePath());
            out.write(data);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(null!=out) try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
           

将生成的字节码反编译

public final class ProxyTargetServiceImpl extends Proxy implements TargetService {
    private static Method m1;
    private static Method m3;
    private static Method m4;
    private static Method m2;
    private static Method m0;

    public ProxyTargetServiceImpl(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void b() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void a() throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("proxy.TargetService").getMethod("b");
            m4 = Class.forName("proxy.TargetService").getMethod("a");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
           

JDK动态代理只会将实现的接口里的方法添加为代理方法。

super.h即InvocationHandler,然后调用它的Invoke方法即
this为代理,此处即ProxyTargetServiceImpl
m4 = Class.forName("proxy.TargetService").getMethod("a");
           

CGLIB动态代理

现象

增强逻辑

public static Object getProxy(Class<?> clazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(clazz.getClassLoader());
        enhancer.setSuperclass(clazz); //增强类是被代理类的子类
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("enter cglib method:"+method.getName()+"()");
                if (method.getName() == "b") {
                    System.out.println("c");
                }
                Object invokeResult = methodProxy.invokeSuper(o, objects);
                return invokeResult;
            }
        });
        return enhancer.create();
    }
           
public class CglibTarget {
    public void a() {
        System.out.println("a");
        b();
        System.out.println("-------------------------------------------------------");
    }
    public void b() {
        System.out.println("b");
    }
}
           
CglibTarget proxy = (CglibTarget)getProxy(CglibTarget.class);
proxy.a();
proxy.b();
           
JDK动态代理和CGLIB动态代理的剖析对比

源码分析

Object invokeResult = methodProxy.invokeSuper(o, objects);

JDK动态代理和CGLIB动态代理的剖析对比

invoke进入实际的方法:这里不一样的是this是增强后的代理对象doTest.CglibTarget E n h a n c e r B y C G L I B EnhancerByCGLIB EnhancerByCGLIB[email protected]

JDK动态代理和CGLIB动态代理的剖析对比

字节码反编译

main函数中加入如下语句

JDK动态代理和CGLIB动态代理的剖析对比
public class CglibTarget$$EnhancerByCGLIB$$75dccf2e extends CglibTarget implements Factory {

	var10000 = ReflectUtils.findMethods(new String[]{"b", "()V", "a", "()V"}, (var1 = Class.forName("doTest.CglibTarget")).getDeclaredMethods());
	CGLIB$b$0$Method = var10000[0];
	CGLIB$b$0$Proxy = MethodProxy.create(var1, var0, "()V", "b", "CGLIB$b$0");
	CGLIB$a$1$Method = var10000[1];
	CGLIB$a$1$Proxy = MethodProxy.create(var1, var0, "()V", "a", "CGLIB$a$1");


	final void CGLIB$b$0() {
        super.b();
    }

    public final void b() {
        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$b$0$Method, CGLIB$emptyArgs, CGLIB$b$0$Proxy);
        } else {
            super.b();
        }
    }

    final void CGLIB$a$1() {
        super.a();
    }

    public final void a() {
        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$a$1$Method, CGLIB$emptyArgs, CGLIB$a$1$Proxy);
        } else {
            super.a();
        }
    }
           

继续阅读