Spring容器创建过程
注意:Spring5.3.9,一个启动类,未自定义任何钩子执行的整个流程。如有任何疑问欢迎讨论!
使用全注解开发,Spring在AnnotationConfigApplicationContext的构造函数中调用了三个方法
- 空参构造方法
- register启动类
- refresh容器
空参构造方法——准备工作
空参方法做准备工作
- DefaultListableBeanFactory:默认Bean工厂
关键在Bean工厂,其中包含了bean定义的map集合、bean后置处理器集合等,部分代码如下(包含该类和其父类):
/** Cache of singleton objects: bean name to bean instance. */
/* 一级缓存 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
/* 二级缓存 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
/* 三级缓存 */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** Disposable bean instances: bean name to disposable instance. */
private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
/** BeanPostProcessors to apply. */
private final List<BeanPostProcessor> beanPostProcessors = new BeanPostProcessorCacheAwareList();
- ProtocolResolver、ResourcePatternResolver、DefaultResourceLoader:负责处理资源
- Environment:容器的环境
- AnnotatedBeanDefinitionReader:解析Bean注解
- ConditionEvaluator:解析@Conditional类注解
- BeanNameGenerator:生成bean名
- scopeMetadataResolver:bean的scope相关信息
- ClassPathBeanDefinitionScanner
- List<BeanFactoryProcessor>:工厂处理器集合
- Set<ApplicationListener<?>>:监听器集合
包括但不限于上述,大多见名知义,做的都是一些准备工作。
到这里,beanDefinitionMap中Spring默认添加了几个intenalxxxx用于完成容器的创建。
register——启动类注册
register方法就几行代码,主要的逻辑在AnnotatedBeanDefinitionReader中的doRegisterBean中,该方法对每个启动类做了以下几件事:
- 检查@Conditional注解,是否需要扫描该类
- 获取该类的scope元数据,处理@Primary、@Lazy、ProxyMode等
- 加入到beanDefinitionMap
refresh方法
prepareRefresh
- 更新容器状态
- 个性化属性设置,子类重写initPropertySource,默认空实现
- 检测当前容器环境是否缺少属性值
- 准备好事件监听,事件监听器集合与事件集合
obtainRefreshBeanfactory
- 设置beanFactory状态refreshed为true
- 设置序列化id,支持beanFactory的反序列化,使用到了弱引用
prepareBeanFactory
- 设置Bean的类加载器,使用上下文的类加载器。更多关于Java类加载的内容
- 设置spel表达式解析器
- 设置PropertyEditor(Bean创建时用于操作属性)注册器
- 设置忽略的自动装配接口(XXXXAware)与可直接自动装配的(AppContext、BeanFactory等)
- 添加ApplicationListenerDetector,是一个BeanPostProcessor,处理ApplicationListenerBean,要求事件监听器为单例。
- 注册默认环境Bean(systemProperties、systemEnvironment等)
postProcessBeanFactory
该方法默认空实现,此时beanDefininationMap仍然只有Spring默认的个类(intenalxxx)及我们自己的启动类,已经注入容器的是systemProperties、systemEnvironment等类。重写这个函数可以在工厂初始化后进行自定义修改
invokeBeanFactoryPostProcessor
如果对Spring的各种PostProcessor不够熟悉的话,建议阅Spring PostProcessor
这个函数很长,就是调用所有BeanFactoryProcessor的过程
在这些postProcessor中,其中有一个关键的ConfigurationClassPostProcessor,在org.springframework.context.annotation包下,顾名思义,处理@Configuration注解。
整理一下,目前,beanDefinitionMap中只有Spring默认注入的几个类用于构建容器的类以及我们的启动配置类
下面方法用于扫描beanDefinitionMap中的每个beanDefinition
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
/* 待扫描的配置类 */
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
/* 获取所有beanDefinition */
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
/* 已被当作配置类处理 */
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
/* 无关代码 */
}
/* 判断是否是配置类 */
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
/* 添加为待处理配置类 */
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 未找到配置类
if (configCandidates.isEmpty()) {
return;
}
// 排序,对应@Order等注解
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
...
}
checkConfigurationClassCandidate函数,如下
/* 获取注解元数据 */
AnnotationMetadata metadata;
if (){...}
else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
// Check already loaded Class if present...
// since we possibly can't even load the class file for this Class.
Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
BeanPostProcessor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
EventListenerFactory.class.isAssignableFrom(beanClass)) {
return false;
}
metadata = AnnotationMetadata.introspect(beanClass);
}
else {metadata=...}
/* 注解元数据获取完毕 */
/* 是否是配置类 */
/* @Configuration注解 */
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
/* lite模式和full模式 */
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
/* 记录已被扫描 */
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}
/* 判断完毕 */
// It's a full or lite configuration candidate... Let's determine the order value, if any.
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
到目前我们扫描出了对应的配置类,但还未解析该类,解析过程是由ConfigurationClassParser完成的,主要在其doProcessConfigurationClass方法,代码较长,只截取了部分
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
/* 优先处理内部类 */
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass, filter);
}
// @PropertySource注解
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {...}
}
// 处理 @ComponentScan
...
// Process any @Import annotations
// Process any @ImportResource annotations
// Process individual @Bean methods
// Process default methods on interfaces
// Process superclass, if any
// No superclass -> processing is complete
...
}
具体的实现细节都在ConfigurationClassParser中,可自行阅读。
另外,在org.springframework.context.annotation包下,可以看到很多用于解析注解数据的类,如AnnocationBeanDefinitionReader、ComponentScanAnnotationParser等,CondtionalEvaluator等,可以说这个包主要是负责容器的建立。
此时,所有需要加入到容器中的类全都被扫描加入到了BeanDefinitionMap中,beanFactory的sigletonObjects有默认添加的用于初始化容器的类以及systemProperties等
registerBeanPostProcessors
从beanFactory中获取所有实现BeanPostProcessor接口的类,注册等待后续处理bean,我们自己写的实现BeanPostProcessor接口的类(已在beanDefinitionMap中)在此时被注册。该方法主要逻辑如下:
- 通过beanFactory.getBeanNamesForTyp获取所有BeanPostProcessor,此时它们还未被实例化,只是在beanDefinitionMap中。
- 通过getBean方法获取bean实例,在getBean方法中,因为还未实例化,所以会会进行一系列实例化、初始化流程,这些BeanPostProcessor相较于普通bean被提前初始化完毕。
所以,按照容器的初始化流程来说,BeanFactoryPostProcessor、BeanPostProcessor是无法与我们的普通bean实例交互的,具体来说,在其中Autowire普通的bean会警告或报错。 - 按照是否实现PriorityOrdered、Ordered接口为所有的BeanPostProcessr排序.
- 添加到beanFactory的beanPostProcessor集合中。
初始化消息源——initMessageSource
事件派发器:initApplicationEventMulticaster
初始化事件派发器,关于Spring的事件监听,可以看这Spring 中ApplicationListener
onRefresh
自己写的类目前都在BeanDefinitionMap中,还未进行实例化与属性注入
onfresh函数允许在这个时候做一些事,比如添加bean到beanDefininationMap。
为事件派发器注册监听器:registerListeners
- 注册监听器
- 收集派发器之前发生的事件
我们自己写的ApplicationListener在此时被注册,同样是从beanFactory中取得
finishBeanFactoryInitialization
完成此上下文的 bean 工厂的初始化,初始化所有剩余的单例bean
网上流传的面试问题Spring Bean的生命周期大概说的这个地方,因为此时容器中只有Spring为整个ApplicationContext能正常运行而注入的Bean,我们自己写的仍然只在beanDefinitionMap中,在DefaulListableBeanFactory的preInstantiateSingletons方法中:
/* 这个里面包含了所有的beanDefinition */
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
/* 这个PREFIXX就是&,在上一篇文章中有提到 */
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
...
}else{
/* 尝试从容器中获取 */
getBean(beanName);
}
getBean方法之后一直在beanFactory中进行函数调用,我们重点关注getSingleton方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
- 尝试从singletonObjetcs中获取bean,若为null且当前bean正在创建中,转到2;否则返回null
- 尝试从earlySingletonObjects中获取,
收尾——finishRefresh
- 清资源缓存
- 初始化lifecycleProcessor
- refresh,bean生命周期开始
- 发布初始化完成事件