Java Proxy 和 CGLIB 动态代理
Java Proxy & CGLIB
好的博客:https://www.cnblogs.com/huhx/p/dynamicTheoryAdvance.html
源码:https://blog.csdn.net/mhmyqn/article/details/48474815
CGLIB博客:http://www.importnew.com/27772.html
代理比较:http://www.importnew.com/22015.html
代理与RPC介绍:http://www.importnew.com/29359.html
场景:动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询、测试框架的后端mock、RPC,Java注解对象获取等
应用:1、代理模式/装饰器模式的动态实现;2、实现AOP;3、实现RPC。
将分散的对对象不同方法的调用转发到一个同一的处理函数中来。
动态代理在Java中有着广泛的应用,比如Spring AOP,Hibernate数据查询、测试框架的后端mock、RPC,Java注解对象获取等。静态代理的代理关系在编译时就确定了,而动态代理的代理关系是在编译期确定的。静态代理实现简单,适合于代理类较少且确定的情况,而动态代理则给我们提供了更大的灵活性。
1、静态代理:
弊端:
如果要想为多个类进行代理,则需要建立多个代理类,维护难度加大。
仔细想想,为什么静态代理会有这些问题,是因为代理在编译期就已经决定,如果代理哪个发生在运行期,这些问题解决起来就比较简单,所以动态代理的存在就很有必要了。
2、JDK原生动态代理:
Java动态代理为我们提供了非常灵活的代理机制,但Java动态代理是基于接口的,如果对象没有实现接口我们该如何代理呢?CGLIB登场。
1、首先实现一个InvocationHandler,方法调用会被转发到该类的invoke()方法。
2、然后在需要使用Hello的时候,通过JDK动态代理获取Hello的代理对象。
好处:
当动态生成的代理类调用方法时,会触发invoke方法,在invoke方法中可以对被代理类的方法进行增强。
通过动态代理可以很明显的看到它的好处,在使用静态代理时,如果不同接口的某些类想使用代理模式来实现相同的功能,将要实现多个代理类,但在动态代理中,只需要一个代理类就好了。
除了省去了编写代理类的工作量,动态代理实现了可以在原始类和接口还未知的时候,就确定代理类的代理行为,当代理类与原始类脱离直接联系后,就可以很灵活地重用于不同的应用场景中。
弊端:
代理类和委托类需要都实现同一个接口。也就是说只有实现了某个接口的类可以使用Java动态代理机制。但是,事实上使用中并不是遇到的所有类都会给你实现一个接口。因此,对于没有实现接口的类,就不能使用该机制。
动态代理与静态代理的区别
Proxy类的代码被固定下来,不会因为业务的逐渐庞大而庞大;
可以实现AOP编程,这是静态代理无法实现的;
解耦,如果用在web业务下,可以实现数据层和业务层的分离。
动态代理的优势就是实现无侵入式的代码扩展。 静态代理这个模式本身有个大问题,如果类方法数量越来越多的时候,代理类的代码量是十分庞大的。所以引入动态代理来解决此类问题
3、CGLIB动态代理
CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。
cglib需要指定父类和回调方法。当然cglib也可以与Java动态代理一样面向接口,因为本质是继承。
cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
1、首先实现一个MethodInterceptor,方法调用会被转发到该类的intercept()方法。 2、然后在需要使用HelloConcrete的时候,通过CGLIB动态代理获取代理对象。 我们通过CGLIB的Enhancer来指定要代理的目标对象、实际处理代理逻辑的对象,最终通过调用create()方法得到代理对象,对这个对象所有非final方法的调用都会转发给MethodInterceptor.intercept()方法,在intercept()方法里我们可以加入任何逻辑,比如修改方法参数,加入日志功能、安全检查功能等;通过调用MethodProxy.invokeSuper()方法,我们将调用转发给原始对象。
JDK原生动态代理是Java原生支持的,不需要任何外部依赖,但是它只能基于接口进行代理;CGLIB通过继承的方式进行代理,无论目标对象有没有实现接口都可以代理,但是无法处理final的情况。
Java动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架。
从反编译$Proxy0.class源码动态生成的代理类有如下特性:
1、继承了Proxy类,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。
2、提供了一个使用InvocationHandler作为参数的构造方法。
3、生成静态代码块来初始化接口中方法的Method对象,以及Object类的equals、hashCode、toString方法。
4、重写了Object类的equals、hashCode、toString,它们都只是简单的调用了InvocationHandler的invoke方法,即可以对其进行特殊的操作,也就是说JDK的动态代理还可以代理上述三个方法。
5、代理类实现代理接口的sayHello方法中,只是简单的调用了InvocationHandler的invoke方法,我们可以在invoke方法中进行一些特殊操作,甚至不调用实现的方法,直接返回。
1. 动态代理是什么
动态代理提供一种抽象,能够将对象中不同方法的调用重定向到一个统一的处理函数,做自定义的逻辑处理。 但是对于调用者,对此毫无察觉,就好像调用的方法是用传统方式实现的一般。
这种语法,在java中被称为动态代理。之所以叫做动态代理,是因为它能避免传统代理模式实现中人工一个一个的将java函数转发过去, 而是能够让代码自动做到这一点,这样代理类的代码是和业务无关的,不会因为业务类的方法增多而逐渐庞大。 使代码更易维护更易修改,实现自动化搬砖。
实际上,被代理的类不一定位于本机类,动态代理语法提供了一种抽象方式,被代理的类也可以位于远程主机上,这也是RPC框架实现原理的一部分。
理解了动态代理的概念后不难发现,动态代理概念上有着这么几个部分:
给调用者使用的代理类。在java中,我们发现动态代理提供的抽象天然契合面向接口编程,因此它也有可能是接口。
一个统一的处理函数,收集不同函数转发过来的请求,可自定义处理逻辑集中处理。java中它可能会成为一个较独立的部分,因此也可能是类。
Last updated
Was this helpful?