简单记录之SpringIOC初始化过程(二)——Bean的创建及循环依赖问题

本文描述的IOC基于注解的方式启动容器

本文主要讲解refresh方法以及bean的创建过程,关于refresh执行前对于配置资源的读取加载可以看上一篇👉简单记录之SpringIOC初始化过程(一)

先贴上refresh()方法的代码:

	public void refresh() throws BeansException, IllegalStateException {
		//给容器refresh加锁,避免容器处在refresh阶段时,容器进行了初始化或者销毁的操作
		synchronized (this.startupShutdownMonitor) {
			//调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识,具体方法
			prepareRefresh();

			//告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
			//子类的refreshBeanFactory()方法启动,里面有抽象方法
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 注册一些容器中需要的系统Bean,例如classLoader,beanFactoryPostProcessor等
			prepareBeanFactory(beanFactory);

			try {
				//允许容器的子类去注册 postProcessor
				postProcessBeanFactory(beanFactory);

				//激活在容器中注册为 bean的 BeanFactoryPostProcessors
				//对于注解容器,org.springframework.context.annotation.ConfigurationClassPostProcessor
				//方法扫描应用中所有BeanDefinition并注册到容器之中
				invokeBeanFactoryPostProcessors(beanFactory);

				//注册拦截 Bean创建过程的BeanPostProcessor
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				//初始化事件发布器
				//可以存储所有事件监听者信息,并根据不同的事件,通知不同的事件监听者。
				initApplicationEventMulticaster();

				//预留给AbstractApplicationContext 的子类用于初始化其他特殊的bean,
				//该方法需要在所有单例 bean初始化之前调用
				//比如Web容器就会去初始化一些和主题展示相关的Bean(ThemeSource)
				onRefresh();

				//注册监听器(检查监听器的bean并注册他们)
				registerListeners();

				// 实例化所有剩余的(非延迟初始化)单例。
				//设置自定义的类型转化器ConversionService
				//设置自定义AOP相关的类LoadTime WeaverAware,
				//清除临时的 ClassLoader
				//实例化所有的类(懒加载的类除外)
				finishBeanFactoryInitialization(beanFactory);

				//初始化容器的生命周期事件处理器,(默认使用 DefaultLifecycleProcessor),调用扩展了SmartLifecycle
				//当Spring容器加载所有bean并完成初始化之后,会接着回调实现该接口的类中对应的方法(start()方法)
				//并发布容器刷新完毕事件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 {
				//重置Spring内今天核中的共用的缓存,因为我们可能再也不需要单例 bean的元数据了
				resetCommonCaches();
			}
		}
	}

这篇文章主要理清bean的创建过程,对于关键的方法会作为标题,其他的方法就简单的说说它的功能。
invokeBeanFactoryPostProcessors(beanFactory):激活在容器中注册为 bean的 BeanFactoryPostProcessors(根据在register方法中注册的BeanFactoryPostProcessor的BeanDefinition去创建对应的bean实例)。这一步除了创建BeanFactoryPostProcessor,另一个重要的动作就是——扫描应用中所有BeanDefinition并注册到容器之中,供后续容器创建bean实例。

registerBeanPostProcessors(beanFactory):将应用中所有的bean级别的后置处理器即BeanPostProcessor(上一个方法是beanFactory级别的后置处理器),根据beanDefinition去创建对应的实例。

finishBeanFactoryInitialization

此方法的作用:完成此容器(上下文)的bean工厂的初始化,初始化所有剩余的单例bean(懒加载的bean除外),然后调用该方法中的beanFactory.preInstantiateSingletons(),实例化所有剩余的非懒加载的单例

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) {
						final 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 {
					getBean(beanName);
				}
			}
		}
		//....

贴了一部分代码,可以看到会先判断这个bean是不是工程bean,即FactoryBean,如果是的话,则在beanName前加一个转义符&,然后进行调用getBean()方法进行下一步的操作。
其实在这里就可以看出,通过FactoryBean的方法向容器添加Bean,会创建两个Bean,一个是FactoryBean,另一个是工厂bean中的Bean。而获取他们的方法:获取工厂bean需要加FactoryBean的名字前加&,如果不加,获取到的就是工厂bean中的Bean。

getBean —> doGetBean

根据Spring中的方法命名习惯,do开头的方法是真正做事儿的方法,从getBean调用doGetBean没有额外的逻辑处理,所以就放一起了。
贴上部分的doGetBean方法👇

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		//通过三种形式获取beanName
		//一个是原始的beanName,一个是加了&的,一个是别名
		final String beanName = transformedBeanName(name);
		Object bean;

		//尝试从单例缓存集合里获取 bean实例
		Object sharedInstance = getSingleton(beanName);

		//如果先前已经创建过单例 Bean的实例,并且调用的 getBean方法传入的参数为空
		//则执行if里面的逻辑
		//args之所以要求为空是因为如果有args,则需要做进一步赋值,因此无法直接返回
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			//如果是普通 bean,直接返回,如果是BeanFactory,则返回他的 getObject对象
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		//若scope为prototype或者单例模式但是缓存中还不存在bean
		else {
			//如果scope为prototype并且显示还在创建中,则基本是循环依赖的情况
			//针对prototype的循环依赖,spring无解,直接抛出异常
			//A--B--A
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			//..............................
			//不想篇幅过长,中间一部分代码删除了
			//..............................
				
				//如果bean是单例
				if (mbd.isSingleton()) {
					//这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							//显式从单例缓存中删除 bean 实例
							//因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}
				//................
				//................

从代码中可以看到:

  1. 首先,通过getSingleton()方法,尝试从缓存中获取bean,如果有就返回,为null的话就进入到else的逻辑中。getSingleton()也是个重要的方法
  2. 在判断这个要创建的bean是会先进行scope为prototype的循环依赖的判断

具体是如何判断的:首先要明确一点,这里处理的循环依赖,是多例情况下的处理方式——直接抛出异常,即不支持多例的循环依赖。
如何检查:一个ThreadLocal<Object>类型的prototypesCurrentlyInCreation,查看具体操作threadLocal的方法,可以看到,里面存储着正在创建的bean的名字的Set集合。假设A,B相互依赖,创建A的时候,A被加入到Set中,当执行到A的成员变量的依赖注入的时候,也是执行getBean这个方法,所以,也会执行到doGetBean方法,当对B的成员变量进行注入的时候,又回去通过getBean去获取A,那么这时候Set已经存在A,所以就会抛出异常。

  1. 接下来就是判断beanDefinition的类型,单例还是多例,然后去执行createBean()方法
createBean

贴上部分代码👇

		try {
			//如果Bean配置了初始化前和初始化后的处理器,则试图返回一个需要创建 Bean的代理对象
			//resolveBeforeInstantiation只是针对有自定义的targetsource,
			//因为自定义的targetsource不是spring的bean那么肯定不需要进行后续的一系列的实例化初始化。
			//所以可以在resolveBeforelnstantiation直接进行 proxy
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			//(创建bean的入口)
			//如果在resolveBeforeInstantiation没有代理对象,则通过spring创建
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}

从代码中可以看到,在doCreateBean之前,会执行一个关键的方法——resolveBeforeInstantiation(),跟进源码中可以看到,会去判断,容器中是否存在InstantiationAwareBeanPostProcessor这样的bean级别的后置处理器,若有,则执行InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation()方法,如果在后置处理器中创建了bean,那么直接返回,等同于在spring创建bean的过程中用户做了截胡。如果没有,那么就执行doCreateBean()方法

doCreateBean
		//bean实例包装类
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			//从未完成创建的包装Bean缓存中清理并获取相关中的包装Bean实例,毕竟是单例的,只能存一份
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			//创建bean的时候,这里创建bean的实例有三种方法
			//1.工厂方法创建
			//2.构造方法的方式注入
			//3.无参构造方法注入
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		//调用 BeanDefinition属性合并完成后的 BeanPostProcessor后置处理器
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					//被@Autowired、@Value标记的属性在这里获取
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		//向容器中缓存单例模式的Bean对象,以防循环引用
		//判断是否是早期引用的bean,如果是,则允许其提前暴露引用
		//这里判断的逻辑主要有三个:
		//1.是否为单例
		//2.是否允许循环引用
		//3.是否是在创建中的bean
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			//这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用
			//getEarlyBeanReference,从二级缓存中取出实例化但没有属性赋值的bean
			//加入到三级缓存objectFactory中,通过getObject获取上述的bean
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}
		//Bean对象的初始化,依赖注入在此触发
		Object exposedObject = bean;
		try {
			//填充Bean实例的属性
			populateBean(beanName, mbd, instanceWrapper);
			//初始化bean,过程如下:
			//1:判断景否实现了BeanNameAware,BeanClassloaderAware,
			//BeanFactoryAware方法,如果有,则设置相关的属性
			//2:调用bean初始化的前置(BeanPostProcessor)操作
			//3:执行初始化的方法。
			//如果有initializingBean,则调用afterPropertiesSet
			//如果有InitMethod,则调用初始方法
			//4:调用bean初始化的后置(BeanPostProcessor)操作
			exposedObject = initializeBean(beanName, exposedObject, mbd);
	//....................
	//....................

在这个方法中,bean才是真正的创建:

  1. 首先调用createBeanInstance()方法,通过反射创建一个bean实例(依赖还未注入)
  2. 然后调用applyMergedBeanDefinitionPostProcessors()方法,判断实例中被@Autowire标记的成员变量或者方法并记录下来
  3. 调用addSingletonFactory()方法,将bean加入到三级缓存中,解决单例模式下的循环依赖问题
  4. 调用populateBean()方法,根据2中被记录下来的成员变量进行注入
  5. 调用initializeBean()方法,执行初始化方法的前置操作——执行初始化方法操作——执行初始化方法的后置操作

到这里,bean的创建就已经完成,下面来讲讲单例模式下是怎么解决循环依赖问题的

单例模式下是怎么解决循环依赖问题的

同样的,假设A、B(单例)相互依赖,创建A的过程中,在属性注入之前,也就是和上面的2步骤,调用addSingletonFactory()方法👇——第二个参数是ObjectFactory,一个只定义了getObject()方法的接口。这里用了匿名内部类,调用getEarlyBeanReference()方法(跟进方法中可以看到依然存在一个bean的后置处理器SmartInstantiationAwareBeanPostProcessor的调用,如果不存在则返回默认的实例)返回实例的值,加入到三级缓存中。

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
  1. 当A执行到属性注入的时候,通过getBean去获取B的实例,B此时还不存在,所以也进入到了doCreateBean中,B的实例也加入到了三级缓存中
  2. 当B去给属性注入的时候,通过getBean去获取A的实例,就会去调用getSingleton()方法,依次从一级缓存–二级缓存–三级缓存中获取,最后从三级缓存中获取到了A的实例,即使这时候它是没有完全初始化的
  3. 然后B初始化完成了,则回到了A的属性注入,后面的步骤就没什么了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值