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. \b 是单词边界锚点 word-boundary anchor,一个“\b”匹配一个单词的一端,两个“\b”匹配一个单词的头尾两端

    123 $_ = "beforematcha? fter";    124 if(/\b\w+a\b/){    125     print "matched: < ...

  2. 74cms_3.5.1 宽字节注入

    第一次进行CMS的代码审计,我选择了2014年发布的74CMS 3.5.1,历史比较久远的CMS往往存在更多的问题,虽然技术上难度不大,但是在思路方面给了我很大的启发.下面我根据我的思路给大家分享一下 ...

  3. EXAM-2018-8-3

    EXAM-2018-8-3 D H 喜闻乐见的水题 J lower_bound + upper_bound 一个可以查找第一个大于,另一个可查找第一个不小于. F 找规律+奇偶分析 偶数好找,就是奇数 ...

  4. iOS 仿看了吗应用、指南针测网速等常用工具、自定义弹出视图框架、图片裁剪、内容扩展等源码

    iOS精选源码 扩展内容的cell - folding-cell 一个近乎完整的可识别中国身份证信息的Demo 可自动快速... JPImageresizerView 仿微信的图片裁剪 带年月和至今以 ...

  5. [LC] 124. Binary Tree Maximum Path Sum

    Given a non-empty binary tree, find the maximum path sum. For this problem, a path is defined as any ...

  6. C语言学习笔记之获取文件长度

    本文为原创文章,转载请标明出处 #include <stdio.h> #include <stdlib.h> int main() { FILE *inputFile; inp ...

  7. 吴裕雄--天生自然 R语言开发学习:聚类分析(续一)

    #-------------------------------------------------------# # R in Action (2nd ed): Chapter 16 # # Clu ...

  8. ZOJ 2532 网络流最小割

    求最小割的问题. 题意:已知网络中有n个源点,m的中转站(也就是节点),一个汇点(编号为0).给出网络,求一些边(增大这个边就可以增大汇点流量的边). 思路:一开始代码只找了有流=0就加入输出数组的情 ...

  9. centos7系统盘变为只读文件的修复

    一台物理机的系统盘在磁盘空间有剩余的情况下变为只读了,咨询后发现前几日修改过系统,然后就不可写了,重启也不行.见下图 解决:参考链接https://bbs.51cto.com/thread-92640 ...

  10. python基础修改haproxy配置文件

    1.通过eval(),可以将字符串转为字典类型. 2.Encode过程,是把python对象转换成json对象的一个过程,常用的两个函数是dumps和dump函数.两个函数的唯一区别就是dump把py ...