1.基于注解,首先我们是通过@EnableAspectJAutoProxy()这个注解开起AOP功能,这个注解会导入AspectJAutoProxyRegistrar组件从而将AnnotationAwareAspectJAutoProxyCreator注册到bean定义中。

2.如果容器有对应名字的bean定义,判断下是不是这个class,如果不是就改成AnnotationAwareAspectJAutoProxyCreator,如果没有就直接注册进去,注册bean定义名字叫org.springframework.aop.config.internalAutoProxyCreator。

3.AnnotationAwareAspectJAutoProxyCreator看来这个类是比较重要的了,我们看一下它的继承关系图,可以看到这个类扩展了那些接口,可以看到他是BeanPostProcessor的实现类

4.现在就直接来看之前在bean的实例化过程中第五点提到的org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation这个方法中是寻找切面的过程。这个方法中其实就是去调用我们相应处理器的before和after方法

在applyBeanPostProcessorsBeforeInstantiation方法中我们看到其实会去调用InstantiationAwareBeanPostProcessor这个接口的postProcessBeforeInstantiation这个方法。从我们上面类图中可以看到。我们通过@EnableAspectJAutoProxy注解注册进去的AnnotationAwareAspectJAutoProxyCreator这个正是InstantiationAwareBeanPostProcessor这个的实现类,所以在这里必然会去调用AnnotationAwareAspectJAutoProxyCreator这个实现,但是这里使用了模板方法的设计模式,实际上的方法实现在其父类AbstractAutoProxyCreator这个中的方法。

5.在AbstractAutoProxyCreator类的postProcessBeforeInstantiation方法中会去判断当前创建的类是否是基础类,是否跳过设置,正是shouldSkip这个方法将切面找出来。

6.shouldSkip中会先调用父类的findCandidateAdvisors找事务切面,再调用自己的builder找其他的切面。

7.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans中会获取到所的bean,循环判断是否是切面类,也就是是否标注了@Aspect注解的,再获取切面类中的增强器,也就是@After,@Before,@AfterReturning,@AfterThrowing,@Around这几个。找到了之后再加入到缓存中。

8.后面的类再进来就直接缓存里面拿出来就行了,不需要再去寻找切面了

9.接下来就是在在bean创建好之后会通过bean的后置处理器创建代理对象返回,并且在代理对象中织入我们的增强器。

10.现在来看AbstractAutoProxyCreator#postProcessAfterInitialization这个方法中的一些逻辑,从缓存中拿到我们之前的找到的增强器信息,并且找到匹配当前类的增强器。

11.找到之后又有一步排序的操作,这个就决定了我们增强器的执行顺序。找到了增强器说明需要生成代理,没有增强器就不需要代理。

12.如果需要创代理对象,则判断我们代理分方式@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true),第一个参数是是否暴露我们代理对象,如果暴露了可以当前原型类中通过AopContext.currentProxy(),获取到代理对象。如下图两种调用方式:一种会被切,一种不会

第二个参数是是否强制只用cglib代理。

判断是何种代理

13.可以看到返回的代理对象里面是有我们的增强器信息的。

至此切面寻找,代理对象创建,增强器织入都完成了,接下来就是我们执行目标方法的时候,这些增强器是如何执行的。

14.代理对象调用方法的时候会将增强器转换成拦截器链,就是根据上说到的排序顺序。

如下图:

15.然后创建一个反射方法的执行器执行proceed()方法 进行一个递归的调用,这里的调用有点绕,初始下标-1,然后通过前++的方式从拦截器链中获取出来执行,当最后都取完了的时候才执行目标方法,通过断点调试会发现调用顺序如下图:

因为是递归的调用所以最先执行结束却是54321的顺序,这就是为什么@Before是在方法执行之前执行,可以看到@AfterThrowing是在try-catch中执行的增强器方法。@After是在一个try-finally中执行的,所以这个始终会被执行。

这就是整个Spirng整个AOP的流程。

Spring aop(1)--- 寻找切面和代理对象执行流程源码分析的更多相关文章

  1. Spring Boot的自动配置原理及启动流程源码分析

    概述 Spring Boot 应用目前应该是 Java 中用得最多的框架了吧.其中 Spring Boot 最具特点之一就是自动配置,基于Spring Boot 的自动配置,我们可以很快集成某个模块, ...

  2. Spring Cloud学习 之 Spring Cloud Ribbon(执行流程源码分析)

    Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 文章目录 分析: 总结: 分析: ​ 在上篇文章中,我们着重分析了RestTempla ...

  3. Spring -- aop(面向切面编程),前置&后置&环绕&抛异常通知,引入通知,自动代理

    1.概要 aop:面向方面编程.不改变源代码,还为类增加新的功能.(代理) 切面:实现的交叉功能. 通知:切面的实际实现(通知要做什么,怎么做). 连接点:应用程序执行过程期间,可以插入切面的地点. ...

  4. spring AOP AspectJ 定义切面实现拦截

    总结记录一下AOP常用的应用场景及使用方式,如有错误,请留言. 1.  讲AOP之前,先来总结web项目的几种拦截方式    A:  过滤器 使用过滤器可以过滤URL请求,以及请求和响应的信息,但是过 ...

  5. Spring AOP系列(一)— 代理模式

    Spring AOP系列(一)- 代理模式 AOP(Aspect Oriented Programming)并没有创造或使用新的技术,其底层就是基于代理模式实现.因此我们先来学习一下代理模式. 基本概 ...

  6. Spring加载流程源码分析03【refresh】

      前面两篇文章分析了super(this)和setConfigLocations(configLocations)的源代码,本文来分析下refresh的源码, Spring加载流程源码分析01[su ...

  7. 转:Spring与Mybatis整合的MapperScannerConfigurer处理过程源码分析

    原文地址:Spring与Mybatis整合的MapperScannerConfigurer处理过程源码分析 前言 本文将分析mybatis与spring整合的MapperScannerConfigur ...

  8. Java的三种代理模式&完整源码分析

    Java的三种代理模式&完整源码分析 参考资料: 博客园-Java的三种代理模式 简书-JDK动态代理-超详细源码分析 [博客园-WeakCache缓存的实现机制](https://www.c ...

  9. spring boot 加载web容器tomcat流程源码分析

    spring boot 加载web容器tomcat流程源码分析 我本地的springboot版本是2.5.1,后面的分析都是基于这个版本 <parent> <groupId>o ...

随机推荐

  1. ansible批量部署(一)

    自动化运维工具shell脚本/Ansible(无客户端)/Saltstack(master-minion) 回顾服务器部署的流程:买云主机->环境部署->软件部署->配置部署-> ...

  2. python基础——认识(if __name__ == ‘__main__’:)

    我们在写代码时,经常会用到这一句:if __name__ == '__main__',那么加这一句有什么用呢?实际上,它起到到了一个代码保护功能,它能够让别人在导入你写的模块情况下,无法看到和运行if ...

  3. bzoj1076 奖励关(概率dp)(状态压缩)

    BZOJ 1076 [SCOI2008]奖励关 Description 你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关.在这个奖励关里,系统将依次随机抛出k次宝物,每次你都可以选择吃或者不吃(必须 ...

  4. java成神之路

    一.基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http://www.jcp.org/en/jsr/detail?id=133 http://i ...

  5. springboot整合mybatis报错:Invalid default: public abstract java.lang.Class org.mybatis.spring.annotation...

    <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis- ...

  6. Qt uchar * 转 QImage

    QImage(uchar * data, int width, int height, Format format) QImage(const uchar * data, int width, int ...

  7. Office Lens:口袋中的扫描仪

    Lens:口袋中的扫描仪" title="Office Lens:口袋中的扫描仪"> 编者按:开会时,你是否觉得白板上天马行空的讨论记录誊抄起来费时费事又难以共享- ...

  8. Spring中Bean的不同配置方式

    Bean的配置方式一共分为三种: 1.基于XML(适用于第三方类库,无法在类中写注解以及写命名空间的配置等情况) 2.基于注解(适用于大部分情况) 3.基于Java类 以下是三种不同情况的配置方式   ...

  9. verilog乘法器的设计

    在verilog编程中,常数与寄存器变量的乘法综合出来的电路不同于寄存器变量乘以寄存器变量的综合电路.知乎里的解释非常好https://www.zhihu.com/question/45554104, ...

  10. generate的使用verilog

    根据项目设计的需要,要实例化多个类似的模块,这些类似的模块包括方波波形发生器,这几个模块基本相同,除了参数传递值不同,其他他部分都是相同的 具体实现代码如下: 此外有计数模块的例化,这个模块例化多个的 ...