Spring Boot「46」扩展:创建 Bean 的过程
在讨论 Spring 时使用的 Bean 指的是托管在 Spring 容器(或称 IoC 容器)中的 Java 类对象。 Bean 的作用范围分为 Singleton、Prototype 两种(spring-web 又增加了 request\session 等)。 默认情况下,Bean 的作用范围是 Singleton。 在 IoC 容器启动时,默认会创建、初始化 Singleton Bean,这个过程被称之为 “eager registration of singletons”。 Spring 创建 Singleton Bean 的过程可以分为三个阶段:
- 实例化阶段,AbstractAutowireCapableBeanFactory#createBeanInstance,这个阶段会调用构造器、工厂方法等来完成 Bean 的实例化。
- 属性设置阶段,AbstractAutowireCapableBeanFactory#populateBean,这个阶段会设置依赖。
- 初始化阶段,AbstractAutowireCapableBeanFactory#initializeBean,如果设置了 Bean 实例的初始化方法,会在这个阶段调用。
接下来,我将逐个分析上述三个阶段,并与大家一块研究下 Spring 中每个过程的实现源码。
01-createBeanInstance
首先,创建 Bean 的过程在 AbstractAutowireCapableBeanFactory#createBeanInstance 方法中实现。 它的主要作用是对 Singleton Bean 进行实例化,例如通过调用类的构造器、工厂方法等。 实例化后的 Bean 通过一个包装类 BeanWrapper 对象返回。 下面,我们来看下这部分的源码实现:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
/**
* 一般来说,这里得到的就是要创建的 Bean 的类型,或者是它的工厂类类型
*/
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
/**
* 如果有 supplier,则使用 supplier 获得实例
*/
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
/**
* 根据工厂类、工厂方法获得实例
* 最终交由 ConstructorResolver#instantiateUsingFactoryMethod 方法实现
*/
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
/**
* 如果前面两种方式都没能创建实例,则需要根据要创建 Bean 的构造器来实例化
* args 是要使用的构造器参数
* 如果 args == null,说明要使用默认够构造器
*/
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
/**
* 对构造方法中需要自动注入的进行处理
* 最终交由 ConstructorResolver#autowireConstructor 处理
*/
return autowireConstructor(beanName, mbd, null, null);
}
else {
/**
* 使用默认够构造器
* 根据实例化策略(SimpleInstantiationStrategy 或 CglibSubclassingInstantiationStrategy)来创建实例
* 然后返回 BeanWrapper 对象
*/
return instantiateBean(beanName, mbd);
}
}
/**
* 这里应对的是 args != null 的情况
* 与前面一样,也是分为两种情况考虑:
* 1. 对于需要 autowiring 的情况,由 ConstructorResolver#autowireConstructor 处理
* 2. 其他情况,直接调用构造器创建对象
*/
// Candidate constructors for autowiring?
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
}
在上述源码实现中,有几点需要特别注意:
- Supplier 是 Java 1.8 版本之后提供的函数式接口,它只定义了一个 get 方法,用来获取结果。 在 AbstractBeanDefinition 中定义了一个 instanceSupplier,通过这个回调,能够创建特定 Bean 的实例。 需要特别提醒的是,通过 instanceSupplier 创建 Bean 实例是从 Spring 5.0 开始支持的功能。 而且,它的优先级要高于构造器、工厂方法。
- 如果没有提供 Supplier,则会尝试通过工厂类、工厂方法或类构造器来创建 Bean 实例。
针对使用无参构造器的情况,直接根据实例化策略(例如基于 CGLIB),创建实例
BeanUtils#instantiateClass
->Constructor#newInstance
。 针对使用工厂类、工厂方法或带参构造器的情况,由 Spring 内部的一个辅助类 ConstructorResolver 来实现。- instantiateUsingFactoryMethod,通过工厂方法来实例化类。工厂方法可能是静态类方法,也可能是工厂类对象。
- autowireConstructor,从容器中自动装配对应的构造器参数。
完成实例化后,Spring 会对 Bean (BeanWrapper) 实例进行属性填充。 这部分代码在 AbstractAutowireCapableBeanFactory#populateBean 中实现。 接下来,让我们一起学习下这部分源码。
02-populateBean
AbstractAutowireCapableBeanFactory#populateBean 方法的主要作用是,根据 BeanDefinition 中的属性值来设置(填充)BeanWrapper 中的 Bean 实例:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
/**
* 当使用 XML 文件作为配置文件时,<bean> 标签中的 <property> 中的内容,会设置到 BeanDefinition 的 PropertyValues 中
* 当使用 @Configuration 类文件作为配置时,pvs 一般是空值
*/
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
/**
* 这里的代码主要是检查 bw 中的引用类型(即依赖的其他 Bean)
* 并且,从容器中获取(容器中不存在时会触发创建)这些 Bean,设置到 newPvs 中
* 最终,applyPropertyValues 中,根据 newPvs 的值,设置 bw 中的属性值
* 根据使用自动注入类型不同,区分为按类型注入、按 Bean 名称注入两种方式
* 需要注意的是,这里并不会真正的修改 bw 中 Bean 的属性值
*/
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
/**
* 根据 bean name 注入依赖,后面会讲到
*/
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
/**
* 与根据 bean name 注入类似
*/
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
/**
* 这里会回调 InstantiationAwareBeanPostProcessor 中的 postProcessProperties
*/
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
/**
* 当使用 AnnotationConfigApplicationContext 时,一个关键的 InstantiationAwareBeanPostProcessor 实现是 AutowiredAnnotationBeanPostProcessor
* 后者会处理 bw 包装的 Bean 类型中的 @Autowired、@Value、@Inject 注解的 Field、Method,并收集到 InjectionMetadata
* 之后,会调用 InjectionMetadata#inject,完成依赖对象(值、其他 Bean)的注入
*/
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
/**
* 从 5.1 版本起被废弃,推荐使用同接口中的 postProcessProperties
*/
pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
/**
* 执行依赖检查,确认是否所有的属性(除那些被特别排除的外)都被设置
* 若有未设置的,会抛异常 UnsatisfiedDependencyException
*/
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
/**
* 这里把 pvs 中的值设置到 bw 中的 Bean 实例中
*/
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
上述源码实现中,有几点需要特别注意:
- autowireByName 方法,它的源码如下。它会遍历所有未满足的属性,然后尝试从容器中获取这些引用,因此会出发其他 Bean 的加载。
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
// 容器中有特定的 Bean
if (containsBean(propertyName)) {
Object bean = getBean(propertyName);
// 获取(可能会出发 Bean 创建)对应 Bean,然后放入 pvs 中,等待后续真正设置到 bean 中属性里
pvs.add(propertyName, bean);
registerDependentBean(propertyName, beanName);
}
else {
}
}
这里的 unsatisfiedNonSimpleProperties 方法,会从 bw 中获取内部 bean 实例的所有未满足的、非简单类型(简单类型指基本类型、enum 等)的属性值。 例如:
public class Person {
private String name;
private String sex;
// 省略 getter\setter
}
它对应的 unsatisfiedNonSimpleProperties 方法放回值就包括 name、sex、class 等。 需要特别注意的是,如果没有 getter 和 setter 方法,这个属性不会出现在返回值列表中。 2. 在 Spring 中,有很多形如 xxxPostProcessors 的接口定义。 这是 Spring 提供的一种生命周期回调机制,允许使用者通过提供 xxxPostProcessor 具体实现的方式,参与到 Spring 的流程中,来实现特定的处理逻辑。 我个人也认为这是一种非常灵活的定制化机制,在开发自己的系统时,可以借鉴、参考 Spring 的这种方式。
当所有必须的属性填充完毕后,Bean 实例已经算是可用的了。 但是,对于一些比较复杂的 Bean,可能需要执行一些初始化步骤,才能真正对外提供服务。 Spring 会在下一个阶段,调用 Bean 的初始化方法。
03-initializeBean
调用 Bean 的初始化方法在 AbstractAutowireCapableBeanFactory#initializeBean 中实现。
/**
* bean 就是前面两步创建好的 Bean 实例
*/
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
/**
* 如果 Bean 实现了 Aware 接口,调用它们定义的方法:
* 1. BeanNameAware#setBeanName
* 2. BeanClassLoaderAware#setBeanClassLoader
* 3. BeanFactoryAware#setBeanFactory
*/
invokeAwareMethods(beanName, bean);
/**
* 对于应用程序定义的 Bean,调用 BeanPostProcessor#postProcessBeforeInitialization 方法
* 这个方法就是常被提到的 Bean 生命周期回调之一
* 这里用到的也是前面提到的 PostProcessor 模式
*/
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) { // synthetic 指不是由应用本身定义的,例如由容器定义的
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
/**
* 调用 Bean 的初始化方法
* 对于 XML 配置文件来说,就是 <bean> 标签中指定的 init-method 方法
* 对于 Java 类配置来说,@Bean 注解中的 initMethod 指定的方法
* 对于实现了 InitializingBean 接口的 Bean 来说,调用 afterPropertiesSet 方法
*
*/
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) { }
/**
* 对于应用程序定义的 Bean,调用 BeanPostProcessor#applyBeanPostProcessorsAfterInitialization 方法
* 这个方法就是常被提到的 Bean 生命周期回调之一
*/
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
到这里为止,Spring 创建 Bean 的过程基本就结束了。 希望通过前面的分析,能帮助你理解 Spring 的工作流程。如果有任何疑问,欢迎同我交流。
转载自:https://juejin.cn/post/7221461552343056444