本文包含以下内容:
postProcessBeforeInstantiation 执行时机
postProcessBeforeInstantiation 的具体作用
目标方法div执行流程一:获取拦截器链
目标方法div执行流程二:拦截器链的调用流程分析
AOP 总结
前文回顾:
《Spring注解驱动开发之十三——AOP原理分析(一)@EnableAspectJAutoProxy注解干了什么》
上文说到,通过 @EnableAspectJAutoProxy 注解,将通过注册器往Spring中注册一个 AnnotationAwareAspectJAutoProxyCreator 实例化对象,并且讨论了AnnotationAwareAspectJAutoProxyCreator 的继承关系。
本文将紧接上文,进行断点调试在 registerBeanPostProcessors 函数之后讨论, AnnotationAwareAspectJAutoProxyCreator 实例化组件如何实现AOP 的功能。
1.postProcessBeforeInstantiation 执行时机
在postProcessBeforeInstantiation 函数添加断点,查看执行时机
调用栈如图所示:
1)
refresh:543, AbstractApplicationContext
调用栈跟上文类似,上文,注册了BeanPostProcessors 现在运行 finishBeanFactoryInitialization 函数
根据注释:注册所有剩余得“非懒加载”得单例
// Instantiate all remaining (non-lazy-init) singletons.
2)进入到内部,是创建Bean 得流程
finishBeanFactoryInitialization:867, AbstractApplicationContext
preInstantiateSingletons:761, DefaultListableBeanFactory
getBean:197, AbstractBeanFactory
doGetBean:302, AbstractBeanFactory
getBean->doGetBean()->getSingleton()
主流程
可以看到 sharedInstance 之前,尝试获取,确认容器内没有才进行创建
// Eagerly check singleton cache for manually registered singletons.
3)getSingleton:230, DefaultSingletonBeanRegistry
getObject:306, AbstractBeanFactory$1
createBean:473, AbstractAutowireCapableBeanFactory
在这里可以看到注释 :让BeanPostProcessors有机会 返回一个代理 而不是原有bean实例。
所以在获取到的Bean ==null 时在后面将会进行 doCreateBean(beanName, mbdToUse, args); 创建Bean
try {
查看函数可以看到,跟上文的 创建Bean 的一样
实例化Bean
if (instanceWrapper == null) {
赋值以及初始化
populateBean(beanName, mbd, instanceWrapper);
4) 进入 resolveBeforeInstantiation 函数
resolveBeforeInstantiation:1011, AbstractAutowireCapableBeanFactory
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
看到函数 中:
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
进入到函数 applyBeanPostProcessorsBeforeInstantiation
查看是否实现InstantiationAwareBeanPostProcessor ,如果是则执行postProcessBeforeInstantiation ,如果返回不为null 则运行applyBeanPostProcessorsAfterInitialization 。所以在这找到了Before 和After
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
从而找到了, postProcessBeforeInstantiation 、applyBeanPostProcessorsAfterInitialization 执行时机 并且得出结论:
AnnotationAwareAspectJAutoProxyCreator 在所有bean创建之前会有一个拦截,InstantiationAwareBeanPostProcessor,会调用postProcessBeforeInstantiation()
2.postProcessBeforeInstantiation 具体作用
我们分别对自定义得MathCalculator进行断点调试, postProcessBeforeInstantiation 函数代码如下所示。
@Override
1. MathCalculator ,放行跳转到 MathCalculator
1.判断是否包含在增强adviseBeans 中
if (this.advisedBeans.containsKey(cacheKey)) {
2.判断 2个函数判断
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
2.1 isInfrastructureClass 判断是不是 Advice、 Pointcut、Adviso r、AopInfras tructureBean 类型
protected boolean isInfrastructureClass(Class<?> beanClass) {
以及 判断是否是切面(@Aspect)
@Override
isAs pect 函数,判断具体是否巨有Aspect.class 这个注解
@Override
2.2 shouldSkip 判断是否应该跳过,获取到所有 Advisor 判断是否实现
AspectJPointcutAdvisor 判断是否跳过
@Override
可以断点看到当前,并不是 AspectJPointcutAdvisor 所以直接返回null
接下来会调用 new方法创建实例
3.然后创建完成后调用postProcessAfterInitialization函数
/**
看到 wrapIfNecessary 函数,如下
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
3.1在wrapIfNecessary函数 中,判断targetSourcedBeans 列表里面是否,创建过当前Bean
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
3.2 判断修饰过的advisedBeans是否包含
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
3.3与上面2.1 和2.2相同 判断是否代理,是否跳过
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
3.4接下来判断过后调用getAdvicesAndAdvisorsForBean函数中的findEligibleAdvisors 找到所有的能用的通知方法并进行排序
@Override
3.5 将当前Bean 放入advisedBeans 中表示已经被增强处理过并且通过createProxy 获得代理对象 并返回
if (specificInterceptors != DO_NOT_PROXY) {
通过代理工厂创建代码如下
protected Object createProxy(
可以看到有CglibAopProxy 和 ObjenesisCglibAopProxy ,然后在容器获取对象时,将会进行返回代理对象。这就是postProcessBeforeInstantiation 具体作用
3.目标方法div执行流程一:获取拦截器链
对容器获取到的对象,添加断点,查看div 目标方法的执行流程
可以看到如下图,所示,mathCalculator 对象是经过Cglib 代理后的对象
1.进入方法可以看到进入CglibAopProxy.intercept() 方法进行代理拦截,代码如下
@Override
2.其核心是通过getInterceptorsAndDynamicInterceptionAdvice函数,获取拦截器列表,判断列表是否为空来进行不同的操作
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
3.进入获取拦截器列表的函数
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
4.看到getInterceptorsAndDynamicInterceptionAdvice函数,registry.getInterceptors(advisor);遍历所有的增强器,返回interceptorList
@Override
5.核心在于registry.getInterceptors(advisor); 将增强器转为List
@Override
4.目标方法div执行流程二:拦截器链的调用流程分析
运行完成后,将获得拦截器如下所示,有5个:1个默认的4个自定义的增强方法
拦截器不为空,将会运行CglibMethodInvocation.proceed()方法
else {
可以看到具体的process()函数代码如下
@Override
1.如果没有拦截器执行执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)执行目标方法;
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
2.接着获取第0个Advice :org.springframework.aop.interceptor.ExposeInvocationInterceptor执行
else {
3.查看invoke()的代码如下,重复调用到这个mi.proceed() 使得取下一个拦截器,进行操作
流程如图所示:
4.再次调用proceed(),运行到AspectJAfterThrowingAdvice第二个拦截器:同样是调用invoke(this)
@Override
流程如图所示:
5.再次调用proceed(),运行到AfterReturningAdviceInterceptor第三个拦截器:同样是调用invoke(this)
@Override
流程图如下:
6.再次调用proceed(),运行到AspectJAfterAdvice第四个拦截器:同样是调用invoke(this),但是此处进行了finally ,无论如何都会运行advice的函数。
@Override
流程图如下:
7.再次调用proceed(),运行到MethodBeforeAdviceInterceptor第五个拦截器:同样是调用invoke(this),但是此处进行了finally ,无论如何都会运行advice的before函数调用前置通知、以及目标函数。
@Override
流程图如下:
8.再次运行proceed()函数检测到是最后一个拦截器,并且进行出栈操作。往上返回到上一级,由于第6步的proceed()方法返回就会触发finnaly 的函数进行 调用后置通知,流程图如下:
9.在第5步,可以看到代码,没有问题才会调用afterReturn 函数完成的回调,所以第6步发生异常直接跳到第4步的,捕获异常并且调用异常的回调方法。流程图如下:
5.AOP 总结
1)、 @EnableAspectJAutoProxy 开启AOP功能
2)、@EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
3)、AnnotationAwareAspectJAutoProxyCreator是一个后置处理器;
4)、容器的创建流程:
1)、 registerBeanPostProcessors()注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象
2)、 finishBeanFactoryInitialization()初始化剩下的单实例bean
1)、创建业务逻辑组件和切面组件
2)、AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
3)、组件创建完之后, 判断组件是否需要增强
是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib);
5)、执行目标方法:
1)、代理对象执行目标方法
2)、CglibAopProxy.intercept();
1)、得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
2)、利用拦截器的链式机制,依次进入每一个拦截器进行执行;
3)、效果:
正常执行:前置通知-》目标方法-》后置通知-》返回通知
出现异常:前置通知-》目标方法-》后置通知-》异常通知
-END-
可以关注我的公众号,免费获取价值1980元****学习资料
点击“在看”,学多少都不会忘~
本文分享自微信公众号 - 阿聪的全栈之路(gh_ffab7c84fb0c)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。