AOP 原理解析 跳转逻辑 代码演示
文章目录
建议大家先看“三、总结”,有一个总体认识比较好
一、AOP功能测试
如果都放在了MathCalculator代码里,那就是一种耦合的方式
所以定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里,然后执行
通知方法:
* 前置通知(@Before):logStart:在目标方法(div)运行之前运行
* 后置通知(@After):logEnd:在目标方法(div)运行结束之后运行(无论方法正常结束还是异常结束)
* 返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
* 异常通知(@AfterThrowing):logException:在目标方法(div)出现异常以后运行
先不用环绕通知,尝试前面4个。注意不是Junit的@Before,@After
是org.aspectj.lang.annotation.After;
@Before("top.p3wj.aop.MathCalculator.div")
如果想切MathCalculator的所有方法(且不区分参数,加"…"),即MathCalculator.*(…)
1.1
但是看起来非常繁琐,有公共的切入点,所以可以提取出来。定义一个方法
1.2 加入到容器中
1.3 告诉哪一个类是切面类
1.4 但是最后记住还要开启AspectJ。给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】
1.5 测试一下是否成功
发现并没有输出相应的东西,这是因为这是我们自己new的,只要容器中的组件才可以使用切面的功能
1.5.1 带异常
这下就有了
1.5.2 不带异常
2.1 那么怎么拿到运行时的信息呢?JoinPoint
2.1.1
JoinPoint.getSignature获得方法签名
获得方法名
参数列表
2.1.2
怎么获得返回值呢?returning属性
returning指定谁来封装这个返回值,比如我们用Object result来接受所有的返回值
2.1.3 获得异常,通过throwing
也跟returning一样要指定
不然会报红色,
这个也一样,如果不指定,spring不知道这个exception要干什么
加上后用1/0看一下结果
那么没有这个@AfterThrowing呢?
我们发现是对这个异常没有进行我们的一个处理的,并没有输出那一句话。
2.1.4 JoinPoint位置
我们发现,JoinPotin如果不放在第一个参数,spring是无法解析的
看一下异常:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.context.event.internalEventListenerProcessor': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 formal unbound in pointcut
放在第一位就正常了
二、AOP原理
2.1- @EnableAspectJAutoProxy
AOP就是从@EnableAspectJAutoProxy开始的,加了就有AOP,不加就没有
我们点进去看一下
发现有ImportBeanDefinitionRegistrar,这是之前学的可以给容器bean中自定义注册
英文不好,我就用Translation插件翻译了,大家可以在plugins中搜索安装
可以自定义地来注册,给BeanDefinitionRegistry
我们回到以前看看以前怎么做的,回到MainConfig2
ImportSelector
ImportBeanDefinitionRegistrar
那么AspectJAutoProxyRegistrar注册了什么bean呢?我们打一个断点debug一下
注册这个组件,如果需要的情况下
调用另一个方法,并传了AnnotationAwareAspectJAutoProxyCreator.class,我们step into进去瞧瞧
3.1 判断是否容器中包含org.springframework.aop.config.internalAutoProxyCreator
3.2 包含则取得这个org.springframework.aop.config.internalAutoProxyCreator
3.3判断这个名字是否等于
对应的他想注册这个
AnnotationAwareAspectJAutoProxyCreator
他这个是判断有了就:
但是我们没有。。。第一次
所以进行了else
3.4
定义一个bean
3.5
然后这个bean的名就叫org.springframework.aop.config.internalAutoProxyCreator
4.1好了,这个beanDefinition就返回了,我们进行下一步
把@EnableAspectJAutoProxy这个注解的信息拿来
4.2 拿来看这个proxyTargetClass,exposeProxy属性是否为true
4.3 这个后来再说
如果为true,就做一些什么操作。
那么,重点就在于他给容器注册了一个AnnotationAwareAspectJAutoProxyCreator,把这个的功能研究出来了,那么AOP功能就出来了。以后也一样的,看见有@EnableXX的注解,就再去看看他给容器注册了什么组件,再去看这些组件的功能是什么
5.那我们就来看一下AnnotationAwareAspectJAutoProxyCreator
5.1 它有很多的继承关系,大家可以放大看一下
注意XXBeanPostProcessor,bean的后置处理器
BeanFactoryAware,能把工厂传进来的
2.2- AnnotationAwareAspectJAutoProxy
只要分析清楚作为后置处理器和BeanFactory做了哪些工作,整个aop的流畅我们就清楚了
因为是从AbstractAutoProxyCreator开始实现SmartInstantiationAwareBeanPostProcessor和BeanFactoryAware接口的
我们点进去看一下
我们发现是它进行setBeanFactory的,我们把断点打在这
只要是postProcessXX乱七八糟的,都是跟后置处理器有关的
我们把所有跟后置处理器有关的逻辑都打上断点
直接返回,或返回空方法的我们就不管了
打上断点:
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
注意有的方法名字有点像,
一个是postProcessBeforeInstantiation,一个是postProcessBeforeInitialization
一些不是重写的,自己定义的我们就不打断点了,例如
我们继续上一层: