应用上下文(接上)
刷新容器
refresh方法
实例化所有剩余的(非延迟初始化)单例
finishBeanFactoryInitialization(beanFactory);
该方法是整个 Spring Ioc 核心中的核心
该方法会实例化所有剩余的非懒加载单例 bean。除了一些内部的 bean、实现了 BeanFactoryPostProcessor 接口的 bean、实现了 BeanPostProcessor 接口的 bean,其他的非懒加载单例 bean 都会在这个方法中被实例化,并且 BeanPostProcessor 的触发也是在这个方法中。
finishBeanFactoryInitialization(beanFactory); 是 Spring 框架中的一个方法调用,它出现在 Spring 容器初始化过程中的某个阶段。在 Spring 的生命周期中,当 ApplicationContext 被创建和配置时,它负责初始化和管理应用程序中的 beans。
具体来说,finishBeanFactoryInitialization(beanFactory); 方法的主要目的是完成 bean 工厂的初始化,这包括:
- 实例化剩余的 singleton beans:在 Spring 的
ApplicationContext中,beans 可以是原型(prototype)或单例(singleton)。在初始阶段,Spring 可能会预先实例化一些必要的 beans,但在调用finishBeanFactoryInitialization时,它会完成剩余的单例 beans 的实例化。 - 处理依赖关系:在这个阶段,Spring 会确保所有的 beans 都被正确创建,并且它们的依赖关系也被正确地注入。
- 触发生命周期回调:Spring 容器支持 bean 的生命周期回调,如
InitializingBean接口的afterPropertiesSet方法或自定义的初始化方法。这些回调方法在这个阶段会被触发。
简而言之,finishBeanFactoryInitialization 方法是 Spring 容器初始化流程中的一个关键步骤,它确保所有的 beans 都已被创建、配置和初始化,并且它们的依赖关系也被正确处理。
内部实现:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 初始化此上下文的转换服务
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));
}
// 如果beanFactory之前没有注册嵌入值解析器,则注册默认的嵌入值解析器:主要用于注解属性值的解析。
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// 初始化LoadTimeWeaverAware Bean实例对象
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
beanFactory.setTempClassLoader(null);
// 冻结所有bean定义,注册的bean定义不会被修改或进一步后处理,因为马上要创建 Bean 实例对象了
beanFactory.freezeConfiguration();
// 实例化所有剩余(非懒加载)单例对象
beanFactory.preInstantiateSingletons();
}
接下来我们重点放在preInstantiateSingletons()方法上。
preInstantiateSingletons()实现:
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// 1.创建beanDefinitionNames的副本beanNames用于后续的遍历,以允许init等方法注册新的bean定义
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 2.遍历beanNames,触发所有非懒加载单例bean的初始化
for (String beanName : beanNames) {
// 3.获取beanName对应的MergedBeanDefinition
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 4.bd对应的Bean实例:不是抽象类 && 是单例 && 不是懒加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 5.判断beanName对应的bean是否为FactoryBean
if (isFactoryBean(beanName)) {
// 5.1 通过beanName获取FactoryBean实例
// 通过getBean(&beanName)拿到的是FactoryBean本身;通过getBean(beanName)拿到的是FactoryBean创建的Bean实例
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
// 5.2 判断这个FactoryBean是否希望急切的初始化
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());
}
// 5.3 如果希望急切的初始化,则通过beanName获取bean实例
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 6.如果beanName对应的bean不是FactoryBean,只是普通Bean,通过beanName获取bean实例
getBean(beanName);
}
}
}
// 7.遍历beanNames,触发所有SmartInitializingSingleton的后初始化回调
for (String beanName : beanNames) {
// 7.1 拿到beanName对应的bean实例
Object singletonInstance = getSingleton(beanName);
// 7.2 判断singletonInstance是否实现了SmartInitializingSingleton接口
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
// 7.3 触发SmartInitializingSingleton实现类的afterSingletonsInstantiated方法
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
关键代码解析:
getMergedLocalBeanDefinition(beanName)
MergedBeanDefinition:该词主要是用来表示 “合并的 bean 定义”,之所以称之为 “合并的”,是因为存在 “子定义” 和 “父定义” 的情况。对于一个 bean 定义来说,可能存在以下几种情况:
- 该 BeanDefinition 存在 “父定义”:首先使用 “父定义” 的参数构建一个 RootBeanDefinition,然后再使用该 BeanDefinition 的参数来进行覆盖。
- 该 BeanDefinition 不存在 “父定义”,并且该 BeanDefinition 的类型是 RootBeanDefinition:直接返回该 RootBeanDefinition 的一个克隆。
- 该 BeanDefinition 不存在 “父定义”,但是该 BeanDefinition 的类型不是 RootBeanDefinition:使用该 BeanDefinition 的参数构建一个 RootBeanDefinition。
源码解释:
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
// 1.加锁再进行操作
synchronized (this.mergedBeanDefinitions) {
// 用于存储bd的MergedBeanDefinition,也就是该方法的结果
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
if (containingBd == null) {
// 2.检查beanName对应的MergedBeanDefinition是否存在于缓存中
mbd = this.mergedBeanDefinitions.get(beanName);
}
// 3.如果beanName对应的MergedBeanDefinition不存在于缓存中
if (mbd == null || mbd.stale) {
previous = mbd;
if (bd.getParentName() == null) {
// 4.如果bd的parentName为空,代表bd没有父定义,无需与父定义进行合并操作,
// 也就是bd的MergedBeanDefinition就是bd本身(可能需要转成RootBeanDefinition)
if (bd instanceof RootBeanDefinition) {
// 4.1 如果bd的类型为RootBeanDefinition,则bd的MergedBeanDefinition就是bd本身,则直接克隆一个副本
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
// 4.2 否则,将bd作为参数,构建一个RootBeanDefinition。
// 正常使用下,BeanDefinition在被加载后是GenericBeanDefinition或ScannedGenericBeanDefinition
// 使用 XML 配置来注册 bean,则该 bean 定义会被封装成:GenericBeanDefinition;如果使用注解的方式来注册 bean,则该 bean 定义会被封装成 ScannedGenericBeanDefinition。
mbd = new RootBeanDefinition(bd);
}
}
else {
// 5.否则,bd存在父定义,需要与父定义合并
BeanDefinition pbd;
try {
// 5.1 获取父定义的beanName
String parentBeanName = transformedBeanName(bd.getParentName());
// 5.2 如果父定义的beanName与该bean的beanName不同
if (!beanName.equals(parentBeanName)) {
// 5.3 获取父定义的MergedBeanDefinition(因为父定义也可能有父定义,也就是bd的爷爷定义...)
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
// 5.4 如果父定义的beanName与bd的beanName相同,则拿到父BeanFactory,
// 只有在存在父BeanFactory的情况下,才允许父定义beanName与自己相同,否则就是将自己设置为父定义
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
// 5.5 如果父BeanFactory是ConfigurableBeanFactory,则通过父BeanFactory获取父定义的MergedBeanDefinition
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
// 5.6 如果父BeanFactory不是ConfigurableBeanFactory,则抛异常
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without a ConfigurableBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// 5.7 使用父定义pbd构建一个新的RootBeanDefinition对象(深拷贝)
mbd = new RootBeanDefinition(pbd);
// 5.8 使用bd覆盖父定义
mbd.overrideFrom(bd);
}
// 6.如果没有配置scope,则设置成默认的singleton
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(SCOPE_SINGLETON);
}
// 7.如果containingBd不为空 && containingBd不为singleton && mbd为singleton,则将mdb的scope设置为containingBd的scope
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// 8.将beanName与mbd放到mergedBeanDefinitions缓存,以便之后可以直接使用
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
// 9.返回MergedBeanDefinition
return mbd;
}
}
其中5.1:transformedBeanName内部实现如下:
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
// 如果beanName带有 "&" 前缀,则去掉
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
public String canonicalName(String name) {
String canonicalName = name;
String resolvedName;
do {
// 将别名解析成真正的beanName
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
为了区分 “FactoryBean” 和 “FactoryBean 创建的 bean 实例”,Spring 使用了 “&” 前缀。假设我们的 beanName 为 name,则 getBean("name") 获得的是自定义FactoryBean通过 getObject() 方法创建的 bean 实例;而 getBean("&name") 获得的是自定义FactoryBean本身。
例子如下:
public class NameFactoryBean implements FactoryBean<Name> {
@Override
public Name getObject() throws Exception {
Name name = new Name();
apple.setName("name");
return name;
}
@Override
public Class<?> getObjectType() {
return Name.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
其中5.3:getMergedBeanDefinition内部实现如下:
public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {
// 1.获取真正的beanName(解析别名)
String beanName = transformedBeanName(name);
// 2.如果当前BeanFactory中不存在beanName的Bean定义 && 父beanFactory是ConfigurableBeanFactory,
// 则调用父BeanFactory去获取beanName的MergedBeanDefinition
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
return ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName);
}
// 3.在当前BeanFactory中解析beanName的MergedBeanDefinition
return getMergedLocalBeanDefinition(beanName);
}
父 BeanFactory
在 Spring 中可能存在多个 BeanFactory,多个 BeanFactory 可能存在 “父工厂” 与 “子工厂” 的关系。最常见的例子就是:Spring MVC 的 BeanFactory 和 Spring 的 BeanFactory,通常情况下,Spring 的 BeanFactory 是 “父工厂”,Spring MVC 的 BeanFactory 是 “子工厂”,在 Spring 中,子工厂可以使用父工厂的 BeanDefinition,因而,如果在当前 BeanFactory 中找不到,而又存在父工厂,则会去父工厂中查找。
isFactoryBean(beanName)
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
// 1.拿到真正的beanName(去掉&前缀、解析别名)
String beanName = transformedBeanName(name);
// 2.尝试从缓存获取Bean实例对象
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null) {
// 3.beanInstance存在,则直接判断类型是否为FactoryBean
return (beanInstance instanceof FactoryBean);
}
// 4.如果beanInstance为null,并且beanName在单例对象缓存中,则代表beanName对应的单例对象为空对象,返回false
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
// 5.如果缓存中不存在此beanName && 父beanFactory是ConfigurableBeanFactory,则调用父BeanFactory判断是否为FactoryBean
return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
}
// 6.通过MergedBeanDefinition来检查beanName对应的Bean是否为FactoryBean
return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
}
其中2:getSingleton内部实现如下:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1.从单例对象缓存中获取beanName对应的单例对象
Object singletonObject = this.singletonObjects.get(beanName);
// 2.如果单例对象缓存中没有,并且该beanName对应的单例bean正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 3.加锁进行操作
synchronized (this.singletonObjects) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 4.从早期单例对象缓存中获取单例对象(之所称成为早期单例对象,是因为earlySingletonObjects里
// 的对象的都是通过提前曝光的ObjectFactory创建出来的,还未进行属性填充等操作)
singletonObject = this.earlySingletonObjects.get(beanName);
// 5.如果在早期单例对象缓存中也没有,并且允许创建早期单例对象引用
if (singletonObject == null) {
// 6.从单例工厂缓存中获取beanName的单例工厂
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 7.如果存在单例对象工厂,则通过工厂创建一个单例对象
singletonObject = singletonFactory.getObject();
// 8.将通过单例对象工厂创建的单例对象,放到早期单例对象缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
// 9.移除该beanName对应的单例对象工厂,因为该单例工厂已经创建了一个实例对象,并且放到earlySingletonObjects缓存了,
// 因此,后续获取beanName的单例对象,可以通过earlySingletonObjects缓存拿到,不需要在用到该单例工厂
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
// 10.返回单例对象
return singletonObject;
}
该段代码是 Spring 解决循环依赖的核心代码
循环依赖
由上可知,循环依赖其实就是一个闭环,像图中情况二Spring在创建单例bean A的时候发现引用了B,这时候就会去容器中查找单例bean B,发现没有然后就会创建bean B,创建bean B时又发现引用了bean A,这时候又会去容器中查找bean A,发现没有,接下来就会循环重复上面的步骤,循环依赖就是一个死循环的过程。
首先需要强调一点,虽然Spring允许Bean对象的循环依赖,但事实上,项目中存在Bean的循环依赖,是Bean对象职责划分不明确、代码质量不高的表现,如果存在大量的Bean之间循环依赖,那么代码的整体设计也就越来越糟糕。所以SpringBoot在后续的版本中终于受不了这种滥用,默认把循环依赖给禁用了!从2.6版本开始,如果你的项目里还存在循环依赖,SpringBoot将拒绝启动!
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| UserService (field private com.plasticene.fast.service.impl.RoleService com.plasticene.fast.service.impl.UserService.roleService)
↑ ↓
| RoleService (field private com.plasticene.fast.service.impl.UserService com.plasticene.fast.service.impl.RoleService.userService)
└─────┘
接下来我们在配置文件中配置开启允许循环依赖
spring:
main:
allow-circular-references: true
项目就能正常启动了。
但对于构造器的循环依赖,Spring 是无法解决的,只能抛出 BeanCurrentlyInCreationException 异常表示循环依赖。
解决方案:
Spring解决循环依赖的核心思想在于提前曝光,使用三级缓存进行提前曝光。
在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map作为三级缓存:
public class DefaultSingletonBeanRegistry ... {
//1、最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存"
Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
//2、早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存"
Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
//3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三级缓存"
Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}
步骤如下:
- 通过构建函数创建A对象(A对象是半成品,还没注入属性和调用init方法)。
- A对象需要注入B对象,发现缓存里还没有B对象,将
半成品对象A放入半成品缓存。 - 通过构建函数创建B对象(B对象是半成品,还没注入属性和调用init方法)。
- B对象需要注入A对象,从
半成品缓存里取到半成品对象A。 - B对象继续注入其他属性和初始化,之后将
完成品B对象放入完成品缓存。 - A对象继续注入属性,从
完成品缓存中取到完成品B对象并注入。 - A对象继续注入其他属性和初始化,之后将
完成品A对象放入完成品缓存。
小问:解决循环依赖只需要一个半成品缓存即可,为何还需要三级缓存(singletonFactories)?
答:第三级缓存(singletonFactories)是为了处理 Spring 的 AOP的。
-
三级缓存利用
ObjectFactory和getEarlyBeanReference()提前执行 AOP 操作生成代理对象。 -
在上移到二级缓存时,如果 Bean 中有 AOP 操作,那么提前暴露的对象会是 AOP 操作后返回的代理对象;如果没有 AOP 操作,那么提前暴露的对象会是原始对象。
-
当出现循环依赖问题时,注入依赖的对象和最终生成的对象会是同一个对象。