1.Overview
Ref: https://www.cnblogs.com/thewindkee/p/12873100.html
createBean 过程总之就是
- 获得 BeanDefinition 的信息
- 通过反射创建实例,
- 再注入依赖
- 然后 initializeBean 完成特殊处理,
- 最后放入缓存中。
在整个过程中,留下了许多钩子,我们可以使用 Aware 接口,BeanPostProcessor 去做特殊处理。
Ref: https://pdai.tech/md/spring/spring-x-framework-ioc-source-3.html
如何从 IOC 容器已有的 BeanDefinition 信息,实例化出 Bean 对象;这里还会包括三块重点内容:
- BeanFactory 中 getBean 的主体思路
- Spring 如何解决循环依赖问题
- Spring 中 Bean 的生命周期
BeanFactory 中 getBean 的主体思路
上文中我们知道 BeanFactory 定义了 Bean 容器的规范,其中包含根据 bean 的名字,Class 类型和参数等来得到 bean 实例。
// 根据bean的名字和Class类型等来得到bean实例
Object getBean(String name) throws BeansException;
Object getBean(String name, Class requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
初步的思考
上文我们已经分析了 IoC 初始化的流程,最终的将 Bean 的定义即 BeanDefinition 放到 beanDefinitionMap 中,本质上是一个 ConcurrentHashMap
这样我们初步有了实现 Object getBean(String name) 这个方法的思路:
- 从 beanDefinitionMap 通过 beanName 获得 BeanDefinition
- 从 BeanDefinition 中获得 beanClassName
- 通过反射初始化 beanClassName 的实例 instance
- 构造函数从 BeanDefinition 的 getConstructorArgumentValues () 方法获取
- 属性值从 BeanDefinition 的 getPropertyValues () 方法获取
- 返回 beanName 的实例 instance
由于 BeanDefinition 还有单例的信息,如果是无参构造函数的实例还可以放在一个缓存中,这样下次获取这个单例的实例时只需要从缓存中获取,如果获取不到再通过上述步骤获取。
(PS:如上只是我们初步的思路,而 Spring 还需要考虑各种设计上的问题,比如 beanDefinition 中其它定义,循环依赖等;所以我们来看下 Spring 是如何是如何实现的)
2.getBean 的主体思路
BeanFactory 实现 getBean 方法在 AbstractBeanFactory 中,这个方法重载都是调用 doGetBean 方法进行实现的:
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
throws BeansException {
return doGetBean(name, requiredType, args, false);
}
doGetBean:
// 参数typeCheckOnly:bean实例是否包含一个类型检查
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// 解析bean的真正name,如果bean是工厂类,name前缀会加&,需要去掉
String beanName = transformedBeanName(name);
Object beanInstance;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// 无参单例从缓存中获取
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 如果bean实例还在创建中,则直接抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 如果 bean definition 存在于父的bean工厂中,委派给父Bean工厂获取
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
// 将当前bean实例放入alreadyCreated集合里,标识这个bean准备创建了
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 确保它的依赖也被初始化了.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep); // 初始化它依赖的Bean
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// 创建Bean实例:单例
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
// 真正创建bean的方法
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 创建Bean实例:原型
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 创建Bean实例:根据bean的scope创建
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
这段代码很长,主要看中文注释的方法即可。
- 解析 bean 的真正 name,如果 bean 是工厂类,name 前缀会加 &,需要去掉
- 无参单例先从缓存中尝试获取
- 如果 bean 实例还在创建中,则直接抛出异常
- 如果 bean definition 存在于父的 bean 工厂中,委派给父 Bean 工厂获取
- 标记这个 beanName 的实例正在创建
- 确保它的依赖也被初始化
- 真正创建
/* Cache of early singleton objects: bean name —> bean instance /
private final Map
/* Cache of singleton factories: bean name —> ObjectFactory /
private final Map
- **第一层缓存(singletonObjects)**:单例对象缓存池,已经实例化并且属性赋值,这里的对象是**成熟对象**;
- **第二层缓存(earlySingletonObjects)**:单例对象缓存池,已经实例化但尚未属性赋值,这里的对象是**半成品对象**;
- **第三层缓存(singletonFactories)**: 单例工厂的缓存
获取单例:
```java
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Spring首先从singletonObjects(一级缓存)中尝试获取
Object singletonObject = this.singletonObjects.get(beanName);
// 若是获取不到而且对象在建立中,则尝试从earlySingletonObjects(二级缓存)中获取
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 若是仍是获取不到而且容许从singletonFactories经过getObject获取,
// 则经过singletonFactory.getObject()(三级缓存)获取
singletonObject = singletonFactory.getObject();
// 若是获取到了则将singletonObject放入到earlySingletonObjects,
// 也就是将三级缓存提高到二级缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
补充一些方法和参数:
- isSingletonCurrentlyInCreation():判断当前单例 bean 是否正在建立中,也就是没有初始化完成 (好比 A 的构造器依赖了 B 对象因此得先去建立 B 对象, 或则在 A 的 populateBean 过程当中依赖了 B 对象,得先去建立 B 对象,这时的 A 就是处于建立中的状态。)
- allowEarlyReference :是否容许从 singletonFactories 中经过 getObject 拿到对象
分析 getSingleton () 的整个过程:
- Spring 首先从一级缓存 singletonObjects 中获取。
- 若是获取不到,而且对象正在建立中,就再从二级缓存 earlySingletonObjects 中获取。
- 若是仍是获取不到且容许 singletonFactories 经过 getObject() 获取,就从三级缓存 singletonFactory.getObject() 获取,若是获取到了则从三级缓存移动到了二级缓存。
从上面三级缓存的分析,咱们能够知道,Spring 解决循环依赖的诀窍就在于 singletonFactories 这个三级 cache。这个 cache 的类型是 ObjectFactory,定义以下:
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
在 bean 建立过程当中,有两处比较重要的匿名内部类实现了该接口。一处是 Spring 利用其建立 bean 的时候,另外一处就是:
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}});
此处就是解决循环依赖的关键,这段代码发生在 createBeanInstance 以后,也就是说单例对象此时已经被建立出来的。这个对象已经被生产出来了,虽然还不完美(尚未进行初始化的第二步和第三步),可是已经能被人认出来了(根据对象引用能定位到堆中的对象),因此 Spring 此时将这个对象提早曝光出来让你们认识,让你们使用。
好比 “A 对象 setter 依赖 B 对象,B 对象 setter 依赖 A 对象”,A 首先完成了初始化的第一步,而且将本身提早曝光到 singletonFactories 中,此时进行初始化的第二步,发现本身依赖对象 B,此时就尝试去 get (B),发现 B 尚未被 create,因此走 create 流程,B 在初始化第一步的时候发现本身依赖了对象 A,因而尝试 get (A),尝试一级缓存 singletonObjects (确定没有,由于 A 还没初始化彻底),尝试二级缓存 earlySingletonObjects(也没有),尝试三级缓存 singletonFactories,因为 A 经过 ObjectFactory 将本身提早曝光了,因此 B 可以经过 ObjectFactory.getObject 拿到 A 对象 (半成品),B 拿到 A 对象后顺利完成了初始化阶段一、二、三,彻底初始化以后将本身放入到一级缓存 singletonObjects 中。此时返回 A 中,A 此时能拿到 B 的对象顺利完成本身的初始化阶段二、三,最终 A 也完成了初始化,进去了一级缓存 singletonObjects 中,并且更加幸运的是,因为 B 拿到了 A 的对象引用,因此 B 如今 hold 住的 A 对象完成了初始化。
3.2 为何不能解决非单例属性之外的循环依赖
Spring 为什么不能解决构造器的循环依赖?
构造器注入形成的循环依赖: 也就是 beanB 需要在 beanA 的构造函数中完成初始化,beanA 也需要在 beanB 的构造函数中完成初始化,这种情况的结果就是两个 bean 都不能完成初始化,循环依赖难以解决。
Spring 解决循环依赖主要是依赖三级缓存,但是的在调用构造方法之前还未将其放入三级缓存之中,因此后续的依赖调用构造方法的时候并不能从三级缓存中获取到依赖的 Bean,因此不能解决。
Spring 为什么不能解决 prototype 作用域循环依赖?
这种循环依赖同样无法解决,因为 spring 不会缓存‘prototype’作用域的 bean,而 spring 中循环依赖的解决正是通过缓存来实现的。
Spring 为什么不能解决多例的循环依赖?
多实例 Bean 是每次调用一次 getBean 都会执行一次构造方法并且给属性赋值,根本没有三级缓存,因此不能解决循环依赖。
3.3 其它循环依赖如何解决
4.Bean 的生命周期
Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。
Spring 容器可以管理 singleton 作用域 Bean 的生命周期,在此作用域下,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成,以及何时被销毁。
而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。每次客户端请求 prototype 作用域的 Bean 时,Spring 容器都会创建一个新的实例,并且不会管那些被配置成 prototype 作用域的 Bean 的生命周期。
了解 Spring 生命周期的意义就在于,可以利用 Bean 在其存活期间的指定时刻完成一些相关操作。这种时刻可能有很多,但一般情况下,会在 Bean 被初始化后和被销毁前执行一些相关操作。
生命周期流程
在 Spring 中,Bean 的生命周期是一个很复杂的执行过程,我们可以利用 Spring 提供的方法定制 Bean 的创建过程。
Spring 容器中 Bean 的生命周期流程:
- 如果 BeanFactoryPostProcessor 和 Bean 关联,则调用 postProcessBeanFactory 方法.(即首先尝试从 Bean 工厂中获取 Bean)
- 如果 InstantiationBeanPostProcessor 和 Bean 关联,则调用 postProcessBeforeInitialzation 方法
- 根据配置情况调用 Bean 构造方法实例化 Bean。
- 利用依赖注入完成 Bean 中所有属性值的配置注入。
- 如果 InstantiationBeanPostProcessor 和 Bean 关联,则调用 postProcessAfterInitialization 方法和 postProcessProperties
- 调用 xxxAware 接口 (上图只是给了几个例子)
- 第一类 Aware 接口
- 如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName () 方法传入当前 Bean 的 id 值。
- 如果 Bean 实现了 BeanClassLoaderAware 接口,则 Spring 调用 setBeanClassLoader () 方法传入 classLoader 的引用。
- 如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory () 方法传入当前工厂实例的引用。
- 第二类 Aware 接口
- 如果 Bean 实现了 EnvironmentAware 接口,则 Spring 调用 setEnvironment () 方法传入当前 Environment 实例的引用。
- 如果 Bean 实现了 EmbeddedValueResolverAware 接口,则 Spring 调用 setEmbeddedValueResolver () 方法传入当前 StringValueResolver 实例的引用。
- 如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext () 方法传入当前 ApplicationContext 实例的引用。
- …
- 第一类 Aware 接口
- 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的预初始化方法 postProcessBeforeInitialzation () 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。
- 如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet () 方法。(或者有执行 @PostConstruct 注解的方法)
- 如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。
- 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization ()。此时,Bean 已经可以被应用系统使用了。
- 如果在
中指定了该 Bean 的作用范围为 scope=”singleton”,则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 中指定了该 Bean 的作用范围为 scope=”prototype”,则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。 - 如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory () 方法将 Spring 中的 Bean 销毁;(或者有执行 @PreDestroy 注解的方法)
- 如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。
Bean 的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:(结合上图,需要有如下顶层思维)
- Bean 自身的方法: 这个包括了 Bean 本身调用的方法和通过配置文件中
的 init-method 和 destroy-method 指定的方法 - Bean 级生命周期接口方法: 这个包括了 BeanNameAware、BeanFactoryAware、ApplicationContextAware;当然也包括 InitializingBean 和 DiposableBean 这些接口的方法(可以被 @PostConstruct 和 @PreDestroy 注解替代)
- 容器级生命周期接口方法: 这个包括了 InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为 “后处理器”。
- 工厂后处理器接口方法: 这个包括了 AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer 等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。