1、概述
- 本文讲主要概括性讲解下 IOC 和 AOP 流程
- 本文是概括性总结,适合对于IOC和AOP 源码有一定了解的人阅读,用于面试的适合直接回答
2、IOC
beanDefinition
-
简称 BD,是spring 框架中最重要的元素之一
-
spring当中的BeanDefinition就是java当中的Class
-
Class可以用来描述一个类的属性和方法等等其他信息 BeanDefintion可以描述springbean当中的scope、lazy,以及属性和方法等等其他信息
BeanFactory
- 可以理解为再 容器中专门用于管理 bean 的一个组件
生命周期
-
对于 IOC 的分析,简单来说就是对于 spring容器的生命周期分析
-
所有对sprin容器的创建,最终都会走到refresh 方法
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
// 加载最开始的五个类 到 BDM 中 通过 beanDef.add()方法进行添加 五次
// 如图 size = 5
this();
// 将配置类转化成为 BD 并存放到 BDM 中
// 如图 size = 6
register(componentClasses);
refresh();
}
refresh()
@Override
public void refresh() throws BeansException, IllegalStateException {
// 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
synchronized (this.startupShutdownMonitor) {
// 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
1 prepareRefresh();
// 这步比较关键,这步完成后,采用 xml 配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中,
// 解析 xml 配置文件的
2 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
// 这块待会会展开说
3 prepareBeanFactory(beanFactory);
try {
// 【这里需要知道 BeanFactoryPostProcessor 这个知识点,Bean 如果实现了此接口,
// 那么在容器初始化以后,Spring 会负责调用里面的 postProcessBeanFactory 方法。】
// 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化
// 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事
4 postProcessBeanFactory(beanFactory);
// 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法,
//如果 是用 并还在里面完成了 其他一系列类的扫描
5 invokeBeanFactoryPostProcessors(beanFactory);
// 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
// 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化
6 registerBeanPostProcessors(beanFactory);
// 初始化当前 ApplicationContext 的 MessageSource,国际化这里就不展开说了,不然没完没了了
7 initMessageSource();
// 初始化当前 ApplicationContext 的事件广播器,这里也不展开了
8 initApplicationEventMulticaster();
// 从方法名就可以知道,典型的模板方法(钩子方法),
// 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
9 onRefresh();
// 注册事件监听器,监听器需要实现 ApplicationListener 接口。这也不是我们的重点,过
10 registerListeners();
// 重点,重点,重点
// 初始化所有的 singleton beans
//(lazy-init 的除外)
11 finishBeanFactoryInitialization(beanFactory);
// 最后,广播事件,ApplicationContext 初始化完成
finishRefresh();
}
}
总结
-
获取到 BeanFactory,同时注入5个默认的 class,一种最重要的是一个 ConfigurationClassPostPrecessor,用于扫描包,生成 BD 放入BDM
-
执行 BeanFactoryPostProcessors 和 BeanDefinitionRegistryPostProcessor 的方法,这里ConfigurationClassPostPrecessor 会扫描所有应该扫描的包,将所有扫描到的类,编程 BD 放入 BDM 中,(所有实现BeanFactoryPostProcessors 的类再这里都会通过 getBean()创建对象,然后调用方法)
-
注册 registerBeanPostProcessors 扫描所有实现 BeanPostProcessors 的类,将其实例化到容器中,但是并不执行方法(AOP 就是再这里扫描进去的)
- BeanFactory 已经创建完成,并且所有的实现了 BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor接口的 Bean 都已经初始化并且其中的 方法已经得到执行了。 所有 实现了 BeanPostProcessor 接口的 Bean 也都完成了初始化,但是其方法还没有执行。
-
注册事件派发器 和 几个监听器
-
完成所有 bean 对象的实例化,初始化、注入属性、实例化
3、AOP
-
@EnableAspectJAutoProxy注解
-
这注解将会往 IOC 中注入AnnotationAwareAspectJAutoProxyCreator,实现了两个接口
-
BeanPostProcessor:后置处理器,即在bean初始化完成前后做些事情
-
BeanFactoryAware:自动注入BeanFactory
-
-
BeanPostProcessor 方法
-
进行对象的创建,当缓存中不存在时候,采用构造器进行实例化,然后他填充属性,最后初始化,发生再初始化前后
-
首先创建bean的实例 然后给bean的各种属性赋值 接着初始化bean
- 1)先执行Aware接口的方法
- 2)应用后置处理器的postProcessBeforeInitialization()方法
- 3)执行自定义的初始化方法
- 4)应用后置处理器的postProcessAfterInitialization()方法
-
-
细节:每一个 通知方法 都会都会封装成为一个给的 增强器,再 postProcessBeforeInitialization() 方法中,会通过切入点匹配,找到所有的增强器,保存到当前 bean 中,创建代理的方法有两种,一种是 jdk(必须要有接口),一种是 cglib
-
方法执行
-
方法执行的适合,会通过链式调用,给所有的切面排序,形成一个调用链,进行递归调用,当调用链的长度是0 的适合,说明执行自身的方法,而后退出当前递归,继续执行下一个通知方法。
-
4、循环依赖
-
首先介绍下 三级缓存是什么
-
一级缓存: 存放的是完整的对象
-
二级缓存: 存放的是提前曝光的对象(属性还有部分没有注入)
-
三级缓存: 存放的是提前曝光的的工厂
-
-
对象创建的过程
- 实例化,大概就是一个空壳
- 注入属性
- 初始化
-
循环依赖情况下(A需要B,同时B 需要 A,没有AOP)
-
A 实例化结束,放入三级缓存中,开始注入属性B,
-
发现属性B 为实例化,开始实例化B
-
B 发现需要对象A , 从三级缓存中获取 A 的实例,将该实例放到二级缓存中,B 从二级缓存中获取该实例,完成属性注入,完成初始化,将 B 放入一级缓存
-
A 从一级缓存中获取到 B,解决了循环依赖
-
-
循环依赖(A需要B,同时B 需要 A,存在AOP)
-
A 实例化结束,放入三级缓存中,开始注入属性B
-
实例化B,放入三级缓存,开始注入属性 A , 调用 aFctory.getObject(),最后会调用到 getEarlyBanReference 方法,对 A 提前进行一个 AOP 动态代理,放入二级缓存中,一定要记住,这时候 B 填充的是 AOP-A 并不是 A, B 完成属性填充,初始化,放入一级缓存中
-
A 继续完成初始化,发现 A 提前代理过了,不会发生代理,创建完成,返回 A
-
-
提前曝光的bean在提前引用时被Spring AOP代理了,但是此时的bean只是经过了实例化的bean,还没有进行@Autowire的注入啊!也就是说此时代理的bean里面自动注入的属性是空的!
-
答案:是的,确实在
Spring AOP提前代理后没有经过属性填充和初始化。那么这个代理又是如何保证依赖属性的注入的呢?答案回到Spring AOP最早最早讲的JDK动态代理上找,JDK动态代理时,会将目标对象target保存在最后生成的代理$proxy中,当调用$proxy方法时会回调h.invoke,而h.invoke又会回调目标对象target的原始方法。因此,其实在Spring AOP动态代理时,原始bean已经被保存在提前曝光代理中了。而后原始Bean继续完成属性填充和初始化操作。因为AOP代理$proxy中保存着traget也就是是原始bean的引用,因此后续原始bean的完善,也就相当于Spring AOP中的target的完善*,这样就保证了Spring AOP的属性填充与初始化了!
5、ConfigurationClassPostProcessor
- 这个在 ApplicaionContext 构造方法里面主动注入 BDM 的内置后置处理器,而后在 refresh()方法利用会首先进行调用,扫描所有的 bean
- 对整个spring工程进行扫描,解析,然后生成beanDefinition,放到beanDefinitionMap中
- 半配置类和全配置类
- 全配置类 =》 @Configuration =》会生成一个动态代理(cglib)
- 半配置类 -》 @Bean,@Component,@ComponentScan,@Import,@ImportResource这些注解,则为lite