在《Spring创建BeanDefinition之路径扫描》《Spring中@Component和@Bean的底层逻辑》中,我们已了解了如何创建BeanDefinition。现在,我们一起来看看Bean的创建过程。
本文中源码来自Spring 5.3.x分支,github源码地址:github.com/spring-proj…
当我们创建了ApplicationContext对象后,就可以从中获取指定的Bean对象了。来看一个示例:
package com.xiakexing.service;
import org.springframework.stereotype.Component;
@Component
public class UserService {
public void test() {
System.out.println("hello spring");
}
}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean("userService", UserService.class);
userService.test();
在执行context.getBean("userService", UserService.class)前,容器中已经存在userService对象了。该对象是什么时候创建的呢?
一 引入
在创建AnnotationConfigApplicationContext对象时,会调用refresh(),其中会实例化所有非懒加载单例Bean。
最终会调用DefaultListableBeanFactory#preInstantiateSingletons:
- 首先遍历所有的BeanDefinition对象,根据它来创建Bean对象;
- 当所有单例Bean都被创建后,执行SmartInitializingSingleton回调。
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
// merge 父子BeanDefinition,属性复写
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// BeanDefinition可以是抽象的
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 创建工厂bean
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
} else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
// 立即创建FactoryBean管理的bean
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 创建普通Bean
getBean(beanName);
}
}
}
// 执行SmartInitializingSingleton回调
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
} else {
smartSingleton.afterSingletonsInstantiated();
}
smartInitialize.end();
}
}
}
二 准备实例化
2.1 合并BeanDefinition
Spring中支持父子BeanDefinition,和Java父子类相似。子BeanDefinition可以继承父BeanDefinition的属性值,也可以进行复写。
比如,child的scope默认是singleton,因此是单例Bean。
<bean id="father" class="com.zhouyu.service.Father" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child"/>
当指定child的parent属性时,child就和father一样,变成原型Bean了,它从父BeanDefinition中继承了自己未定义的scope属性指。
<bean id="father" class="com.zhouyu.service.Father" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child" parent="father"/>
因此,Spring在创建Bean对象之前,需要进行父子BeanDefinition合并,保证属性完整。
合并后的BeanDefinition会保存到AbstractBeanFactory#mergedBeanDefinitions中(Map结构):
其实,父子BeanDefinition实际应用的很少。
当合并后的BeanDefinition,不是Abstract的、单例的且非懒加载的,才会进行Bean实例化。
2.2 区分工厂Bean和普通Bean
对于普通Bean,调用构造器创建即可。但是,对于FactoryBean接口实现,除了创建工厂Bean对象外,还要创建它所管理的Bean。
- 首先判断当前BeanDefinition是不是FactoryBean的。此时会加载Class文件到JVM中,根据class对象来判断。
注意,起初在BeanDefinition对象中,BeanDefinition的beanClass属性存储的是当前类的全类名,而不是class对象。
- 如果当前BeanDefinition是FactoryBean接口的实现,给beanName加前缀&,尝试从单例池中获取工厂bean对象,没有则创建;
- 如果工厂Bean是SmartFactoryBean接口的实现,且isEagerInit()返回true,则表示要立即创建FactoryBean管理的bean,则会调用getBean(beanName),将结果缓存到factoryBeanObjectCache中(Map结构)。
2.3 处理@dependsOn
创建Bean的逻辑在AbstractBeanFactory#doGetBean中。
- 先将入参name转为标准的beanName,主要是将别名转为真正的beanName;
- 尝试从当前容器中获取Bean对象,如果没有,则尝试从父容器中获取;如果都没有,进入创建环节;
- 根据合并后的BeanDefinition,判断@dependsOn是否会引起循环依赖,存在循环依赖则报错。
- 如果没有循环依赖,则注册Bean的依赖关系到Map中;
- 先创建所依赖的所有Bean对象;最后再创建当前Bean。
三 创建Bean对象
已创建的单例Bean,会被缓存到单例池singletonObjects(Map结构)中。
在DefaultSingletonBeanRegistry#getSingleton()方法中,当用beanName从单例池中获取不到Bean时,就使用入参ObjectFactory创建Bean,并在添加到单例池中。
3.1 实例化前
首先,加载BeanDefinition对应的Class,创建class对象,并赋值给BeanDefinition.beanClass属性。
Spring提供了一个扩展点,在实例化对象之前,允许执行用户的自定义动作:InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()。
当postProcessBeforeInstantiation()有返回值时,表示我们自行完成了实例化,不需要Spring介入;那么依赖注入、初始化前、初始化都不会执行,直接到初始化后阶段。
3.2 实例化
在AbstractAutowireCapableBeanFactory#createBeanInstance中,
-
如果BeanDefinition.instanceSupplier有值, 则调用Supplier.get()创建对象;
-
如果BeanDefinition.factoryMethodName有值,说明是用@Bean定义的,调用method.invoke();
- factoryBeanName有值,说明是工厂方法;
- factoryBeanName无值,说明是静态工厂方法;
-
否则,对于@Component等定义的Bean,推断出合适的构造方法(当类中有多个构造器时),反射创建Bean。
3.3 实例化后
Bean对象实例化后、属性赋值之前,spring又提供了一个扩展点:
MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition(),用于修改合并后BeanDefinition。
它有个默认实现AutowiredAnnotationBeanPostProcessor,用于寻找@Autowired注解的注入点,并缓存在AutowiredAnnotationBeanPostProcessor.injectionMetadataCache(Map结构)中。
还会执行InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(),用于在设置属性之前修改bean的状态(即属性)。
3.4 自动注入
执行InstantiationAwareBeanPostProcessor.postProcessProperties(),处理@Autowired、@Resource、@Value等注解,实现依赖自动注入。(我们之后在细看)
3.5 执行Aware回调
完成属性赋值后,在AbstractAutowireCapableBeanFactory#invokeAwareMethodsSpring中,Spring会执行一些回调,包括:
- BeanNameAware:回传beanName给bean对象。
- BeanClassLoaderAware:回传classLoader给bean对象。
- BeanFactoryAware:回传beanFactory给对象。
3.6 初始化前
即遍历所有BeanPostProcessor实现,执行postProcessBeforeInitialization方法。
源码中有两个实现:
-
ApplicationContextAwareProcessor:进行其他Aware回调,包括
- EnvironmentAware:回传环境变量
- EmbeddedValueResolverAware:回传占位符解析器
- ResourceLoaderAware:回传资源加载器
- ApplicationEventPublisherAware:回传事件发布器
- MessageSourceAware:回传国际化资源
- ApplicationStartupAware:回传应用监听对象,可忽略
- ApplicationContextAware:回传Spring容器ApplicationContext
-
InitDestroyAnnotationBeanPostProcessor,执行@PostConstruct标注的方法。
3.7 初始化
执行AbstractAutowireCapableBeanFactory#invokeInitMethods,包括两步:
- 查看当前Bean对象是否实现了InitializingBean接口,如果是就调用afterPropertiesSet();
- 执行@Bean指定的init-mothed。
3.8 初始化后
创建Bean的最后一个步骤,Spring提供了一个扩展点:BeanPostProcessor.postProcessAfterInitialization()。
Spring AOP就是在此处实现的,初始化后返回的对象(可能是代理对象)才是最终的Bean。
四 流程图
五 总结
我们手动创建一个Bean时,感觉很简单。而Spring容器创建Bean时,由于提供了多种方式,提供了很多扩展点,需要解决循环依赖,实现自动注入和aop代理,因此过程变得很复杂。
了解源码后,有以下几点需注意:
- 由@dependsOn造成的循环依赖,Spring无法解决,只会报错。
- 由FactoryBean创建的Bean,只会经历初始化后阶段,没有其他阶段,因为Bean的实例化、初始化完全由程序员自行定义了;
- 单例池中会保存FactoryBean对象,而FactoryBean所管理的单例Bean,保存在FactoryBeanRegistrySupport.factoryBeanObjectCache缓存中;
- 自定义Bean实现Aware接口时,复写setXXX方法,在源码中由Spring完成回调;
- 在执行顺序上,@PostConstruct > InitializingBean.afterPropertiesSet > init-mothed;
- Spring AOP在最后阶段——初始化后被实现,一个类被代理后,单例池中只会保存代理类对象。