源码顺序图
Bean的元数据搜集
- 在
**Java对象**
的创建中,只是通过 加载到**方法区的Class对象**
为模板,创建出对应的对象 - 而被
**Spring管理的Bean对象**
中,除了**基础的类信息**
以外,还包括了**对象的元信息**
,例如像**单例还是多例**
@Scope,是否进行**懒加载**
@Lazy,是否**依赖于其他的Bean**
@DependOn - Spring会通过扫描文件的方式,xml、或是@Configuration等获取到相关的Bean的元数据信息
- 在扫描完毕元数据信息后,每个Bean的元数据信息会封装成一个
**BeanDefinition**
对象 - 所有的Bean的
**BeanDefinition**
对象都会封装到**BeanDefinitionMap**
中,key是Bean的名称,value是对应的**BeanDefinition对象**
- 此时
**Bean对象没有被真正创建**
,仅仅是做了元数据的收集工作
BeanFactoryPostProcessor
- 在元数据的收集工作完成后,可以获取到Bean的元数据信息对象
**BeanDefinition**
。 - 此时会对所有的
**BeanDefinition**
进行遍历执行**BeanFactoryPostProcessor**
的方法 - @Value的实现类 就是 BeanFactoryPostProcessor的子类
- 这里的方法可以对
**Bean的元数据信息进行获取或修改操作**
,但是一般不会这样使用
通过反射创建Bean对象
对Bean的属性进行依赖注入
主要的缓存集合
**singletonObjects**
一级缓存,ConcurrentHashMap,在所有对象完成初始化后,最终都会进入到一级缓存中,保存的是bean的名称与bean的关系**earlySingletonObjects**
二级缓存,HashMap,主要用于解决在Bean的生命周期中,需要**生成代理对象的情况**
,存放的是Bean的名称和bean。在流程结束后会从二级缓存中获取到bean,放入一级缓存中**singletonFactories**
三级缓存,HashMap,**用于打破循环**
,存放的是 bean的名称和对应的lambda表达式,**用于判断创建的是 代理对象还是普通对象**
**earlyProxyReferences**
,**AOP组件内的集合**
,如果bean出现循环依赖后,则需要提前创建代理对象并放入二级缓存中,此时会将该bean加入到该集合中,在bean的真正到判断创建代理对象的时候,**通过判断该集合从而判断是否仍然需要创建代理对象**
**singletonsCurrentlyInCreation**
,bean在**创建的过程**
中会**处于在这个集合内**
,保存的是Set集合,Bean的名称,在bean创建的时候会加入这个集合,在bean加载完毕后,则会从这个集合中移除,**用于判断是否存在循环依赖**
。
当Bean A和B相互依赖时的初始化流程
- 调用
**doGetBean(beanA)**
流程,此时会将beanA的名称加入到**singletonsCurrentlyInCreation**
中 - 判断
**singletonObjects**
一级缓存和**earlySingletonObjects**
二级缓存中是否存在该bean,存在则直接返回 - 调用
**addSingletonFactory()**
,会将一个**lambda表达式**
存放到**singletonFactories**
三级缓存中,其中value保存的是一个lambda表达式作用是用于生成原始对象,会根据**判断是否包含**
对应的**BeanPostProcessors**
从而**判断生成的是代理对象还是普通对象**
。此时对象没有进行初始化操作。 - 此时判断到BeanA有依赖注入属性B,此时则会去调用
**doGetBean(beanB)**
流程,BeanB也重复上面123的流程 - 此时判断到BeanB存在依赖注入属性A,此时会先寻找一级缓存中是否存在,然后在
**singletonsCurrentlyInCreation**
判断到BeanA还没有初始化完毕,即**出现了循环依赖**
- 此时会从二级缓存、三级缓存的顺序寻找BeanA对象,然后调用三级缓存中的lambda表达式
**创建出BeanA的基本对象**
,如果BeanA的有动态代理的相关操作,会在此时进行完毕,确保此时BeanB注入的BeanA属性对象是**代理对象**
而不是原始对象 - 在调用lambda函数创建完毕对象后,会将
**BeanA**
加入到**二级缓存**
中,并且会删除**三级缓存**
的内容 - 此时BeanB会继续执行后续的操作,然后放到
**一级缓存**
中,此时**BeanB初始化完成**
- 会到BeanA的初始化流程中,从
**一级缓存**
中获取到**BeanB**
的对象,并且此时BeanB的对象也是已经完成动态代理操作的。 - 在属性注入完毕后,
**earlyProxyReferences**
需要判断是否需要创建动态代理对象,因为此时BeanB的初始化流程中已经生成了BeanA对应的代理对象,此时不需要再创建 - 在初始化创建完毕后,BeanA也会放到单例池中
为什么一定要使用三级缓存
- 在只有二级缓存的情况下,无法处理需要创建代理对象的操作
- 在BeanA中包含BeanB属性时,要注入BeanB对象
**不能只是注入BeanB的基本对象**
,**需要**
注入的是BeanB的**代理对象**
- 但是此时BeanB没有
**走完初始化的流程**
,不能在此时直接创建BeanB的代理对象,因为**不能够创建多个代理对象**
,要保证BeanB的单例 - 因此需要引入现在的
**earlySingletonObjects**
二级缓存用来解决循环依赖中,没有进行完毕初始化流程,但是**需要提前将Bean暴露给其他Bean进行使用**
的情况
Spring可以解决哪些循环依赖
单例Bean
,并且通过@Autowire
等通过setter方法
注入的普通AOP增强Bean
(可以解决循环依赖)
原型模式Bean,不会保存在单例池中,因此无法使用三级缓存(不能解决)
构造方法注入的Bean(不能解决)
- 在通过三级缓存解决循环依赖问题时,需要能够创建初始对象
- 但如果构造方法注入Bean的情况出现循环依赖,此时无法创建出初始对象
- 因此构造方法注入的Bean不能解决
@Async增强的Bean(不能解决)
- 普通的 AOP 代理都是通过
**AbstractAutoProxyCreator**
来生成代理类的,**AbstractAutoProxyCreator**
实现了**SmartInstantiationAwareBeanPostProcessor**
。 - 而 @Async 标记的类是通过
**AbstractAdvisingBeanPostProcessor**
来生成代理的,**AbstractAdvisingBeanPostProcessor**
没有实现**SmartInstantiationAwareBeanPostProcessor**
。 - 因此@Async 的类在发现循环依赖后,不会提前创建代理对象,此时其他的类则无法从二级缓存中获取到代理对象,因此无法解决循环依赖
@Lazy解决循环依赖的原理
@Lazy可以解决哪些循环依赖
- 构造方法的循环依赖
- @Async竹节标记的循环依赖
- 依旧不能解决原型模式的循环依赖
@Lazy如何解决循环依赖
- 在没有@Lazy时,此时会直接寻找依赖的对象,此时因为循环依赖,因此无法找到依赖的对象从而导致出错
- 在有@Lazy时,此时不会去直接寻找依赖的对象,会直接创建一个代理对象,作为构造方法的参数进行传入
- 此时在Bean真正调用该Bean的方法时,实际调用的是对应代理对象的方法,代理对象会先在单例池中寻找该Bean,然后再调用该Bean的对应方法,从而解决循环依赖
Aware相关接口
Aware接口执行顺序
名称 | 用途 | 所属容器 | 回调点 |
---|---|---|---|
BeanNameAware | 获取bean名称 | BeanFactory | Bean后处理器的BeforeInitialization方法之前 |
BeanClassLoaderAware | 获取bean的类加载器 | BeanFactory | Bean后处理器的BeforeInitialization方法之前 |
BeanFactoryAware | 获取bean工厂(建议用下面的ApplicationContextAware) | BeanFactory | Bean后处理器的BeforeInitialization方法之前 |
EnvironmentAware | 获取环境相关信息,如属性、配置信息等 | ApplicationContext | Bean后处理器的BeforeInitialization方法中 |
EmbeddedValueResolverAware | 获取值解析器 | ApplicationContext | Bean后处理器的BeforeInitialization方法中 |
ResourceLoaderAware | 获取资源加载器 | ApplicationContext | Bean后处理器的BeforeInitialization方法中 |
ApplicationEventPublisherAware | 获取事件广播器,发布事件使用 | ApplicationContext | Bean后处理器的BeforeInitialization方法中 |
MessageSourceAware | 获取消息资源 | ApplicationContext | Bean后处理器的BeforeInitialization方法中 |
ApplicationContextAware | 获取ApplicationContext | ApplicationContext | Bean后处理器的BeforeInitialization方法中 |
Aware接口实际运用
- Aware接口的主要作用是可以
**提前获取到相对应的信息**
,如果在某个Bean中需要使用某个对象,只需要让其实现 xxxAware接口,就可以获取到对应的对象 - 在Aware处可以获取到Bean的相关信息,可以进行数据的处理,例如可以对Bean内属性进行赋值操作等。
- 封装
**ApplicationContextHolder**
上下文工具类,在封装的**工具类**
或者是**封装的starter组件**
中,无法直接使用ApplicationContext进行使用,此时则需要封装上下文工具类。
BeanPostProcess前置(postProcessBeforeInitialization)
- 在Aware相关接口执行完毕后,则马上执行BeanPostProcessor的相关方法
- BeanPostProcess是AOP实现的关键
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
初始化方法
**@PostConstruct**
所有对象实例化完成后调用- 继承了
**InitializingBean**
接口 调用afterPropertiesSet()方法 **Init-Method**
@PostConstruct @Bean(init-method=…)
BeanPostProcess后置
正常使用
Disposable的Destory方法
- @PreDestory
- DisposableBean的destory()方法
- 配置的destory-method