Spring—AOP
AOP是在不惊动原有的代码的基础上对功能进行增强操作
连接点:JoinPoint,可以被AOP控制的方法
通知:Advice,增强的逻辑,共性功能
切入点:PointCut,匹配连接点的条件,表明连接点中哪些方法是真正需要被增强的
切面:Aspect,描述通知与切入点对应关系的
😃通知有五种类型:
@Before前置通知
@After后置通知
@AfterReturning返回后通知
@AfterThrowing抛出异常后通知
@Around环绕通知
顾名思义,就是分别在原始切入点方法之前,之后,返回后,抛出异常后,还有把原始切入点方法放入通知中间执行的
😃动态代理实现AOP:
代理其实本质就是生成一个代理对象,这个代理对象和切入点有相同的方法,然后代理对象中的方法是根据需求进行增强过的,然后当调用切入点的方法时,不走切入点的方法,走代理对象增强过的方法,而怎么保证代理对象和切入点有着相同的方法呢,基于这个思路,代理它又分为jdk代理和cglib代理
- jdk代理:是java自带的代理方法,主要采用了多态和反射的技术,它是让代理对象和目标类一起去实现一个共同的接口,这样就可以保证两者有相同的方法
newProxyInstance方法的三个参数:
-
- 第一个参数,类加载器
- 第二个参数,接口集合,因为jdk代理需要目标对象实现接口
- 第三个参数,一个函数式接口,实现增强方法逻辑,这个函数式接口也有三个参数:
-
-
- 第一个参数,目标对象
- 第二个参数,需要被增强的方法
- 第三个参数,方法执行的参数
-
- cglib代理:不是jdk自带的代理,需要导外部依赖,其底层是让代理类继承目标类,通过Enhancer.create获取代理对象
create方法的两个参数:
-
- 第一个参数:目标类
- 第二个参数:一个函数式接口,实现增强方法逻辑,这个函数式接口有四个参数:
-
-
- 第一个参数,代理对象自己
- 第二个参数,需要被增强的方法
- 第三个参数,方法执行的参数
- 第四个参数,MethodProxy,代理不走反射的关键
-
其实AOP的重点就是如何获取到目标类的原始方法,并把它放到特定的上下文环境下执行,对于这一点,jdk代理是采用反射,你看,我都反射了,我还拿不到你的原始方法?直接获取到Method类,再放入特定的上下文环境,也就是AOP通知,调用invoke方法即可。而cglib代理是怎么获得原始方法的呢,它的代理类是继承目标类的,那都直接继承目标类了,那不就可以直接通过super.的形式调用目标类的原始方法
😃spring如何选择代理方式:
Spring容器代理时,会有一个ProxyFactory类,这个类传入目标类对象和通知,里面有个boolean类型参数proxyTargetClass,这个如果设置为false,就会去检查目标类是否继承了接口,如果有,就用jdk代理,没有就cglib代理,如果为true,则不管有没有继承接口,都用cglib代理
😃一个方法被多个切面AOP了?
此时需要给切面@Order(1)标注顺序,越小优先级越高,如果没标注顺序,就会按照注册顺序进行AOP,此时的顺序是不可知的,是随机的
😃AOP什么时候失效?
- 类中自调用方法,同一个类中A调用B方法,B方法的AOP不会生效
- 调用内部类方法
- 调用静态方法,静态方法不会被AOP
- 调用final方法,final方法不会被AOP
- 目标类不符合规则,如jdk代理时没继承接口,cglib代理时是final类