静态代理:由程序员创建或工具生成代理类的源码,再编译代理类,即代理类和委托类的关系再程序运行前就已经存在。
动态代理:在运行期间使用动态生成字节码形式,动态创建代理类。使用的工具有 jdkproxy、cglibproxy 等。
JDK实现动态代理:
利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
- JDK动态代理只能代理有接口的类,并且是能代理接口方法,不能代理一般的类中的方法
- 提供了一个使用InvocationHandler作为参数的构造方法。在代理类中做一层包装,业务逻辑在invoke方法中实现
- 重写了Object类的equals、hashCode、toString,它们都只是简单的调用了InvocationHandler的invoke方法,即可以对其进行特殊的操作,也就是说JDK的动态代理还可以代理上述三个方法
- 在invoke方法中我们甚至可以不用Method.invoke方法调用实现类就返回。这种方式常常用在RPC框架中,在invoke方法中发起通信调用远端的接口等
cglib动态代理
利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
两者区别
动态代理分为两种:
- jdk的动态代理
- 代理对象和目标对象实现了共同的接口
- 拦截器必须实现InvocationHanlder接口,其中的invoke方法是执行代理时会执行的方法(参数是要代理的方法),并且同时传入自身被调用的方法的的Method对象和参数列表方便我们编码实现方法的调用。
* cglib的动态代理(要用到cglib的jar包)
* 代理对象是目标对象的子类
* 拦截器必须实现MethodInterceptor接口
* hibernate中session.load采用的是cglib实现的
JDK动态代理和CGLIB字节码生成的区别?
1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类。
2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,
并覆盖其中方法实现增强,但是因为采用的是继承,所以该类或方法最好不要声明成final,
对于final类或方法,是无法继承的。
Spring如何选择用JDK还是CGLiB?
1)当Bean实现接口时,Spring就会用JDK的动态代理。
2)当Bean没有实现接口时,Spring使用CGlib是实现。
3)可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class=“true”/>)。
JDK和CGLIB动态代理总结
JDK代理是不需要第三方库支持,只需要JDK环境就可以进行代理,使用条件:
1)实现InvocationHandler
2)使用Proxy.newProxyInstance产生代理对象
3)被代理的对象必须要实现接口
CGLib必须依赖于CGLib的类库,但是它需要类来实现任何接口代理的是指定的类生成一个子类,
覆盖其中的方法,是一种继承但是针对接口编程的环境下推荐使用JDK的代理;
部分转自:https://blog.youkuaiyun.com/yhl_jxy/article/details/80635012