代理是Java常用的设计模式,代理类通过调用被代理类的相关方法,实现对相关方法增强。比如加入事务、日志、报警发邮件等操作。
静态代理
静态代理,就是由程序员手动编写代理类或者用工具生成代理类的代码,再进行编译生成class文件,实现代理。比如简单工厂模式。
用法:
- 代理类和目标类都实现相同接口。
- 代理类持有目标类的引用。
缺点:
静态代理要为每个目标类创建一个代理类,当需要代理的对象太多,那么代理类也变得很多。代理类违背了可重复代理只写一次的原则。
动态代理
为了解决静态代理的缺点,于是引入了动态代理。
它有一个好处,那就是不用写很多代理类,生成的代理类数量是固定的。
一般动态代理分为2种:
JDK动态代理
JDK动态代理是JDK自带的,不依赖第三方框架。
它的实现原理,就是利用Java的反射机制,创建一个实现接口的代理类。
用法:
- 被代理对象必须实现接口。
- 代理对象由代理工厂自动生成。
下面贴个例子
接口类:
实现类:
代理工厂:
测试类:
CGLIB代理
使用CGLIB代理需要引入CGLIB库,它使用字节码技术实现代理。
|
|
2种动态代理的区别
JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而CGLIB动态代理是利用asm开源包,加载代理对象类的class文件,修改其字节码生成子类来处理。
在 Spring 中,
- 如果目标对象实现了接口,默认情况下会采用JDK动态代理实现AOP
- 如果目标对象实现了接口,可以强制使用CGLIB实现AOP
- 如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换
如何强制使用CGLIB实现AOP?
- 添加CGLIB依赖
- 在Spring配置文件中加入
<aop:aspectj-autoproxy proxy-target-class="true"/>
- 如果是SpringBoot,在配置文件设置
spring.aop.proxy-target-class=true
JDK动态代理和CGLIB字节码生成的区别?
- JDK动态代理只能对实现了接口的类生成代理,而不能针对未实现接口的类
- CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
- 因为是继承,所以该类或方法最好不要声明成final