IoC源码分析——singleton bean创建与循环依赖

概要

容器初始化时,会创建单例bean,本文主要关注单例bean是如何创建的,并说明源码中是如何解决循环依赖的
代码入口

@Test
	public void testIoC() {
		// ApplicationContext是容器的高级接口,BeanFactory(顶级容器/根容器,规范了/定义了容器的基础行为)
		// Spring应用上下文,官方称之为 IoC容器(错误的认识:容器就是map而已;准确来说,map是ioc容器的一个成员,
		// 叫做单例池, singletonObjects,容器是一组组件和过程的集合,包括BeanFactory、单例池、BeanPostProcessor等以及之间的协作流程)

		/**
		 * Ioc容器创建管理Bean对象的,Spring Bean是有生命周期的
		 * 构造器执行、初始化方法执行、Bean后置处理器的before/after方法、:AbstractApplicationContext#refresh#finishBeanFactoryInitialization
		 * Bean工厂后置处理器初始化、方法执行:AbstractApplicationContext#refresh#invokeBeanFactoryPostProcessors
		 * Bean后置处理器初始化:AbstractApplicationContext#refresh#registerBeanPostProcessors
		 */

		// ClassPathXmlApplicationContext-> AbstractXmlApplicationContext
		// -> AbstractRefreshableConfigApplicationContext ->AbstractRefreshableApplicationContext
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		NormalBean normalBean = applicationContext.getBean(NormalBean.class);
		System.out.println(normalBean);
	}

以下是spring源码启动的主流程入口

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
			/**
			 * 刷新前的预处理
			 * 表示在真正做refresh操作之前需要准备做的事情
			 * 	设置spring容器的启动时间
			 * 	开启活跃状态,撤销关闭状态
			 * 	验证环境信息里一些必须存在的属性等
			 */
			prepareRefresh();
			/**
			 * 获取BeanFactory;默认实现是DefaultListableBeanFactory
			 * 加载BeanDefition 并注册到 BeanDefitionRegistry
			 */
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			/**
			 * 第三步: BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,⽐如context的类加
			 * 载器等)
			 */
			prepareBeanFactory(beanFactory);

			try {
				// 第四步: BeanFactory准备⼯作完成后进⾏的后置处理⼯作
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// 第六步:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执⾏
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				// Initialize message source for this context.
				// 第七步:初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
				initMessageSource();

				// Initialize event multicaster for this context.
				// 第⼋步:初始化事件派发器
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 第九步:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑
				onRefresh();

				// Check for listener beans and register them.
				// 第⼗步:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器bean
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				/*
				  第⼗⼀步:
				  初始化所有剩下的⾮懒加载的单例bean
				  初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性)
				  填充属性
				  初始化⽅法调⽤(⽐如调⽤afterPropertiesSet⽅法、 init-method⽅法)
				  调⽤BeanPostProcessor(后置处理器)对实例bean进⾏后置处
				*/
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				/*
					第⼗⼆步:
					完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,并且发布事
					件 (ContextRefreshedEvent)
				*/
				finishRefresh();
			} catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			} finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}

主流程

关于bean的三级缓存,DefaultSingletonBeanRegistry中的变量,如下

/**
* 一级缓存:单例(对象)池,这里面的对象都是确保初始化完成,可以被正常使用的
* 它可能来自3级,或者2级
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/**
* 三级缓存:单例工厂池,这里面不是bean本身,是它的一个工厂,未来调getObject来获取真正的bean
* 一旦获取,就从这里删掉,进入2级(发生闭环的话)或1级(没有闭环)
*/
private final Map<String, ObjectFactory<?>> singletonFactories = newHashMap<>(16);
/**
* 二级缓存:早期(对象)单例池,这里面都是半成品,只是有人用它提前从3级get出来,把引用
暴露出去
* 它里面的属性可能是null,所以叫早期对象,early!半成品
* 未来在getBean付完属性后,会调addSingleton清掉2级,正式进入1级
*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

关于单例bean的生命周期,其主要包括以下几个方面
在这里插入图片描述
各个部分的细节如下:
在这里插入图片描述

bean的创建

代码层面,主要关注以下几个方法
在这里插入图片描述
入口:org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

public void preInstantiateSingletons() throws BeansException {
	if (logger.isTraceEnabled()) {
		logger.trace("Pre-instantiating singletons in " + this);
	}

	// Iterate over a copy to allow for init methods which in turn register new bean definitions.
	// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// Trigger initialization of all non-lazy singleton beans...
	for (String beanName : beanNames) {
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		// 是否抽象 是否单例 是否延迟创建
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			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());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
			} else {
				// 不是工厂bean,普通bean的创建
				getBean(beanName);
			}
		}
	}
	....
}

在这里插入图片描述

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 判断一级缓存中是否存在
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
			// 二级缓存中是否存在
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
				// 	再从三级缓存中获取
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

注意这里有个细节,先判断二级中缓存是否存在,不存在再从三级缓存中获取。这里很重要,也是为什么要有二级缓存存在的原因

在这里插入图片描述
触发函数式接口
在这里插入图片描述
下面看:AbstractAutowireCapableBeanFactory#createBean(String,RootBeanDefinition,Object[])

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {
		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			// 调用构造函数创建bean  未设置属性
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}
		synchronized (mbd.postProcessingLock) {
			...
		}

		// 是否单例 是否允许循环引用 是否 正在创建->提前暴露
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			...
			// 放入到三级缓存中
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}
		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			// bean属性填充
			populateBean(beanName, mbd, instanceWrapper);
			// 调用初始化方法,应用BeanPostProcessor方法
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		} catch (Throwable ex) {
			..
		}
		...

		return exposedObject;
	}

到这里,初始化bean的主流程就跑完了,在没有循环依赖的情况下,bean的正常创建就是经历了以上主流程代码。下面仔细分析下org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getEarlyBeanReference

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
				exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
			}
		}
		return exposedObject;
	}

bean在用构造函数创建后,此时还没有设置属性值,会提前把一个函数式接口放入到三级缓存中,上面的getEarlyBeanReference方法,就是在addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));放入到三级缓存中。进入到里面可以看到跟创建代理对象有关。所以此处将接口放入到三级缓存主要有以下两个作用:

  1. 提前暴露正在创建的对象,如果有其他对象引用了该对象,那么就可以直接从三级缓存中获取
  2. 如果该对象需要被增强,要被创建代理对象,那么该函数式接口也能保证,其他对象依赖的是增强后的对象

循环依赖

下面从源码分析,spring是如何解决循环依赖的。
循环依赖涉及到三级缓存的的变化,下面围绕三级缓存的变化梳理主要流程

有配置文件如下

<!--循环依赖BeanA依赖BeanB -->
<bean id="userServiceImplA" class="com.spring.test.impl.UserServiceImplA">
<property name="userServiceImplB" ref="userServiceImplB"/>
</bean>
<!--循环依赖BeanB依赖BeanA -->
<bean id="userServiceImplB" class="com.spring.test.impl.UserServiceImplB">
<property name="userServiceImplA" ref="userServiceImplA"/>
</bean>

上面看出对象A引用了对象B,同时对象B也引用了对象A,对象A、B之间存在循环依赖

在这里插入图片描述
对象B在设置属性值A时,会调getBean方法,从容器中获取对象,从而会重新走一遍上面的主流程,入口如下
org.springframework.beans.factory.support.BeanDefinitionValueResolver#resolveReference
在这里插入图片描述
在走一遍主流程时,在org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean) 方法中,会发现三级缓存中已经存在对象A了,就直接从三级缓存中获取
在这里插入图片描述
这里要注意的时,三级中A的会被移除,从而转移到二级缓存中,这里为什么要从三级缓存中移除呢?假如有个对象C也引用了A,并且对象A是需要创建动态代理的,如果不从3级缓存中进行移除,那么A对象就会被重复执行到三级缓存中的函数式接口,这样就是产生多个A的代理对象。从三级缓存中移除,并转移到二级缓存中,这样,当C也需要A时,直接从二级缓存中进行获取就可以了,就不会造成创建多个A对象的代理对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值