Spring 源码分析四 :bean的加载② - doGetBean详解

1. 转换 beanName

final String beanName = transformedBeanName(name);

这一步的目的是为了去除 beanName 的别名,获取bean的真正beanName。

这里的name传入的可能是 bean的别名,或者是FactoryBean类型的bean。所以需要一系列的解析,解析包括

去除 FactoryBean 的修饰符。也就是说如果 name = “&name” 或者 name = “&&name” 这种多&& 情况也会去除& 使得 name = “name”。
取指定alias所表示的最终beanName。比如别名A指向B的bean,则会返回B。

protected String transformedBeanName(String name) {
		return canonicalName(BeanFactoryUtils.transformedBeanName(name));
	}
	
	....
	// 从别名中获取真正的beanName
	public String canonicalName(String name) {
		String canonicalName = name;
		// Handle aliasing...
		String resolvedName;
		do {
			// 从aliasMap 中获取到真实的beanName
			resolvedName = this.aliasMap.get(canonicalName);
			if (resolvedName != null) {
				canonicalName = resolvedName;
			}
		}
		while (resolvedName != null);
		return canonicalName;
	}

	....
	// BeanFactoryUtils 中
	public static String transformedBeanName(String name) {
		Assert.notNull(name, "'name' must not be null");
		// 如果不是以 & 开头直接返回
		if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
			return name;
		}
		// 否则剪切到 开头的 & ,直至开头没有 &
		return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
			do {
				beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
			}
			while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
			return beanName;
		});
	}

2. 尝试从缓存中加载单例

Object sharedInstance = getSingleton(beanName);

 对于单例Bean来说, Spring只会在同一容器中创建一次,并将创建好的Bean 实例保存到 singletonObjects 中,下次再获取bean实例,直接从 singletonObjects 中获取。
这一步的目的是从尝试从缓存中获取实例。需要注意的是,Spring为了解决循环依赖问题, 在创建bean的原则是不等bean 创建完成就会将创建bean的ObjectFactory提早曝光加入到缓存()中,一旦下一个bean创建时需要依赖上一个bean,则直接使用ObjectFactory。 关于循环依赖的更多问题,请阅衍生篇。

代码逻辑如下:

1.尝试从singletonObjects 中获取Bean 实例。获取不到说明该bean尚未创建成功
2.isSingletonCurrentlyInCreation 返回 true,则说明当前bean 的创建过程存在循环依赖。下面的逻辑就是为了尝试解决循环依赖
3.尝试从 earlySingletonObjects 中获取,获取不到说明该bean并未在创建过程中。(为了解决循环依赖的问题)
4.当 allowEarlyReference = true时,这个是针对循环引用的操作,是允许循环引用。
5.随后 从singletonFactories 中加载 ObjectFactory,并将结果保存到 earlySingletonObjects 中,同时将 singletonFactories 中关于bean的定义移除。(earlySingletonObjects 和 singletonFactories 互斥)
这里我们看到
singletonFactories 的映射关系是 beanName : ObjectFactory
earlySingletonObjects 的映射关系是 beanName : ObjectFactory#getObject
个人理解 earlySingletonObjects 是 singletonFactories 更进一步的缓存,所以二者互斥,相同的对象,一个缓存中存在即可

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 尝试从单例缓存 singletonObjects 中加载。
		Object singletonObject = this.singletonObjects.get(beanName);
		// 单例缓存中没有对象 && 当前单例bean正在创建中,这是为了解决循环依赖的问题
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			// 如果单例缓存中不存在该bean,则加锁进行接下来的处理
			synchronized (this.singletonObjects) {
				// 如果此时bean正在加载(bean 在 earlySingletonObjects 中),则直接将singletonObject 返回。
				singletonObject = this.earlySingletonObjects.get(beanName);
				// allowEarlyReference = true 才会允许循环依赖
				if (singletonObject == null && allowEarlyReference) {
					// 当某些方法需要提前初始化的时候则会调用addSingletonFactory 将对应的ObjectFactory初始化策略存储在singletonFactories中
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						// 调用预先设定的getObject方法
						singletonObject = singletonFactory.getObject();
						// 记录在缓存中,earlySingletonObjects 和 singletonFactories互斥
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

3. 尝试从FactoryBean中获取对象

bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

代码逻辑大体如下:

首先是在 AbstractAutowireCapableBeanFactory#getObjectForBeanInstance 中,添加依赖bean信息。随后跳转到 AbstractBeanFactory#getObjectForBeanInstance 中
判断程序是否想获取 FactoryBean实例(beanName 是否以 & 开头)。如果是判断当前beanInstance是否是 FactoryBean。如果是则返回,否则抛出异常
如果不是想获取FactoryBean,那么就是想获取bean实例了。那么判断此时的beanInstance是普通的bean还是FactoryBean类型,如果是普通的bean则直接返回。
此时beanInstance 必定是 FactoryBean类型并且程序想获取bean实例。那么首先尝试从缓存 factoryBeanObjectCache 中获取。获取失败,则调用FactoryBean#getObject 方法来获取bean实例。并且在允许调用后置方法的情况下(shouldPostProcess 为true),调用BeanPostProcessor#postProcessAfterInitialization 的方法。

下面我们来看详细代码

3.1 AbstractAutowireCapableBeanFactory#getObjectForBeanInstance
首先调用的是 AbstractAutowireCapableBeanFactory#getObjectForBeanInstance
 

private final NamedThreadLocal<String> currentlyCreatedBean = new NamedThreadLocal<>("Currently created bean");

	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
		// 获取当前线程正在创建的bean。currentlyCreatedBean 是一个 ThreadLocal
		String currentlyCreatedBean = this.currentlyCreatedBean.get();
		// 如果当前线程正在创建其他bean,则说明currentlyCreatedBean  的创建依赖于 beanName。则去保存这个依赖关系
		if (currentlyCreatedBean != null) {
			registerDependentBean(beanName, currentlyCreatedBean);
		}

		return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd);
	}

	....
	// 注册依赖关系的bean
	public void registerDependentBean(String beanName, String dependentBeanName) {
		// 获取真实的beanName
		String canonicalName = canonicalName(beanName);
		// 保存依赖关系。dependentBeanMap: key 被 value 依赖
		synchronized (this.dependentBeanMap) {
			Set<String> dependentBeans =
					this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
			if (!dependentBeans.add(dependentBeanName)) {
				return;
			}
		}
		// dependenciesForBeanMap : key 依赖于bean
		synchronized (this.dependenciesForBeanMap) {
			Set<String> dependenciesForBean =
					this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
			dependenciesForBean.add(canonicalName);
		}
	}

 3.2 AbstractBeanFactory#getObjectForBeanInstance
随后通过super.getObjectForBeanInstance(beanInstance, name, beanName, mbd); 调用了 AbstractBeanFactory#getObjectForBeanInstance

protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		// 1. 检测name 是否是想获取 工厂类 (name 以 & 开头) 
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			// 以&开头又不是FactoryBean实现类,则抛出异常
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
			if (mbd != null) {
				mbd.isFactoryBean = true;
			}
			return beanInstance;
		}

		// 2. 此时bean可能是 FactoryBean 或者 普通的bean。判断如果 beanInstance 不是 FactoryBean而是普通的bean, 就直接返回
		if (!(beanInstance instanceof FactoryBean)) {
			return beanInstance;
		}
		// 3. 到这一步就可以确定,当前beanInstance 是FactoryBean,并且需要获取getObject() 的结果
		Object object = null;
		if (mbd != null) {
			mbd.isFactoryBean = true;
		}
		else {
			// 尝试从缓存中加载bean。这一步是从 factoryBeanObjectCache 集合中获取
			// 在后面获取 bean 成功后,可能会将 其缓存到 factoryBeanObjectCache  中
			object = getCachedObjectForFactoryBean(beanName);
		}
		
		if (object == null) {
			// Return bean instance from factory.
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// containsBeanDefinition 检测  beanDefinitionMap中也就是所有已经加载的类中检测是否定义beanName
			if (mbd == null && containsBeanDefinition(beanName)) {
				// 合并父类bean 定义的属性
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			// 4. 这一步中对FactoryBean进行了解析。
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

3.2.1 doGetObjectFromFactoryBean

getObjectFromFactoryBean 方法中 调用 doGetObjectFromFactoryBean 方法来获取 FactoryBean 中的 bean实例。下面我们来看一下getObjectFromFactoryBean 代码:

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		// 判断是否是单例模式 && singletonObjects 尚未缓存该bean (containsSingleton调用的是 singletonObjects )
		if (factory.isSingleton() && containsSingleton(beanName)) {
			synchronized (getSingletonMutex()) {
				// 尝试从 factoryBeanObjectCache 缓存中获取
				Object object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
					// 在这个方法中进行解析。调用 FactoryBean 的 getObject 方法
					object = doGetObjectFromFactoryBean(factory, beanName);

					// 因为是单例模式,所以要保证变量的全局唯一。所以这里如果缓存中已经创建好了bean则替换为已经创建好的bean
					Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
					if (alreadyThere != null) {
						object = alreadyThere;
					}
					else {
						// 如果允许调用bean的后置处理器。因为这里是直接将bean创建返回了,如果要调用后置方法则只能在这里调用。
						if (shouldPostProcess) {
							if (isSingletonCurrentlyInCreation(beanName)) {
								// Temporarily return non-post-processed object, not storing it yet..
								return object;
							}
							// 将beanName 添加到 singletonsCurrentlyInCreation 中缓存,表示当前bean正在创建中
							beforeSingletonCreation(beanName);
							try {
								// 调用了ObjectFactory的后置处理器。
								object = postProcessObjectFromFactoryBean(object, beanName);
							}
							catch (Throwable ex) {
								throw new BeanCreationException(beanName,
										"Post-processing of FactoryBean's singleton object failed", ex);
							}
							finally {
							// 将beanName 从 singletonsCurrentlyInCreation 中移除,表示当前bean已经创建结束
								afterSingletonCreation(beanName);
							}
						}
						// return this.singletonObjects.containsKey(beanName); 如果 singletonObjects缓存中存在当前beanName,则将其缓存到 factoryBeanObjectCache 中。
						if (containsSingleton(beanName)) {
							// 这里保存的是 beanName : FactoryBean
							this.factoryBeanObjectCache.put(beanName, object);
						}
					}
				}
				return object;
			}
		}
		else {
			// FactoryBean 非单例直接调用 getObject 方法
			Object object = doGetObjectFromFactoryBean(factory, beanName);
			// 如果允许调用后置方法,则调用postProcessObjectFromFactoryBean 方法
			if (shouldPostProcess) {
				try {
					object = postProcessObjectFromFactoryBean(object, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
				}
			}
			return object;
		}
	}

4. 原型模式的依赖检查 - isPrototypeCurrentlyInCreation

if (isPrototypeCurrentlyInCreation(beanName)) {
		throw new BeanCurrentlyInCreationException(beanName);
	}

在衍生篇中对循环依赖有过结介绍,简而言之就是 单例模式下才会尝试去解决循环依赖的问题,而原型模式则无法解决。也就是 isPrototypeCurrentlyInCreation 返回true,则抛出异常。
需要注意的是还有一个 方法是 判断单例模式的依赖检查 : isSingletonCurrentlyInCreation

5. 递归 parentBeanFactory
这一步的逻辑比较简单,如下:

首先通过 containsBeanDefinition(beanName) 方法判断当前beanFactory中是否有bean的定义,如果有,皆大欢喜。直接进入下一步。
如果没有,且 parentBeanFactory 不为空,则会通过递归的方式,尝试从 parentBeanFactory 中加载bean定义。
 

// 5. 如果 beanDefinitionMap 中也就是在所有已经加载的类中不包含beanName,则尝试从parentBeanFactory中检测
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				// 递归到BeanFactory中检测
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}

其中 DefaultListableBeanFactory#containsBeanDefinition 代码如下 

@Override
	public boolean containsBeanDefinition(String beanName) {
		Assert.notNull(beanName, "Bean name must not be null");
		return this.beanDefinitionMap.containsKey(beanName);
	}

6. 合并 BeanDefinition 

BeanDefinition 顾名思义,就是关于bean 的定义信息。通过xml的bean定义可以很清楚的看到一些属性定义。

所以这一步就是检查当前 BeanDefinition 是否有父BeanDefinition ,如果有将一些属性和当前bean合并,生成一个 RootBeanDefinition。

final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
		checkMergedBeanDefinition(mbd, beanName, args);

这一块的调用链路:getMergedLocalBeanDefinition -> getMergedBeanDefinition -> getMergedBeanDefinition。所以我们 这里直接来看 getMergedBeanDefinition 方法。

首先,mbd 即 MergedBeanDefinition 的缩写,即一个合并的beanDefinition。

// 如果给定bean的定义是子bean定义,则通过与父级合并返回RootBeanDefinition。
	protected RootBeanDefinition getMergedBeanDefinition(
			String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
			throws BeanDefinitionStoreException {
		
		synchronized (this.mergedBeanDefinitions) {
			RootBeanDefinition mbd = null;
			RootBeanDefinition previous = null;

			// Check with full lock now in order to enforce the same merged instance.
			if (containingBd == null) {
				mbd = this.mergedBeanDefinitions.get(beanName);
			}

			if (mbd == null || mbd.stale) {
				previous = mbd;
				// 判断如果parentName为空则没必要进行合并了,直接克隆返回即可
				if (bd.getParentName() == null) {
					// Use copy of given root bean definition.
					if (bd instanceof RootBeanDefinition) {
						mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
					}
					else {
						mbd = new RootBeanDefinition(bd);
					}
				}
				else {
					// Child bean definition: needs to be merged with parent.
					BeanDefinition pbd;
					try {
						// 转换beanName
						String parentBeanName = transformedBeanName(bd.getParentName());
						// 递归调用,解析更上层的parent BeanDefinition 
						if (!beanName.equals(parentBeanName)) {
							pbd = getMergedBeanDefinition(parentBeanName);
						}
						else {
							BeanFactory parent = getParentBeanFactory();
							if (parent instanceof ConfigurableBeanFactory) {
								pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
							}
							else {
								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);
					}
					// Deep copy with overridden values.
					// 深拷贝
					mbd = new RootBeanDefinition(pbd);
					mbd.overrideFrom(bd);
				}

				// Set default singleton scope, if not configured before.
				if (!StringUtils.hasLength(mbd.getScope())) {
					mbd.setScope(SCOPE_SINGLETON);
				}

				if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
					mbd.setScope(containingBd.getScope());
				}

				// Cache the merged bean definition for the time being
				// (it might still get re-merged later on in order to pick up metadata changes)
				if (containingBd == null && isCacheBeanMetadata()) {
					this.mergedBeanDefinitions.put(beanName, mbd);
				}
			}
			if (previous != null) {
				copyRelevantMergedBeanDefinitionCaches(previous, mbd);
			}
			return mbd;
		}
	}

7. 寻找依赖

这一步也是针对 BeanDefinition 的 dependsOn 属性来说的(对应注解则是 @DependsOn。主要是 优先加载Bean 的 depends-on依赖。

注:
在 BeanDefinition 加载过程中,通过扫描路径加载的时候,通过 ClassPathBeanDefinitionScanner#doScan方法时会调用AnnotationConfigUtils#processCommonDefinitionAnnotations 来进行BeanDefinition 封装,其中就包含了诸多注解的解析,如下:
在这里插入图片描述

因为bean 的初始化过程中很可能会用到某些属性,而某些属性很可能是动态配置的,并且配置成依赖于其他的bean,那么这个时候就有必要先加载依赖的bean,所以,在Spring的加载顺寻中,在初始化某一个bean的时候首先会初始化这个bean所对应的依赖。

// 获取依赖项
		String[] dependsOn = mbd.getDependsOn();
		if (dependsOn != null) {
			for (String dep : dependsOn) {
				// 判断是否有循环依赖的情况 : A依赖B,B依赖A
				if (isDependent(beanName, dep)) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
				}
				// 注册依赖信息,将依赖信息保存到 dependentBeanMap、dependenciesForBeanMap中
				registerDependentBean(dep, beanName);
				try {
					// 获取依赖的bean,这一步又回到了最初的getBean
					getBean(dep);
				}
				catch (NoSuchBeanDefinitionException ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
				}
			}
		}

 下面我们来看一看 isDependent(beanName, dep) 的处理逻辑

private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
		// 是否已经检测过了,上层一直是null
		if (alreadySeen != null && alreadySeen.contains(beanName)) {
			return false;
		}
		// 格式化beanName
		String canonicalName = canonicalName(beanName);
		// 获取 依赖于 beanName 的 bean集合
		Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
		if (dependentBeans == null) {
			return false;
		}
		// 如果 依赖于 beanName中存在 dependentBeanName 则说明存在循环依赖。
		// 代码走到这里说明是beanName 创建过程中要依赖 dependentBeanName。但是dependentBeans.contains(dependentBeanName) = true 则说明dependentBeanName依赖于beanName
		// 造成了 A依赖B,B依赖A的情况
		if (dependentBeans.contains(dependentBeanName)) {
			return true;
		}
		// 递归,确定没有A->B->C-A 这种长链路的循环依赖情况
		for (String transitiveDependency : dependentBeans) {
			if (alreadySeen == null) {
				alreadySeen = new HashSet<>();
			}
			alreadySeen.add(beanName);
			if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
				return true;
			}
		}
		return false;
	}

 注:
@DependsOn:注解是在另外一个实例创建之后才创建当前实例,也就是,最终两个实例都会创建,只是顺序不一样
@ConditionalOnBean :注解是只有当另外一个实例存在时,才创建,否则不创建,也就是,最终有可能两个实例都创建了,有可能只创建了一个实例,也有可能一个实例都没创建
8. bean创建

上面这么多逻辑,都是准备工作。确定缓存中没有当前bean,并且当前bean的创建合法。准备开始创建。不过这里考虑到不同的 Scope,所以针对不同的Scope进行不同的初始化操作。创建bean 的过程也很复杂。

下面代码就是根据 Singleton、Prototype 或者其他Scope 走不同的流程创建bean。

关于 bean 创建的过程 getSingleton ,请阅Spring源码分析五 :bean的获取③ - getSingleton

9. 类型转换
到这里整个流程基本就结束了。通常对该方法的调用参数 requiredType 是null,。但某些情况可能会出现返回的bean是个String类型,但是requiredType 传入的却是Integer类型,这时候就会触发这一步的操作,将String类型转换为Integer类型。
 

if (requiredType != null && !requiredType.isInstance(bean)) {
		try {
			T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
			if (convertedBean == null) {
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
			return convertedBean;
		}
		catch (TypeMismatchException ex) {
			if (logger.isTraceEnabled()) {
				logger.trace("Failed to convert bean '" + name + "' to required type '" +
						ClassUtils.getQualifiedName(requiredType) + "'", ex);
			}
			throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
		}
	}

 


        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值