Spring源码深度解析:八、bean的获取② - getSingleton

news2024/11/17 14:35:20

一、前言

文章目录:Spring源码分析:文章目录

在Spring源码分析七 :bean的加载① - doGetBean 文章中,我们介绍了Spring对获取bean的过程,但是并没有详细解释Bean是如何创建的,本文就来分析Spring是如何创建的bean

bean的加载① - doGetBean 文章中我们知道DefaultSingletonBeanRegistry#getSingleton(java.lang.String, ObjectFactory<?>)这一步创建了bean,如下图:
在这里插入图片描述

到了这一步,Spring就基本对Bean已经创建好的不抱什么希望了,所以着手开始自己创建bean
本文就先来分析getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法整个流程。

二、获取单例 - getSingleton

具体代码如下:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		// 因为创建过程中需要操作singletonObjects。所以需要加锁
		synchronized (this.singletonObjects) {
			// 1. 再次尝试获取bean,判断bean是否已经加载。如果加载直接返回。
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				// 2. 判断,如果当前beanFactory正在被销毁则直接抛出异常,不允许创建单例bean
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
				// 3. 做一些bean创建前的准备工作:记录beanName正在加载的状态(添加到singletonsCurrentlyInCreation缓存中),若bean已经正在加载,则抛出异常。为了解决循环引用的问题
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// 4. 通过回调方式获取bean实例。
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					// 5. 加载单例后的处理方法调用:删除bean正在创建的记录(从singletonsCurrentlyInCreation中移除beanName)
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					// 6. 加入到缓存中,并删除加载bean过程中所记录的各种辅助状态
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

上面的代码注释也比较清楚,基本流程如下:

  1. this.singletonObjects.get(beanName); :再次尝试从缓存中获取bean,若获取到,则直接返回。
  2. if (this.singletonsCurrentlyInDestruction) :未获取到检测bean是否正在销毁,若是则抛出异常
  3. beforeSingletonCreation():记录bean正在创建的状态将beanName添加到 singletonsCurrentlyInCreation集合中)。在循环依赖时可根据此判断。
  4. singletonObject = singletonFactory.getObject(); :调用ObjectFactory.getObject()方法来实例化bean
  5. afterSingletonCreation():删除bean正在创建的记录(从singletonsCurrentlyInCreation中移除beanName)
  6. addSingleton(beanName, singletonObject); : 加入到缓存中,并删除加载bean过程中所记录的各种辅助状态

DefaultSingletonBeanRegistry#beforeSingletonCreation(String beanName)

	/**
	 * 不包含 && 添加失败 :则认为Bean正在创建中,抛出异常
	 */
	protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

DefaultSingletonBeanRegistry#afterSingletonCreation(String beanName)

	/**
	 * 不包含 && 移除失败 :认为Bean 已经创建结束,抛出异常。
	 */
	protected void afterSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
			throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
		}
	}

DefaultSingletonBeanRegistry#addSingleton(String beanName, Object singletonObject)

	/**
	 * 主要还是对几个缓存map的操作
	 */
	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.put(beanName, singletonObject);
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}

流程图如下所示 :
在这里插入图片描述

可以非常直观的看出, getSingleton 方法中的关键逻辑非常简单,bean创建的具体逻辑在singletonObject = singletonFactory.getObject();中,所以下面继续去分析singletonFactory.getObject()中做了什么。

三、创建bean - createBean概述

上面可以看到,主要步骤还是在回调的getObject()方法中。那么我们来看看在bean加载过程中的FactoryBean做了什么。代码如下:
在这里插入图片描述
兜了一大圈关键代码还是在createBean()方法里。接下来,我们就来仔细分析一下createBean()方法。
AbstractBeanFactory#createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException;

AbstractAutowireCapableBeanFactory#createBean()

	@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		if (logger.isDebugEnabled()) {
			logger.debug("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		// 1. 锁定class, 根据mdb和beanName解析出来class
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		// Prepare method overrides.
		try {
			// 2. 验证及准备覆盖的方法
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			// 3. 给beanPostProcessor一个返回目标类代理类的机会
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			// 如果后处理器真的实现了,则直接返回使用后处理器的bean
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			// 4.  创建bean 的 真正方法
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isDebugEnabled()) {
				logger.debug("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			// A previously detected exception with proper bean creation context already,
			// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

可以看到,createBean 的整体流程大致如下:

  1. 根据设置的class属性或者根据className来解析Class。
  2. 对override 属性进行标记及验证。
  3. 应用初始化前的后处理器,解析指定bean是否存在初始化前的短路操作。
  4. 创建bean。
  5. 返回bean

流程图如下:
在这里插入图片描述

四、创建bean - createBean详解

上面的逻辑看着似乎不复杂,实际上,真正的逻辑都被封装在了方法中,所以下面需要关注如下的几个方法:

1、resolveBeanClass()

这里不再过多展示代码,这个方法的作用就是根据参数和返回值都能知道: 根据BeanDefinitionbeanName解析出beanClass

	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

2、prepareMethodOverrides()

见名知意: 准备方法重写,这里更多是做一个校验的功能。这个方法主要是针对lookup-methodreplaced-method两个属性的,用来覆盖指定的方法。

	mbdToUse.prepareMethodOverrides();

详细代码如下:
AbstractBeanDefinition#prepareMethodOverrides()

	public void prepareMethodOverrides() throws BeanDefinitionValidationException {
		// Check that lookup methods exist and determine their overloaded status.
		// // 判断是否有方法需要重写
		if (hasMethodOverrides()) {
			getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
		}
	}

AbstractBeanDefinition#prepareMethodOverride(MethodOverride mo)

	protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
		// 获取对应的类中的对应方法名的个数
		int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
		// 等于0抛出异常。上面已经验证有方法需要覆盖,这里为0肯定错误
		if (count == 0) {
			throw new BeanDefinitionValidationException(
					"Invalid method override: no method with name '" + mo.getMethodName() +
					"' on class [" + getBeanClassName() + "]");
		}
		else if (count == 1) {
			// Mark override as not overloaded, to avoid the overhead of arg type checking.
			// 标记 MethodOverride 暂未被覆盖,避免参数类型检查的开销。
			mo.setOverloaded(false);
		}
	}

解释一下上面的逻辑:

  1. 首先会判断是否有方法需要重写,这里的是根据RootBeanDefinition中的 methodOverrides属性来进行判断,为空则表示没有。
  2. 若上述判断有方法需要覆盖,则会调用prepareMethodOverride(MethodOverride mo)方法。而在prepareMethodOverride(MethodOverride mo)方法中会根据需要覆盖的方法名称 来获取加载类中关于该方法的实现。如果获取不到 count == 0,则直接抛出异常,如果获取到只有一个count == 1,则记录该方法并未被重载(因为Spring在方法匹配时,如果一个类中存在若干个重载方法,则在函数调用及增强的时候需要根据参数类型进行匹配,来最终确定调用的方法是哪一个,这里直接设置了该方法并未被重载,在后续方法匹配的时候就不需要进行参数匹配验证,直接调用即可)。
  3. 打个比方,比如指定覆盖A类中的 a方法,但是A类中可能存在多个a方法或者不存在a方法,若count == 0不 存在a方法,则谈何覆盖,直接抛出异常,若count ==1 则a方法的实现只有一个,标记该方法并未被重载后续可跳过参数验证的步骤。

3、resolveBeforeInstantiation

该方法主要是调用InstantiationAwareBeanPostProcessor来进行一些处理,这里实际上是给了用户一次代替Spring来创建bean的机会,代码实现上非常简单直接调用的后处理器方法。

			// 3. 调用BeanProcessors的方法来替代真正的实例
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			// 如果后处理器真的实现了,则直接返回使用后处理器的bean
			if (bean != null) {
				return bean;
			}

该方法调用了后处理器的方法:

  • InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation() : 在bean初始化前调用
  • BeanPostProcessor#postProcessAfterInitialization() : 在bean初始化后调用

详细代码如下:在调用doCreate()方法创建bean的实例前调用了该方法对 BeanDefinition中的属性做一些前置处理。

	@Nullable
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		// 如果尚未被解析
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			// 当前类并非合成类 && 存在 BeanPostProcessor (后处理器)
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				// 1. 获取目标类
				Class<?> targetType = determineTargetType(beanName, mbd);
				// 2. 实例前的后处理器应用
				if (targetType != null) {
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						// 3. 实例后的后处理器应用
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

其中applyBeanPostProcessorsBeforeInstantiationapplyBeanPostProcessorsAfterInitialization很明显就是调用bean的后处理器,也就是对后处理器中的InstantiationAwareBeanPostProcessor类型的后处理器进行 postProcessBeforeInstantiation方法 和BeanPostProcessor类型的 postProcessAfterInitialization方法的调用。

3.1 determineTargetType(beanName, mbd);

关于factoryMethodName值的由来 这一点我们在 Spring源码深度解析:六、ConfigurationClassPostProcessor 中有过强调。即如果通过@Bean注入,则保存期工厂类的方法名称,简单来说就是配置类中对应该bean的注入方法名称。

	@Nullable
	protected Class<?> determineTargetType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
		// 获取目标类。这里获取的目标类并不一定是真正生成的类,可能是其真正类的父类或者父接口
		Class<?> targetType = mbd.getTargetType();
		if (targetType == null) {
			// 根据mdb 是否存在 factoryMethodName 来确定是直接解析class还是通过 工厂类的方法返回值来获取class
			targetType = (mbd.getFactoryMethodName() != null ?
					getTypeForFactoryMethod(beanName, mbd, typesToMatch) :
					resolveBeanClass(mbd, beanName, typesToMatch));
			if (ObjectUtils.isEmpty(typesToMatch) || getTempClassLoader() == null) {
				mbd.resolvedTargetType = targetType;
			}
		}
		return targetType;
	}

需要注意的是 这里获取的targetType类型并不一定是真正生成的bean类型,也可能是实际类型的父类或者父接口 。因为对于通过@Bean注解修饰注入到Spring容器的时候,BeanDefinitionfactoryMethodName属性值不为空,指向其工厂类的方法名。并且由于多态的特性,其工厂方法引入的类型并不一定是实际类型。这个类型的错误会在 AbstractAutowireCapableBeanFactory#doCreateBean()中纠正过来.

比如 :下面的demoService()方法实际生成的类型是DemoServiceImpl。这里返回的类型是DemoService。那么我们这里获取到的targetType就是 DemoService.class。其BeanDefinition.factoryMethodName = demoService(即 DemoConfig 生成DemoService的方法的名称)

public class DemoConfig {
    @Bean
    public DemoService demoService() {
        return new DemoServiceImpl();
    }
}

3.2 postProcessBeforeInstantiation

在bean 实例化前调用,也就是将AbstractBeanDefinition转换为BeanWrapper前的处理。给子类一个修改BeanDefinition的机会,也就是说当程序经过这个方法后,bean可能已经不是我们所认为的bean了。或许是一个经过代理的代理bean。可能是通过cglib生成的,也可能是通过其他技术生成的。
AbstractAutowireCapableBeanFactoryapplyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName)

	@Nullable
	protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
		// 获取所有BeanPostProcessor进行遍历
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				// 调用postProcessBeforeInstantiation方法
				Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
				if (result != null) {
					return result;
				}
			}
		}
		return null;
	}

3.3 postProcessAfterInitialization

这里是bean创建后的后置方法调用,逻辑基本类似。不同的是到达这一步时,Bean已经创建成功,并且注入属性也进行了赋值。

需要注意,如果bean交由Spring来创建,那么Spring会将需要的属性注入到bean中,如果是自己代理生成(比如通过postProcessBeforeInstantiation方法生成),那么需要自己解决bean的属性注入问题。
AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)

	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

4、创建bean - doCreateBean

代码执行到这里,可以确定第三步中并没有返回一个非空的bean(BeanPostProcessor 并没有代理生成一个bean)。所以Spring开始自己着手创建bean。do开头的方法才是真正做事情的,所以这里才是真正创建bean的地方。

Object beanInstance = doCreateBean(beanName, mbdToUse, args);

具体代码如下:

	/** 保存的是 FactoryBean 的beanName -> FactoryBean 的 BeanWrapper */
	private final ConcurrentMap<String, BeanWrapper> factoryBeanInstanceCache = new ConcurrentHashMap<>(16);

	// 创建Bean的核心方法
	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// 实例化Bean
		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			// 有可能在本Bean创建之前,就有其他Bean把当前Bean给创建出来(比如依赖注入过程中)
			// 单例情况下清除缓存。这里保存的是 FactoryBean 和 BeanWrapper 的映射关系。
			// factoryBeanInstanceCache是在创建其他bean的时候缓存了一下FactoryBean 。
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		// 如果没有缓存,则重新创建
		if (instanceWrapper == null) {
			// 1. 创建Bean实例:根据指定的bean使用对应的策略创建新的实例。如:工厂方法、构造函数自动注入,简单初始化
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		// 获取bean实例
		Object bean = instanceWrapper.getWrappedInstance();
		// 获取bean类型
		Class<?> beanType = instanceWrapper.getWrappedClass();
		// 将目标类型替换成实际生成的类型.纠正了上面说到类型错误(如果存在)
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// 2. 调用 MergedBeanDefinitionPostProcessor 后处理器,后置处理合并后的BeanDefinition
		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					// 调用MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition后处理器的方法。
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		// 3. 判断是否需要提早曝光:单例 & 允许循环依赖 & 当前bean已经正在创建中
		// 由于当前bean已经在创建中,本次创建必然是循环引用造成的,所以这里判断是否可以需要提前曝光
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			// 4. 为避免后期循环依赖,在bean初始化完成前将创建实例的ObjectFactory加入工程  -- 解决循环依赖:添加到三级缓存
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			// 5. 对bean进行属性填充,将各个属性值注入,其中如果存在依赖于其他bean的属性,则会递归初始依赖bean
			populateBean(beanName, mbd, instanceWrapper);
			// 调用初始化方法,比如 init-method
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		// 6. 进行循环依赖检查
		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			// earlySingletonReference只有在检测到有循环依赖的情况下才会不为空
			if (earlySingletonReference != null) {
				// 如果exposedObject没有在初始化方法中被改变,也就是没有被增强
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						// 检测依赖
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					// 因为bean创建后其所依赖的bean一定是已经创建了的。actualDependentBeans不为空说明当前bean创建后其依赖的bean却没有全部创建完,也就说说存在循环依赖。
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			// 7.根据Scopse 注册bean
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

大致逻辑如下:

  1. createBeanInstance(beanName, mbd, args) :实例化bean,将BeanDefinition转换为BeanWrapper
  2. applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); MergedBeanDefinitionPostProcessor后处理器的应用。bean合并后的处理,比如 @Autowired@Value注解正是通过 AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition()此方法实现的预解析。
  3. addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); : 关于循环依赖的处理,添加ObjectFactory到singletonFactories缓存中,同时这里给了用户一个机会通过调用SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference方法来由用户生成暴露的实例
  4. populateBean(beanName, mbd, instanceWrapper); :对创建的bean内部的一些属性进行填充注入
  5. initializeBean(beanName, exposedObject, mbd); : 初始化bean的一些属性,如Aware接口的实现,init-method属性等
  6. 循环依赖检查。和第四步不同的是,这里了是判断是否无法解决循环依赖,否则抛出异常。
  7. registerDisposableBeanIfNecessary(beanName, bean, mbd); : 注册DisposableBean
  8. 完成创建并返回。

4.1 createBeanInstance

见名知意 : 该方法完成了bean的实例创建。

instanceWrapper = createBeanInstance(beanName, mbd, args);

大概逻辑可以概括为:

  1. 如果存在工厂方法则使用工厂方法进行初始化
  2. 若类有多个构造函数,则根据参数锁定构造函数并初始化
  3. 如果即不存在工厂方法也不存在带参构造函数,则使用默认的构造函数进行bean的实例化。

具体的代码分析已成文 : Spring源码分析六:bean的创建④ - createBeanInstance

4.2 applyMergedBeanDefinitionPostProcessors

这种方法命名的也见得多了,见名知意: 该方法完成了MergedBeanDefinitionPostProcessors后处理器的功能。主要是 bean合并后的处理。在 AutowiredAnnotationBeanPostProcessorpostProcessMergedBeanDefinition方法的实现中,就对@Autowired、@Value 等注解进行了一系列的预处理,这里我们并不需要太过在意。
AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors()

	protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof MergedBeanDefinitionPostProcessor) {
				MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
				bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
			}
		}
	}

4.3 addSingletonFactory

这一部分的逻辑就是为了解决循环依赖的问题,将未创建完成的当前bean,通过ObjectFactory进行一个包装,提前暴露给其他bean。

具体代码如下:

		// 3. 判断是否需要提早曝光:单例 & 允许循环依赖 & 当前bean已经正在创建中
		// 由于当前bean已经在创建中,本次创建必然是循环引用造成的,所以这里判断是否可以需要提前曝光
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			// 4. 为避免后期循环依赖,在bean初始化完成前将创建实例的ObjectFactory加入工程  -- 解决循环依赖:添加到三级缓存
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

首先我们需要分析出earlySingletonExposure为true的条件:

  • bean是单例
  • 允许循环依赖
  • 当前bean正在创建中 :singletonsCurrentlyInCreation包含当前bean。在Spring中有专门的属性记录bean的加载状态 – DefaultSingletonBeanRegistry#singletonsCurrentlyInCreation()。在bean创建前会将bean添加,bean创建结束后将bean移除。这一点我们在前篇有过提及。
    满足上述三个条件后,则会调用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); 方法。为避免后期循环依赖,在bean初始化完成前将创建实例的ObjectFactory加入工程 – 解决循环依赖:添加到三级缓存

DefaultSingletonBeanRegistry#addSingletonFactory()

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		synchronized (this.singletonObjects) {
			if (!this.singletonObjects.containsKey(beanName)) {
				this.singletonFactories.put(beanName, singletonFactory);
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}
	}

AbstractAutowireCapableBeanFactory#getEarlyBeanReference()

	 
	/** 
	 * 给调用者一次机会,主要就是调用了SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference()方法。将getEarlyBeanReference方法的返回值作为提前暴露的对象。
	 * 我们可以通过实现 getEarlyBeanReference()方法来替代Spring提前暴露的对象
	 * Aop就是在这里将Advice动态织入bean中,若没有bean则直接返回bean,不做任何处理
	 */
	protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		// 当前类并非合成类 && 在hasInstantiationAwareBeanPostProcessors中
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
		return exposedObject;
	}

该方法中getEarlyBeanReference调用了后处理器的方法,可用于用户自己扩展替换Spring生成的提前暴露的对象 :

4.4 populateBean

见名知意,下面这个方法是用来属性注入的。
populateBean()方法则是对bean属性的注入,上面的createBeanInstance方法创建了 bean,但是其内部属性并没有注入,比如通过@Autowired注解注入的变量属性,此时还为null,需要对这种属性进行注入,这一步就是完成这种功能。

	populateBean(beanName, mbd, instanceWrapper);

这里方法里按照如下顺序调用了后处理器

  1. InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation : 返回true 才会调用下面两个方法
  2. InstantiationAwareBeanPostProcessor.postProcessProperties : 进行属性的注入。
  3. InstantiationAwareBeanPostProcessor.postProcessPropertyValues : 已过时

篇幅所限,详细的代码分析请阅 Spring源码分析七:bean的属性注入⑤ - populateBean

4.5 initializeBean

到达这一步,其实bean已经创建结束了,这一步是完成最后的功能,提供一些功能的实现,如Aware 接口的实现, init-method、InitializingBean属性等。

	exposedObject = initializeBean(beanName, exposedObject, mbd);

篇幅所限,详情请阅 : Spring源码分析八:bean的初始化⑥ - initializeBean

4.6 循环依赖检查

Spring 循环依赖的解决仅对单例且非构造函数构造的形式有效,对于原型模式的bean,Spring直接抛出异常,在这个步骤中会检测已经加载的bean 是否已经出现了循环依赖,并判断是否需要抛出异常。

// 6. 进行循环依赖检查
		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			// earlySingletonReference只有在检测到有循环依赖的情况下才会不为空
			if (earlySingletonReference != null) {
				// 如果exposedObject没有在初始化方法中被改变,也就是没有被增强
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						// 检测依赖
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					// 因为bean创建后其所依赖的bean一定是已经创建了的。actualDependentBeans不为空说明当前bean创建后其依赖的bean却没有全部创建完,也就说说存在循环依赖。
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}
	// 上面调用的 getSingleton 方法。可以知道这里传递的 allowEarlyReference 为false。
	// 因为当前bean在进行循环创建的时候,就已经将 bean缓存到 earlySingletonObjects 中了
	@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;
	}
  • 上面调用的getSingleton()方法。可以知道这里传递的allowEarlyReference为false。因为当前bean在进行循环创建的时候,就已经将 bean缓存到earlySingletonObjects中了

DefaultSingletonBeanRegistry#getSingleton(String beanName, boolean allowEarlyReference)

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 尝试从单例缓存(一级缓存) singletonObjects 中获取完整的Bean。
		Object singletonObject = this.singletonObjects.get(beanName);
		// 如果单例缓存(一级缓存)中没有对象,创建中的Bean的名字会被保存在singletonsCurrentlyInCreation中
		// 也就是说,当前所需要获取的bean是否是singleton的,并且处于创建中的形态
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			// 如果单例缓存中不存在该bean,则加锁进行接下来的处理
			// 这里作为锁还有一个原因是二级缓存和三级缓存都是HashMap,需要一个锁来控制这两个map的操作
			synchronized (this.singletonObjects) {
				// 尝试从二级缓存earlySingletonObjects中获取半成品的Bean, 则直接将singletonObject返回。
				// 二级缓存存储的是未对属性进行添加的Bean.
				singletonObject = this.earlySingletonObjects.get(beanName);
				// 如果还获取不到,并且allowEarlyReference为true,则表示可以进行循环引用
				if (singletonObject == null && allowEarlyReference) {
					// 从三级缓存singletonFactories这个ObjectFactory实例的缓存中尝试获取创建此Bean的单例工厂实例
					// ObjectFactory为用户定制(容器中的代理Bean),FactoryBean框架会进行特殊处理(自定义)
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						// 调用单例工厂的getObject方法获取对象实例
						singletonObject = singletonFactory.getObject();
						// 将实例放入二级缓存中.
						this.earlySingletonObjects.put(beanName, singletonObject);
						// 从三级缓存中删除
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}
  • 删除给定bean名称的单例实例(如果有的话),但前提是该类型仅用于类型检查以外的用途。
    AbstractBeanFactory#removeSingletonIfCreatedForTypeCheckOnly(String beanName)
	protected boolean removeSingletonIfCreatedForTypeCheckOnly(String beanName) {
		if (!this.alreadyCreated.contains(beanName)) {
			removeSingleton(beanName);
			return true;
		}
		else {
			return false;
		}
	}

FactoryBeanRegistrySupport#removeSingleton(String beanName)

	@Override
	protected void removeSingleton(String beanName) {
		synchronized (getSingletonMutex()) {
			super.removeSingleton(beanName);
			this.factoryBeanObjectCache.remove(beanName);
		}
	}

DefaultSingletonBeanRegistry#removeSingleton(String beanName)

	protected void removeSingleton(String beanName) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.remove(beanName);
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.remove(beanName);
		}
	}

整个逻辑如下:

  1. getSingleton(beanName, false); : 从缓存中获取缓存对象,这传递的false, 直接从 earlySingletonObjects中获取循环依赖的对象earlySingletonReference
  2. 如果earlySingletonReference == bean ,说明bean没有被修改,直接赋值即可。
  3. 如果earlySingletonReference != bean ,那么说明 在 下面的代码中,bean被修改了
	populateBean(beanName, mbd, instanceWrapper);
	exposedObject = initializeBean(beanName, exposedObject, mbd);

此时需获取依赖于当前bean的dependentBeans。如果dependentBeans中有已经创建好的,那么则抛出异常

4.7 registerDisposableBeanIfNecessary

这一步的目的是实现destory-method属性,如果bean配置了该属性,则需要注册以便在销毁时调用。

详细代码如下:

	protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
		AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
		if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
			if (mbd.isSingleton()) {
				// Register a DisposableBean implementation that performs all destruction
				// work for the given bean: DestructionAwareBeanPostProcessors,
				// DisposableBean interface, custom destroy method.
				// 单例模式下注册需要销毁的bean,此方法会处理实现DisposableBean的bean
				// 并且对所有的bean使用 DestructionAwareBeanPostProcessor 处理 DisposableBean DestructionAwareBeanPostProcessor
				registerDisposableBean(beanName,
						new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
			}
			else {
				// A bean with a custom scope...
				// 自定义 scope 的处理
				Scope scope = this.scopes.get(mbd.getScope());
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
				}
				scope.registerDestructionCallback(beanName,
						new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
			}
		}
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/30168.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mybatis 源码分析

mybatis 的一些总结 XMLConfigBuilder mybatis 的配置文件解析的能力是交给了XMLCconfigBuilder 去解析的 public SqlSessionFactory build(Reader reader, String environment, Properties properties) {try {XMLConfigBuilder parser new XMLConfigBuilder(reader, envir…

JDK内置命令工具

JDK内置命令工具 jps 作用 查看java进程的pid和全路径主类名和jvm参数 使用 -l : 输出所有正在运行java进程的pid 和主类名-v &#xff1a;输出正在运行java进程的pid和主类名和运行参数 jstack 作用 查看某个java进程当前的堆栈信息&#xff0c; 也就是当前进程中的线程…

NIO与BIO服务器端对比

本文利用NIO实现一个重复回复&#xff0c;客户端发送什么信息&#xff0c;客户端就会收到什么信息。 主要是理解NIO与BIO的区别。客户端采用telnet进行测试&#xff0c;以下连接是Telnet安装的方法。 Telnet的简单使用_武汉小喽啰的博客-CSDN博客_telnet 注意&#xff01;&a…

POSIX信号量

文章目录概念信号量函数基于环形队列的生产消费模型概念 信号量是一个计数器&#xff0c;用来描述临界资源数量的计数器。 每个执行流要进入临界资源时&#xff0c;要先申请信号量&#xff0c;出临界资源时&#xff0c;要释放信号量。 信号量的PV操作 P操作&#xff1a;申请…

万字长文总结分布式事务,总有一款适合你

导语&#xff1a;本文参考网络相关文章&#xff0c;主要总结了XA, 2PC, 3PC, 本地事务状态表, 可靠消息队列, 最大努力通知, TCC, SAGA等分布式事务的特点和适用场景&#xff0c;为大家选择分布式事务提供一些参考。 概述 分布式事务是指事务的参与者、支持事务的服务器、资源…

宝刀未老!阿里P8老兵耗时三年总结出这份Java项目实战文档

文档特点&#xff1a; 为了方便小伙伴们能更好地阅读&#xff0c;我已经提前给大家整理好了学习路线和知识结构 本书综合讲解Java程序设计中的核心技术&#xff0c;全书一共设计为22章&#xff0c;章节结构如下。 需要获取的小伙伴可以直接转发关注后私信&#xff08;学习&…

[Python]Django 配置

文章目录&#x1f349; pycharm中打开Django项目并配置虚拟环境运行项目&#x1f348; 打开项目后pycharm自动识别配置项目运行环境&#x1f34d; 指定项目运行的端口号&#x1f348; 自行配置项目的运行环境&#x1f34d; 配置项目的python解释器&#x1f34d; 配置Django项目…

本地demo服务器搭建计划——(三)rabbitmq配置中心config配置自动刷新

本章内容主要使用Spring Cloud Config来启动一个配置中心服务&#xff0c;通过Spring Cloud Bus消息总线&#xff08;依赖rabbitmq&#xff09;和Git仓库&#xff08;Gitee&#xff09;Webhook钩子函数来实现配置的自动更新&#xff08;push新的配置到gitee仓库时触发&#xff…

【英语口语】单词如何正确发音?

1. 发音基础介绍 音素&#xff1a;元音 辅音 单词&#xff1a;重音 失去爆破 浊化 三单 过去式过去分词 句子&#xff1a;语调 重音 弱读 连读 缩读 段落&#xff1a;意群 元音字母&#xff1a; A、E、I、O、U 2. 音节的定义 英语单词在发音的时候&#xff0c;不是一个字…

GD32F4(9):GD32f4出现上电不工作,必须按复位程序才能跑起来

GD32&#xff1a;上电不工作&#xff0c;需要按一下复位按键程序才能跑起来 文章目录GD32&#xff1a;上电不工作&#xff0c;需要按一下复位按键程序才能跑起来1.问题描述2. 我的调试思路2.1 第一步&#xff0c;排除电源问题2.2 第二步&#xff0c;排除复位电路的问题2.3 第三…

QUIC简介

一、概述、 QUIC&#xff08;Quick udp Internet connection&#xff09;&#xff1a;快速UDP互联网协议。相比于当前广泛应用的http2tcptls有如下优势&#xff1a; 减少三次握手及TLS握手时间&#xff1b;改进拥塞机制&#xff1b;避免队头阻塞的多路复用&#xff1b;连接迁移…

一文了解riscv软件系列之linux内核编译运行

一、交叉编译工具链的安装 【推荐阅读文章】 代码大佬的【Linux内核开发笔记】分享&#xff0c;前人栽树后人乘凉&#xff01; 一篇长文叙述Linux内核虚拟地址空间的基本概括 一文了解Linux内核的Oops 需要多久才能看完linux内核源码&#xff1f; 详细讲解磁盘及文件系统…

【antd vue pro】设置项目默认语言为中文:

文章目录一、官网文档&#xff1a;二、解决&#xff1a;1、在src\locales\index.js文件修改默认语言2、src\core\bootstrap.js文件&#xff0c;修改初始化的语言3、src\store\modules\app.js4、清空本地存储&#xff0c;然后npm run serve重启&#xff1a;5、遇到问题&#xff…

Linux文件权限管理:chomd命令和chown命令

Linux文件权限管理&#xff1a;chomd命令和chown命令前言介绍文件类型文件权限文件所属文件信息chomd命令chown命令前言 在服务器部署项目、安装应用会经常涉及到文件权限的问题&#xff0c;在此记录chomd命令和chown命令它们的用法及区别。 介绍 以下图为例&#xff0c;进行…

如何解决全局工业相机飞拍拖影问题

1.问题描述: 物体静态拍摄时图像正常&#xff0c;但是动态拍摄时会有拖影现象。 2.问题原因&#xff1a; 只要物体存在运动&#xff0c;拍摄就一定会存在拖影&#xff0c;那么如何判断飞拍项目能否使用&#xff1f;拖影是否会对飞拍造成影响呢&#xff1f;这就要看具体的检测…

Viterbi维特比译码误码率仿真,调制为QPSK,信道为高斯白噪声

目录 1.算法描述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法描述 整体思路如图1中所示&#xff0c; 其中输入序列使用randn函数来产生&#xff0c;卷积也采用matlab本身的函数conv&#xff0c;加性高斯白噪声用wgn函数来产生&#xff0c;由于实验的重点…

世上最全NVDIA GPU参数列表: 3090,4090, A40, A30,V100, A100, A800性能参数

-1&#xff09;GeForce RTX 4090 GeForce RTX 4090 GPU 引擎规格&#xff1a;NVIDIA CUDA 核心数量16384加速频率 (GHz)2.52基础频率 (GHz)2.23显存规格&#xff1a;标准显存配置24 GB GDDR6X显存位宽384 位技术支持&#xff1a;Ray Tracing Core第 3 代Tensor Cores第 4 代N…

CRDB-多区域部署

多区域部署允许cockachdb数据库跨越多个地理区域。多区域部署的配置对集群的容错和区域性能有影响。一般来说&#xff0c;我们将一个cockachdb集群配置为多个区域&#xff0c;以实现以下两个目标中的一个或两个&#xff1a; 允许集群在其中一个区域的计算资源不可用时继续服务…

磨金石教育摄影技能干货分享|花朵怎样拍才能不凌乱

喜欢养花种花的朋友&#xff0c;除了享受花朵在自己精心培育下绽放之外&#xff0c;给爱花拍照发在朋友圈炫耀也是一大乐趣之一。 但是别看花朵静静地盛开&#xff0c;娇艳欲滴&#xff0c;想要拍得好看却不是一件容易的事。作为摄影小白常常遇到的情况就是&#xff0c;拍出的花…

即兴发言怎样避免语无伦次?记住这个即兴发言万能公式

作为PMO和项目经理&#xff0c;经常要组织和参与各种会议&#xff0c;在会议中难免需要即兴发言&#xff0c;但是很多人即兴发言时总语无伦次&#xff0c;不知所云&#xff0c;而PMO和项目经理又是依靠外在表现来体现自己的专业性的&#xff0c;这时候就很难获得被人的认可&…