前言
在一个风和日立的下午,一个java程序员正在愉(tong)快(ku)的修改着bug,旁边的一个好基友突然问我AOP动态代理的区别。楞了一下,心想 " 卧槽,这特喵的就触及到我的知识盲区了"。尽管内心波涛汹涌,表面上还是故作镇定的答道:“我现在还有工作要忙,明天再告诉你”。好基友只能点点头说那好吧,下班回到家后赶紧麻溜的打开笔记本一顿谷歌加百度
- JDK动态代理是基于接口的代理方式,其实现原理是让代理对象与原生对象实现相同的接口,并且在代理对象内部维护一个原生对象的引用。这样一来,不需要加强的方法,就可以通过原生对象的引用直接返回。需要加强的方法可以在原生对象方法执行前后做相应的处理。
- CGLIB动态代理是基于继承的代理方式,其实现原理也是在代理对象内部维护一个原生对象的引用,不同的是此方式生成的代理对象是原生对象的子类。因此由于final类中的方法、private方法、final方法不能被继承、因此这些方法都无法使用CGLIB进行增强
Spring相关特性
- Spring IOC中存放的Bean默认是单例的
- Spring IOC进行依赖注入时,只有需要被AOP加强的Bean才会注入代理对象,否则注入原生对象
- Spring MVC中的AOP底层实现默认是JDK动态代理,只有被代理的类没有实现接口时才会使用CGLIB代理。
- Spring Boot中的AOP的底层实现默认是CGLIB。
- Spring中的一些注解(@Async@Retry@Transaction)都属于AOP的一种
- 需要被AOP增强的方法,必须由代理对象直接调用才能生效(内部方法调用不生效)。
- 如果一个被spring管理的类使用了AOP,那么在IOC容器中维护的就是该类的代理对象。如果采用的是JDK动态代理,那么就只能通过接口的方式进行注入。通过实现类进行注入时将会提示类转换异常。
如果不注意这些点,在实际开发过程中往往会出现一些奇怪的现象。我遇到的问的最多的一个问题就是为什么事务没生效? 感兴趣的可以参考我的另一篇文章:为啥我的@Transaction不生效?
JDKProxy伪代码
代码语言:javascript复制/**
* 接口:TargetService
* 原生类:Target 指被代理的类
* 代理类:TargetProxy 指代码增强后产生的类
* 代理对象:targetService 指代理类所产生的对象
* 原生对象:target 指代理类内部引用的对象
*
* @author hcq
* @date 2020/3/25 20:57
*/
public class JdkProxy {
interface TargetService {
void save();
void select();
}
static class Target implements TargetService {
@Override
public void save() {
System.out.println("我要变强!!!");
}
@Override
public void select() {
System.out.println("我是咸鱼,我不增强");
}
}
static class TargetProxy implements TargetService{
private final Target target;
TargetProxy(Target target){
this.target = target;
}
@Override
public void save() {
System.out.println("已充值1000000元");
target.save();
System.out.println("小伙子你很强!");
}
@Override
public void select() {
target.select();
}
}
public static void main(String[] args) {
//new TargetProxy(new Target())对象的过程其实就相当于是spring注入代理对象的过程
TargetService targetService=new TargetProxy(new Target());
//增强后的方法
targetService.save();
//未进行增强的方法
targetService.select();
}
}
CGLIB伪代码
代码语言:javascript复制/**
* @author hcq
* @date 2020/3/25 23:19
*/
public class Cglib {
static class Target{
void save(){
System.out.println("我不充钱也要变强!!!");
}
void select(){
System.out.println("我继续咸鱼。。。。。");
}
}
static class TargetProxy extends Target{
private final Target target;
TargetProxy(Target target){
this.target = target;
}
@Override
void save(){
target.save();
System.out.println("日复一日,年复一年的辛苦刷经验,终于达到了完成了变强的愿望。n");
}
@Override
void select(){
System.out.println("我继续咸鱼。。。。。");
}
}
public static void main(String[] args) {
//new TargetProxy(new Target())对象的过程相当于是spring注入CGLIB代理对象的过程
Target targetService=new TargetProxy(new Target());
//增强后的方法
targetService.save();
//未进行增强的方法
targetService.select();
}
}
觉得写的还行的话点个赞再走呗,你们的点赞与关注就是我创作的最大动力。