JDK动态代理代理与Cglib代理区别

JDK动态代理代理与Cglib代理区别

在Java中,许多框架的底层都是基于动态代理来实现的,比如Aop,mybaits动态生成数据库操作类。在Java中有两种动态代理的方法,一种是JDK原生的动态代理,一种是基于Cglib的代理方式

什么是代理模式

为其他对象提供一种代理以控制对这个对象的访问

什么是动态代理

与静态代理在程序运行前就已经存在的方式不同,动态代理指的是代理类是在运行时才被创建出来的。相比于静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。

动态代理的实现方式

1.JDK动态代理

1.定义接口

    /*
     * @Author  Avalon
     * @Email   [email protected]
     * @Version V1.0
     * @Created Date:2017/8/6 
     */
    public interface IService {
        String doService(String s);
    }

2.定义实现类

    /*
     * @Author  Avalon 
     * @Email   [email protected]
     * @Version V1.0
     * @Created Date:2017/8/6 
     */
    public class ServiceImpl implements IService {
        @Override
        public String doService(String s) {

            return String.format("hello:%s", s);
        }
    }

3.InvocationHandler类

    /*
     *
     * @Author  Avalon 
     * @Email   [email protected]
     * @Version V1.0
     * @Created Date:2017/8/6 
     */
    public class MyInvocationHandler<T> implements InvocationHandler {
        private T target;
        public MyInvocationHandler(T target) {
            super();
            this.target = target;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("方法调用前");
            Object result = method.invoke(target, args);
            System.out.println("方法调用后");
            return result;
        }
    
        public T getProxy() {
            return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
        }
    }

4.测试类

    /*
     *
     * @Author  Avalon 
     * @Email   [email protected]
     * @Version V1.0
     * @Created Date:2017/8/6 
     */
    public class MyInvocationHandler<T> implements InvocationHandler {
    
        private T target;
    
        public MyInvocationHandler(T target) {
            super();
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("方法调用前");
            Object result = method.invoke(target, args);
            System.out.println("方法调用后");
            return result;
        }
    
        public T getProxy() {
            return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
        }
    }

运行结果

方法调用前
hello:Avalon
方法调用后

可以看到在方法动用前后都打印出了相应的日志,说明方法已经成功被代理了。那具体JDK是怎么实现的呢,让我们来看看JDK生成的代理类$Proxy0

    public final class $Proxy0 extends Proxy implements IService {
        private static Method m1;
        private static Method m2;
        private static Method m3;
        private static Method m0;
    
        public $Proxy0(InvocationHandler var1) throws  {
            super(var1);
        }
    
        public final boolean equals(Object var1) throws  {
            try {
                return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
    
        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 void doService(String var1) throws  {
            try {
                //将被代理的方法method,参数,及代理类传给invokeHandler调用
                super.h.invoke(this, m3, new Object[]{var1});
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
    
        public final int hashCode() throws  {
            try {
                return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        static {
            try {
                m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
                m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
                m3 = Class.forName("IService").getMethod("doService", new Class[]{Class.forName("java.lang.String")});
                m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            } catch (NoSuchMethodException var2) {
                throw new NoSuchMethodError(var2.getMessage());
            } catch (ClassNotFoundException var3) {
                throw new NoClassDefFoundError(var3.getMessage());
            }
        }
    }

也就是说main函数里面的proxy实际就是$Proxy0的一个实例对象。可知JDK动态代理是使用接口生成新的实现类,实现类里面则委托给InvocationHandler,InvocationHandler里面则调用被代理的类方法。

1.Cglib实现方式

Cglib(Code Generation Library)。是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。它不需要被代理的类实现某个接口就可以实现动态代理

1.Service类

    public class ServiceImpl  {
        public void doService(String s) {
            System.out.println(String.format("hello:%s", s));
        }
    }

2.CglibProxy代理

    public class CglibProxy implements MethodInterceptor {

        @Override
        //Object为由CGLib动态生成的代理类实例,Method为上文中实体类所调用的被代理的方法引用,Object[]为参数值列表,MethodProxy为生成的代理类对方法的代理引用。
        public Object intercept(Object obj, Method method, Object[] params, MethodProxy proxy) throws Throwable {
            System.out.println("调用前");
            Object result = proxy.invokeSuper(obj, params);
            System.out.println(" 调用后");
            return result;
        }
    
        //Enhancer类是CGLib中的一个字节码增强器
        private Enhancer enhancer = new Enhancer();
        public Object getProxy(Class clazz) {
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
            return enhancer.create();
        }
    }

3.测试类

    public class Test {
        public static void main(String[] args) {
            //生成代理类到本地
            System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "target/cglib");
            ServiceImpl service = new ServiceImpl();
            CglibProxy cp = new CglibProxy();
            ServiceImpl proxy = (ServiceImpl) cp.getProxy(service.getClass());
            proxy.doService("avalon");
        }
    }

生成代理类反编译后:

    public class ServiceImpl$$EnhancerByCGLIB$$2c41332b extends ServiceImpl 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$doService$0$Method;
        private static final MethodProxy CGLIB$doService$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];
            Class var0 = Class.forName("ServiceImpl$$EnhancerByCGLIB$$2c41332b");
            Class var1;
            Method[] 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$1$Method = var10000[0];
            CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
            CGLIB$toString$2$Method = var10000[1];
            CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
            CGLIB$hashCode$3$Method = var10000[2];
            CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
            CGLIB$clone$4$Method = var10000[3];
            CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
            CGLIB$doService$0$Method = ReflectUtils.findMethods(new String[]{"doService", "(Ljava/lang/String;)Ljava/lang/String;"}, (var1 = Class.forName("ServiceImpl")).getDeclaredMethods())[0];
            CGLIB$doService$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "doService", "CGLIB$doService$0");
        }
    
        final String CGLIB$doService$0(String var1) {
            return super.doService(var1);
        }
        public final String doService(String var1) {
            //方法拦截器
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if(this.CGLIB$CALLBACK_0 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
            //将具体方法调用方在拦截器中执行
            return var10000 != null?(String)var10000.intercept(this, CGLIB$doService$0$Method, new Object[]{var1}, CGLIB$doService$0$Proxy):super.doService(var1);
        }
        //其他
        ....
    }

从代理类里面可知道对于原来的doService函数,代理类里面对应了两个函数分布是doService 和CGLIB$doService 0 其 中 后 者 是 在 方 法 拦 截 器 里 面 调 用 的 的 , 前 者 则 是 我 们 使 用 代 理 类 时 候 调 用 的 函 数 。 当 我 们 代 码 调 用 d o S e r v i c e 时 候 , 会 具 体 调 用 到 方 法 拦 截 器 的 i n t e r c e p t 方 法 , 该 方 法 内 则 通 过 p r o x y . i n v o k e S u p e r 调 用 C G L I B 0 其中后者是在方法拦截器里面调用的的,前者则是我们使用代理类时候调用的函数。当我们代码调用doService时候,会具体调用到方法拦截器的intercept方法,该方法内则通过proxy.invokeSuper调用CGLIB 0使doServiceinterceptproxy.invokeSuperCGLIBdoService$0

优缺点

  • JDK实现方式产生的代理类是接口的实现,也就是说serviceProxy是可以赋值给IService的,但是不能赋值给ServiceImpl。对应Cglib则使用的继承机制,具体说被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。
  • JDK代理只能对接口进行代理,Cglib则是对实现类进行代理。
  • Cglib采用的是继承,所以不能对final修饰的类进行代理。
  • JDK采用反射机制调用委托类的方法,Cglib采用类似索引的方式直接调用委托类方法;
  • 从 jdk6 到 jdk7、jdk8 ,动态代理的性能得到了显著的提升,与cglib的性能上已经差别不大

你可能感兴趣的:(JDK动态代理代理与Cglib代理区别)