spring的AOP底层原理

AOP:面向切面编程,是对oop(面向对象)的一种补充,完成面向对象完成不了的一小类问题,如:日志管理,性能检查,事物等等;(建议真正感兴趣的读者,结合底层源码,可以去看一下网名为:墨家巨子@俏如来 的文章,我这一篇相当于一个自己的笔记,加总结)

下面我们直接来了解Spring的AOP的实现原理

1.我们知道springAOP分为注解形式,和xml形式;但是无论是注解形式,还是xml形式,我们都需要在配置文件中添加对应的"自定义标签":

如注解形式:

 当然,除了AOP的自定义标签,还有其它的自定义标签,比如事物.....等,spring为了实现这些特殊且标签的解析,和其功能,spring特意提供了一个公共解析规则接口,来统一管理spring自定义标签的解析NamespaceHandlerSupport

我们可以看到NamespaceHandlerSupport接口下面实现了很多实现类,其中就包括我们熟悉的Aop自定义标签解析的类和事物标签的解析类;为什么spring对自定义标签,还额外分别生成对应的解析类和公共接口规则,我个人认为是为了实现"职责分裂",方便管理和后期的维护;

当我们认识到spring会对自定义标签,生成其对应的自定义解析器后,接下来我们看源码

2. AopNamespaceHandler类

进入AopNamespaceHandler类,在这里我们可以看到spring针对于不同形式的AOP注册了不同的解析类:

ConfigBeanDefinitionParser:基于xml的Aop解析类,

AspectJAutoProxyBeanDefinitionParser:基于注解形式的Aop解析类;(本文我们主要看基于注解的Aop)

3.进入AspectJAutoProxyBeanDefinitionParser类

该方法的作用是创建一个AspectJAnnotionAutoProxyCreator自动代理创建器:它的作用就是用来处理AOP

4.进入AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);

在这里spring注册了两个功能,

1.注册基于AOP的注解解析器:AnnotationAutoProxyCreator

2.对aop标签的两个属性赋值

        2.1 proxy_target_class:指定当前AOP代理使用那种代理模式(jdk、cglib)

        2.2 expose_proxy

5.继续进入AopConfigUtils.registerOrEscalateApcAsRequired()方法

在 registerOrEscalateApcAsRequired()方法中,总共就做了一件事情,生成Aop解析器,先从缓存中获取,如果缓存中有,则根据优先级选择使用那个,如果不存在,则新生成一个注解解析器,并加入缓存中

6.现在注解解析器有了,那么我们接下来真正看Aop是怎么实现的,Aop的功能实现,跟bean的加载流程息息相关

springAop的实现是在初始化后,在beanPostProcessor的后置处理器中实现的,我们直接看初始化后的代码

7.进入初始化方法:initializeBean

进入初始化方法后,我们可以看到,在这里spring调用了beanPostProcessor的后置处理器

8.进入beanPostProcessor的后置处理器的调用

在这里就做了一件事情,调用当前spring中的所有的beanPostProcessor的后置处理器方法

9.接下来我们直接看基于Aop的注解解析器:AbstractAutoProxyCreator(beanPostProcessor的子类)

10. 进入wrapIfNecessary()方法

 在这里首先判断当前bean是否需要代理增强,如果不需要,则直接返回,如果需要,则寻找bean的增强器,然后根据增强器创建代理对象

11.寻找bean的增强器getAdvicesAndAdvisorsForBean()方法

寻找bean的增强器,判断符合当前bean的增强器,并封装成List<advisor>返回

12.寻找所有的bean的增强器findCandidateAdvisors()方法

13.我们继续看寻找AOP的增强器方法buildAspectJAdvisors()

在这里真正的开始进行寻找切面类,获取增强方法,这里其实是先判断缓存中是否有增强方法,如果有则直接走下面的从缓存中获取增强器,如果没有,则在查询当前项目中的增强器,并缓存起来

14.进入this.advisorFactory.getAdvisors()方法:寻找增强器

 15.进入getAdvisor()方法

   getPointcut()方法

 findAspectJAnnotationOnMethod()方法:寻找切点信息

找到切点信息,并封装成AspectJExpressionPointcut返回

进入InstantiationModelAwarePointcutAdvisorImpl()构造器方法

16.进入instantiateAdvice()方法

找到增强器中的,增强方法,并将其封装到对应的Advice类中;在这里我们就找到了所有的增强器了,接下来,就用这些增强器创建,代理增强对象

 17.createProxy()方法:创建代理对象

18.proxyFactory.getProxy(this.proxyClassLoader):方法:创建代理对象

 

 在这里,我们可以看到springAop是通过代理模式,来实现功能增强,来实现的Aop;假如目标类是实现了接口的类,且proxy_target_class为false则默认使用jdk动态代理,假如proxy_target_class为true,无论改类有没有实现接口,则使用cglib动态代理,加入该类没有实现接口,则直接使用cglib动态代理

19.创建完代理对象后,接下来执行目标方法

 首先获取增强器执行链,就是对应的增强通知方法

 20.进入proceed()方法:这个方法会涉及到一个复杂的调用链

 第一次进来,this.currentInterceptorIndex=-1,

this.interceptorsAndDynamicMethodMatchers.size() - 1 = 4;此时-1 != 4,则不执行目标方法,则走下面的执行链的增强方法

走到第一个增强器方法后,在执行过程中又回到了,proceed方法,然后在接着看proceed方法

第二次进入proceed()方法

此时this.currentInterceptorIndex=-1,

this.interceptorsAndDynamicMethodMatchers.size() - 1 = 3;此时-1 != 3,则不执行目标方法,则继续走下面的执行链的增强方法

 在这里,我们看到第二次,走增强方法的时候,走到返回通知的方法,在Aop里面,返回通知里面的增强方法,是不管目标方法是否报错,都会执行的方法,在这里,我们可以看到返回通知里的方法确实也是这样,不管mi.proceed()主干流程方法是否会报错,到最后,都会执行finally中的方法,然后继续回到proceed()方法(注意,在这几次走增强方法时,每个增强方法都没执行完,然后就继续调用了proceed方法,这就是springAop执行增强方法的巧妙之处,感兴趣的读者可以下来自行了解)

 第三次进入proceed()方法

此时this.currentInterceptorIndex=-1,

this.interceptorsAndDynamicMethodMatchers.size() - 1 = 2;此时-1 != 2,则不执行目标方法,则继续走下面的执行链的增强方法

 此时走到了异常通知,异常通知:当目标方法发生报错时,才会执行异常通知,在这里,我们可以看到,同样的首先,继续调用proceed()方法,然后通过catch(){}包住了,异常通知增强方法,只有在程序发生错误时,才会走异常通知的增强方法

继续走proceed()方法

第四次次进入proceed()方法

此时this.currentInterceptorIndex=-1,

this.interceptorsAndDynamicMethodMatchers.size() - 1 = 1;此时-1 != 1,则不执行目标方法,则继续走下面的执行链的增强方法

 此时走到了后置通知,后置通知:程序一切正常,调用目标方法之后,走后置通知,如果目标方法发生报错,则不走后置通知,在后置通知invoke()方法中,也是非常符合这个逻辑的,这里我们可以看到,进来之后首先继续调用执行链,如果执行链没有报错,则在走后置通知的增强方法,在这之前,我们已经走了2个增强了,分别是返回通知和异常通知,还剩下前置通知,和执行目标方法了,根据执行链,越调用后面的通知,越早执行,后置通知,是当前置+目标方法正常执行,不报错,则在执行后置通知,所以这里非常符合,在这里首先继续调用执行链,就是调用前置通知+目标放,然后调用完成之后,如果两个都没报错,则走这里的后置通知增强方法,否则直接抛异常,往上执行,就不在走this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());方法了

接着,我们继续往走执行链

 此时第五次次进入proceed()方法

此时this.currentInterceptorIndex=-1,

this.interceptorsAndDynamicMethodMatchers.size() - 1 = 0;此时-1 != 0,则不执行目标方法,则继续走下面的执行链的增强方法

此时走到前置通知,在这里我们可以看到,前置通知里面的invoke()方法,跟之前的通知都不一样了,在这里是先走的前置增强,然后在走的执行链,为什么呢,我们都知道前置通知,是在目标方法执行前调用,既然我们现在都已经走到了前置通知方法了,那么下一步,毋庸置疑,肯定就是执行目标方法了,既然下一步肯定是执行目标方法了,所以在前置通知这里,就可以完全先执行前置增强方法,然后在执行执行链,因为到执行链的时候,就执行目标方法了

继续往下执行,走执行链

 在次进入到proceed()方法后,此时-1=-1了,则就执行目标方法,不在走下面的增强器了,执行完目标方法后,在一层一层的返回执行之前在各个增强器里面,没有执行完的增强方法;AOP整体流程也就到这里了

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值