Java的动态代理
date
Jun 12, 2017
slug
Java的动态代理
status
Published
tags
Java
summary
type
Post
JDK动态代理
JDK原生动态代理必须先实现接口,再通过反射实现方法增强,参考Oracle文档,下面直接上代码例子:
- 先定义接口
- 定义实现类
- 再定义代理类,实现InvocationHandler接口
最后运行主类:
运行结果:
CGLIB
CGLIB通过字节码操作生成子类的方法来进行代理,所以final修饰的方法无法被增强,子类无法覆盖父类的final方法。首先引入cglib.jar,然后编写一个代理类,对方法进行前后增强:
在主类中通过enhancer获取到代理类:
使用过程中可能会报以下错误:
这是cglib.jar用到asm.jar,所以asm.jar也需要加入到classpath中。
运行期间调试看一下printerImplProxy对象:
可以看到printerImplProxy为类PrinterImpl$$EnhancerByCGLIB$$51a0998的对象,但是看不到这个类内部结构是怎么样的,可以通过本地生成的class文件反编译一下查看类的源码:
通过jad online反编译一下,也可以通过jd-gui本地反编译,但我使用jd-gui过程中反编译的源码有点莫名其妙,我这就直接用在线反编译了:
以下节选部分关键代码:
可见cglib是通过创建子类的方式实现代理的,如果方法被final,static修饰,则无法进行增强,因为被final,static修饰的方法子类无法重写。
Spring AOP用哪种?
Spring AOP两种动态代理的方式都用,但默认用JDK的动态代理,对于没有实现接口的业务类就会使用CGLIB,Spring文档有阐明如何选择用哪种方式的:
Spring AOP defaults to using standard JDK dynamic proxies for AOP proxies. This enables any interface (or set of interfaces) to be proxied. Spring AOP can also use CGLIB proxies. This is necessary to proxy classes rather than interfaces. By default, CGLIB is used if a business object does not implement an interface.