AOP入口代码分析

通过注解的方式来实现AOP
1. @EnableAspectJAutoProxy通过@Import注解向容器中注入了AspectJAutoProxyRegistrar这个类,而它在容器中的名字是org.springframework.aop.config.internalAutoProxyCreator。
2. AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,所以可以向容器中注册Bean的定义信息。
3. 通过跟踪AspectJAutoProxyRegistrar,我们发现它向容器中注册了AnnotationAwareAspectJAutoProxyCreator的定义信息。
4. 观察AnnotationAwareAspectJAutoProxyCreator的继承结构图,发现,它既是一个后置处理器,又是一个BeanFactoryAware的实现类。
所以我们可以分析:
一、 AnnotationAwareAspectJAutoProxyCreator作为后置处理器做了什么?
二、 作为Aware做了什么?

继承结构分析

AnnotationAwareAspectJAutoProxyCreator的继承结构图,如下:

AnnotationAwareAspectJAutoProxyCreator
-> extends AspectJAwareAdvisorAutoProxyCreator
-> extends AbstractAdvisorAutoProxyCreator
-> extends AbstractAutoProxyCreator
-> implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
【可见AnnotationAwareAspectJAutoProxyCreator是一个后置处理器,也是一个Aware】 AbstractAutoProxyCreator作为一个抽象类,实现了SmartInstantiationAwareBeanPostProcessor和BeanFactoryAware
故,我们分别在他们的实现方法上加断点,比如:postProcessBeforeInstantiation()和setBeanFactory()

断点调试

首先来到AbstractAutoProxyCreator的setBeanFactory(),查看IDE的调用栈,如图:

1. 传入配置类,创建IOC容器
2. 注册配置类,调用refresh()刷新容器
3. registerBeanPostProcessors(beanFactory)注册Bean的后置处理器,来拦截Bean的创建。
1) 先获取IOC容器已经定义了的需要创建对象的所有BeanPostProcessor
2) 给容器中添加另外其他的BeanPostProcessor
3) 优先注册实现了PriorityOrdered接口的BeanPostProcessor
4) 再注册实现Order接口的BeanPostProcessor
5) 最后注册没实现任何接口的BeanPostProcessor
6) 注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,并保存在容器中
如何创建名字叫internalAutoProxyCreator【AnnotationAwareAspectJAutoProxyCreator】的后置处理器?
1) 先来创建Bean的实例
2) populateBean()给Bean的属性赋值
3) initializeBean()初始化Bean
1) invokeAwareMethods(beanName, bean)处理Aware接口的方法回调
2) applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)
拿到所有的BeanPostProcessor并执行postProcessBeforeInitialization
3) invokeInitMethods(beanName, wrappedBean, mbd)执行自定义的初始化方法,比如init()和destroy()
4) applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)
拿到所有的BeanPostProcessor并执行postProcessAfterInitialization
4) BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】创建成功
7) 把BeanPostProcessor注册并添加到BeanFactory中 ==========以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程==========

AnnotationAwareAspectJAutoProxyCreator作为后置处理器做了什么?

4. finishBeanFactoryInitialization(beanFactory)完成BeanFactory的初始化工作,创建剩下的单实例Bean
1)遍历获取所有的Bean,依次创建对象getBean(beanName)
getBean -> doGetBean() -> getSingleton()
2)如何创建Bean?
【首先说明:上面注册过的后置处理器AnnotationAwareAspectJAutoProxyCreator会在所有Bean创建之前进行拦截调用,因为
AnnotationAwareAspectJAutoProxyCreator实现了InstantiationAwareBeanPostProcessor接口】
1)先从缓存中获取当前Bean,如果能获取到,说明Bean是之前被创建过了的,直接使用,否则再进行创建
只要被创建过的Bean都会被缓存起来
2)createBean()创建Bean的实例,过程如下:
1)resolveBeforeInstantiation(beanName, mbdToUse)这一步是尝试返回Bean的代理对象
希望后置处理器在此能返回一个代理对象,如果不能就调用doCreateBean()创建对象
如何返回代理对象呢?
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
【注意:这里的applyBeanPostProcessorsBeforeInstantiation不同于BeanPostProcessor的postProcessBeforeInitialization】
【applyBeanPostProcessorsBeforeInstantiation和applyBeanPostProcessorsAfterInitialization属于InstantiationAwareBeanPostProcessor的方法
而InstantiationAwareBeanPostProcessor是在创建Bean对象实例之前进行调用,目的是在创建Bean对象之前首先尝试返回代理对象,
但BeanPostProcessor的两个方法则是在Bean对象创建完成,进行初始化的前后才进行调用,他们两个执行的时机不一样BeanPostProcessor的执行稍微晚一点】
2)doCreateBean(beanName, mbdToUse, args)此方法才是真正的创建一个Bean实例,创建实例的流程和上面一样

分析InstantiationAwareBeanPostProcessor的两个方法

AnnotationAwareAspectJAutoProxyCreator实现了InstantiationAwareBeanPostProcessor所以每一个Bean在创建之前,都会经过
postProcessBeforeInstantiation()方法。当然也包括被切的实体。 1. 每个Bean在创建之前都会经过postProcessBeforeInstantiation()过程分析:
1)判断当前Bean是否在advisedBeans(里面保存了需要增强的Bean)中。
this.advisedBeans.containsKey(cacheKey)
2)判断当前Bean是否是基础类型(Advice,Pointcut,Advisor,AopInfrastructureBean)。
isInfrastructureClass(beanClass)
3)是否需要跳过?(好像永远要跳过^_^)
shouldSkip(beanClass, beanName)
这个方法首先获取候选的增强器List<Advisor> candidateAdvisors = findCandidateAdvisors();
每一个Advisor的类型是InstantiationModelAwarePointcutAdvisor,并不是AspectJPointcutAdvisor 2. 经过postProcessBeforeInstantiation()尝试创建对象出来以后,进入AbstractAutoProxyCreator的postProcessAfterInitialization方法
postProcessAfterInitialization方法中有一个wrapIfNecessary(bean, beanName, cacheKey)开始进行包装Bean,点击进入:
1)Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
找到所有的增强器,并获取到能在该Bean使用的增强器,然后顺便排序(目的是为了有序的切入)
2)保存当前Bean到advisedBeans中
this.advisedBeans.put(cacheKey, Boolean.TRUE)
3)如果当前Bean需要增强,就创建当前Bean的代理对象
Object proxy = createProxy(...),如何创建?如下:
1. 获取所有通知方法
2. 保存到proxyFactory中
3. 创建代理对象,Spring自动决定
new JdkDynamicAopProxy(config);实现接口
ObjenesisCglibAopProxy(config);没有实现接口
4)通过以上三步,wrapIfNecessary()方法会返回一个代理Bean并且放到容器中,当调用目标方法的时候,实际上是代理类在调用

Spring源码窥探之:注解方式的AOP原理的更多相关文章

  1. Spring源码 05 IOC 注解方式

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  2. Spring源码 04 IOC XML方式

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  3. Spring源码之@Configuration注解解析

    1.前言 ​ Spring注解开发中,我们只需求要类上加上@Configuration注解,然后在类中的方法上面加上@Bean注解即可完成Spring Bean组件的注册.相较于之前的xml配置文件定 ...

  4. Spring源码窥探之:Spring AOP初步

    AOP(Aspect Oriented Programming):即我们常说的面向切面编程. 什么是AOP?AOP是在我们原来写的代码的基础上,进行一定的包装,比如在方法执行前.方法返回后.方法抛出异 ...

  5. Spring源码窥探之:AOP注解

    AOP也就是我们日常说的@面向切面编程,看概念比较晦涩难懂,难懂的是设计理念,以及这样设计的好处是什么.在Spring的AOP中,常用的几个注解如下:@Aspect,@Before,@After,@A ...

  6. Spring源码解析-基于注解依赖注入

    在spring2.5版本提供了注解的依赖注入功能,可以减少对xml配置. 主要使用的是 AnnotationConfigApplicationContext: 一个注解配置上下文 AutowiredA ...

  7. Spring源码窥探之:@Profile

    Spring为我们提供的多环境启动 1. 配置类,注入三个不同环境的数据源,并加上注解 /** * description: 以下准备了三套不同环境的数据源 * * @author 70KG * @d ...

  8. Spring源码窥探之:声明式事务

    1. 导入驱动,连接池,jdbc和AOP的依赖 <!-- c3p0数据库连接池 --> <dependency> <groupId>c3p0</groupId ...

  9. Spring源码窥探之:Spring AOP初步使用

    AOP即面向切面编程.它的底层实际是用了spring的动态代理,具体是JDK的代理还是CGLIB的代理,就视情况而定了.本博客园仅仅作为平时记录,显得有些杂乱无章,如果想了解动态代理,设计模式,请访问 ...

随机推荐

  1. PHP防止被重复请求接口的方法(网页端签名验证的方法)

    PHP防止被重复请求接口的方法(网页端签名验证的方法) 可以采取签名验证的方式来 解决这个问题 1 time和随机数都是PHP生成的显示在前端 2 前端生成sign 3 进行每次请求的sign计数 这 ...

  2. sizeof(类名字)

    析构函数,跟构造函数这些成员函数,是跟sizeof无关的,因为我们的sizeof是针对实例,而普通成员函数,是针对类体的,一个类的成员函数,多个实例也共用相同的函数指针,所以自然不能归为实例的大小. ...

  3. LeetCode 394. 字符串解码(Decode String) 44

    394. 字符串解码 394. Decode String 题目描述 给定一个经过编码的字符串,返回它解码后的字符串. 编码规则为: k[encoded_string],表示其中方括号内部的 enco ...

  4. kafka 如何保证数据不丢失

    一般我们在用到这种消息中件的时候,肯定会考虑要怎样才能保证数据不丢失,在面试中也会问到相关的问题.但凡遇到这种问题,是指3个方面的数据不丢失,即:producer consumer 端数据不丢失  b ...

  5. 理解SQL Server中索引的概念,原理以及其他(转载)

    简介 在SQL Server中,索引是一种增强式的存在,这意味着,即使没有索引,SQL Server仍然可以实现应有的功能.但索引可以在大多数情况下大大提升查询性能,在OLAP中尤其明显.要完全理解索 ...

  6. [NOIP2016]天天爱跑步-题解

    题面传送门 解答 设第\(j\)号玩家在\(V_j\)时刻出发. 弱化问题:如果树退化成了一条链.则在\(j\)处的观察员能观察到的\(i\)号玩家当且仅当 \[ i玩家经过j,且 \begin{ca ...

  7. C++ Primer第五版(中文带书签)

    本想发github的(链接更稳定),但是大小超出限制了. 本文件为扫描件,还是在我找了大半天之后的结果.能找到的免费的貌似都是扫描件,在看了一百多页之后(我不喜欢文字不能选中的感觉),我果断买了纸质书 ...

  8. 深度学习-InfoGAN论文理解笔记

    在弄清楚InfoGAN之前,可以先理解一下变分推断目的以及在概率论中的应用与ELBO是什么,以及KL散度 https://blog.csdn.net/qy20115549/article/detail ...

  9. Spring整合Hibernate的两种方式

    在使用spring注解整合hibernate时出现"org.hibernate.MappingException: Unknown entity: com.ssh.entry.Product ...

  10. sqlserver通过递归查找所有下级或上级部门和用户的操作实例

    --查找当前用户所在部门的所有下级包括当前部门 with cte as ( as lvl from Department union all from cte c inner join Departm ...