前言

在上一篇文章提到在AbstractApplicationContext类的refresh方法中,可以通过invokeBeanFactoryPostProcessors方法,修改BeanDefinition对象。

其实在refresh方法中,还有:registerBeanPostProcessors、initMessageSource、initApplicationEventMulticaster、onRefresh、registerListeners、finishBeanFactoryInitialization和finishRefresh方法没有讲。image

registerBeanPostProcessors方法主要是注册BeanPostProcessor对象到Spring容器,后面在Bean初始化前后会用到。这个方法的逻辑非常直观,跟invokeBeanFactoryPostProcessors方法差不多,在这里就不多介绍了。

initMessageSource方法:主要初始化支持国际化用的功能,内容也很简单。initApplicationEventMulticaster方法:主要是初始化广播事件,内容也很简单。onRefresh方法:是一个空方法,给子类重写的。registerListeners方法:主要是注册事件监听器,内容也很简单。

接下来,把我们的目光一起聚集到finishBeanFactoryInitialization方法上来,这个方法初始化单例bean,是我们今天的重头戏。

1 finishBeanFactoryInitialization

通过前面的操作,Spring已经从XML文件中,把bean的相关内容解析到了BeanDefinition对象中,接下来,需要把这些对象真正的实例化。

Spring为了性能考虑,把单例的并且非懒加载的bean,在Spring容器启动的时候,先实例化并且初始化好,保存到缓存中。

这样真正的用户请求来了,Spring可以直接从缓存中获取bean实例,提升整个框架的性能。

我们一起看看finishBeanFactoryInitialization方法是怎么初始化bean的。

protectedvoidfinishBeanFactoryInitialization(ConfigurableListableBeanFactorybeanFactory){
//1初始化类型转换器
if(beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)&&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME,ConversionService.class)){
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME,ConversionService.class));
}


// 2 注册内容解析器,解析内容中的比如:$等
if(!beanFactory.hasEmbeddedValueResolver()){
beanFactory.addEmbeddedValueResolver(strVal->getEnvironment().resolvePlaceholders(strVal));
}


//3实例化并初始化@EnableLoadTimeWeavering或<context:load-time-weaver>标记的类
String[]weaverAwareNames=beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class,false,false);
for(StringweaverAwareName:weaverAwareNames){
getBean(weaverAwareName);
}


//将临时的classLoader设置成null
beanFactory.setTempClassLoader(null);


//马上要进行初始化了,冻结所有的bean
beanFactory.freezeConfiguration();


//初始化单例非懒加载的bean
beanFactory.preInstantiateSingletons();
}

其中preInstantiateSingletons方法,才是真正 初始化单例非懒加载的bean的入口:

image该方法会遍历所有的beanName,获取到对应的BeanDefinition对象,然后判断,如果该BeanDefinition不是抽象的,是单例的,并且不是延迟加载的,则进行下一步处理。

再判断如果该beanName对于的类是FactoryBean类型的,则使用&beanName作为key,调用getBean方法获取对应bean。

如果beanName不是FactoryBean类型的,则直接使用beanName作为key,调用getBean方法获取对应bean。

其实真正实例化并且初始化bean的地方在getBean方法中,我们下一篇重点介绍。

此外,还有两个比较有意思的方法:getMergedLocalBeanDefinition和isFactoryBean。

2 getMergedLocalBeanDefinition

首先getMergedLocalBeanDefinition这个方法的名字,就比较有意思。

为什么不直接取名getBeanDefinition,而取名getMergedLocalBeanDefinition呢?

很显然这个方法,不是简单的通过beanName获取BeanDefinition对象。image先从缓存mergedBeanDefinitions中根据beanName获取BeanDefinition对象,如果能够获取到,则直接返回。

如果缓存中为空,则调用重载的getMergedBeanDefinition方法,将通过beanName获取到的BeanDefinition和beanName合并。

听上去是不是有点懵?

假如有这样的场景:

@Data
publicclassPeople{
privateintage=25;
privateStringname="苏三";
}


@Data
publicclassStudentextendsPeople{
privateintscore=90;
}

这里有People和Student两个类,其中Student类是People类的子类,这样Student就可以将People的所有属性,这里的age和name,继承过来了。

对应到BeanDefinition,需要把父类中的属性合并过来。

imagegetMergedBeanDefinition调用了重载getMergedBeanDefinition方法:image这个方法一上来,就是用synchronized关键字,锁定了mergedBeanDefinitions对象,说白了是为了防止并发的场景下,有多个线程同时执行下面的代码块,导致merge的属性有问题。

由于containingBd是null,所以会先从缓存mergedBeanDefinitions中获取一下,如果缓存中获取到了,则直接返回。

如果缓存中获取不到对象,则判断一下parentName是否为空,如果为空,则判断对象是否为RootBeanDefinition类型,如果是则拷贝BeanDefinition,如果对象不是RootBeanDefinition类型,则创建一个RootBeanDefinition类型的对象。

image如果parentName不为空,则先获取parentBeanName,判断parentBeanName跟当前beanName是否相等,如果不相等,则获取parentBeanName合并后的BeanDefinition。

如果name相等,则获取parentBeanFactory对象,如果该对象是ConfigurableBeanFactory,则获取parentBeanFactory对象的parentBeanName合并后的BeanDefinition。

3 isFactoryBean

再一起看看isFactoryBean方法,这个方法也挺有意思的,它主要是用来判断指定的name,是不是FactoryBean。image先调用transformedBeanName方法,将name转换成beanName,然后调用getSingleton方法,从三级缓存中获取bean实例。

如果从缓存中可以获取到bean实例beanInstance对象,直接判断一下beanInstance对象的类型,是不是FactoryBean,然后直接返回。

如果beanInstance对象为空,则判断如果parentBeanFactory是ConfigurableBeanFactory类型,则调用parentBeanFactory的isFactoryBean方法判断是不是FactoryBean。

如果beanInstance对象为空,并且parentBeanFactory不是ConfigurableBeanFactory类型,则获取合并之后的RootBeanDefinition,调用重载的isFactoryBean方法。image这个方法中,先判断mbd.isFactoryBean是空,则获取该beanName对应的Class对象,最后判断Class对象的类型是不是FactoryBean类型。

为什么Spring这么纠结,要花这么大的力气,去判断当前beanName对象是不是FactoryBean呢?

后面会有一篇专题文章。

4 afterSingletonsInstantiated

最后,回到preInstantiateSingletons方法中,其中有这样一段代码:image说白了,就是遍历所有的beanName,如果bean是单例的,并且实现了SmartInitializingSingleton接口,则会调用它的preInstantiateSingletons方法。

在这个方法中,可以做一些初始化的工作。

我们所知道的在bean中初始化的方法有:

  1. 在方法上使用@PostConstruct注解。
  2. 实现InitializingBean接口,重写afterPropertiesSet方法。

这里告诉大家一种新的方式,实现SmartInitializingSingleton接口,重写preInstantiateSingletons方法。

前面两种方式,Spring是在bean实例化完成,bean的初始化过程当中调用的。

而SmartInitializingSingleton接口这种方式,是在bean初始化完成之后,任然给大家提供了一个初始化的机会。

有些业务场景,通过前面方式初始化数据是有问题的。

关于bean的初始化,后面会有一篇专栏。

好了,今天的内容分享到这里,我们下期再见。

最后修改:2026 年 06 月 05 日
如果觉得我的文章对你有用,请随意赞赏