Spring 源码分析三 :bean的加载① - doGetBean概述

在 Spring源码分析一:容器的刷新 - refresh() 文章中分析了Spring容器的刷新过程。我们知道了 Spring 在容器刷新的后期 通过调用AbstractApplicationContext#finishBeanFactoryInitialization 方法来实例化了所有的非惰性bean。在这里面就通过 beanFactory.preInstantiateSingletons(); 调用了一个非常关键的方法 AbstractBeanFactory#getBean(java.lang.String),而其实际上调用的是 AbstractBeanFactory#doGetBean 方法

@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

如果说,Spring中,Bean 的发现是在 ConfigurationClassPostProcessor 中进行的。那么Bean的创建就是在 doGetBean方法中进行的。 doGetBean 完成了单例Bean的完整创建过程,包括bean的创建,BeanPostProcessor 的方法调用、init-method等方法的调用、Aware 等接口的实现。
下面,我们开始来分析这个 doGetBean。

关于Bean 的加载过程,AbstractApplicationContext#finishBeanFactoryInitialization 经过几次跳转,最终会跳转到 AbstractBeanFactory#doGetBean 方法。每个bean的创建都会经历此方法,所以本文的主要内容是分析 AbstractBeanFactory#doGetBean 。

二、DefaultListableBeanFactory

需要强调的是,本文中调用 doGetBean 方法的是 AbstractBeanFactory 的子类DefaultListableBeanFactory。如下图

在这里插入图片描述

DefaultListableBeanFactory 结构图如下:

在这里插入图片描述 注意这里说的 BeanFactory 并不是指 ApplicationContext,而是 ApplicationContext 内部的一个BeanFactory 。对 Springboot 来说,Springboot 默认的上下文是 AnnotationConfigServletWebServerApplicationContext,AnnotationConfigServletWebServerApplicationContext 内部还有一个单独的BeanFactory对象(DefaultListableBeanFactory)。虽然 AnnotationConfigServletWebServerApplicationContext 也实现了 BeanFactory接口,但是实际上对于一般的BeanFactory 请求是AnnotationConfigServletWebServerApplicationContext 直接委托给内部的 BeanFactory来解决。 而这里所说的BeanFactory实际上是 AnnotationConfigServletWebServerApplicationContext 内部的 DefaultListableBeanFactory。
大体如下,其中我们主要只需要关注前四个即可:


	/** Cache of singleton objects: bean name to bean instance. */
	//	用于保存BeanName和创建bean实例之间的关系,即缓存bean。 beanname -> instance 
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** Cache of singleton factories: bean name to ObjectFactory. */
	// 用于保存BeanName和常见bean的工厂之间的关系。beanname-> ObjectFactory
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/** Cache of early singleton objects: bean name to bean instance. */
	// 也是保存BeanName和创建bean实例之间的关系,与singletonObjects 不同的是,如果一个单例bean被保存在此,则当bean还在创建过程中(比如 A类中有B类属性,当创建A类时发现需要先创建B类,这时候Spring又跑去创建B类,A类就会添加到该集合中,表示正在创建),就可以通过getBean方法获取到了,其目的是用来检测循环引用。
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

	/** Set of registered singletons, containing the bean names in registration order. */
	// 用来保存当前所有已经注册的bean
	private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

	/** Names of beans that are currently in creation. */
	// 用来保存当前正在创建的Bean。也是为了解决循环依赖的问题
	private final Set<String> singletonsCurrentlyInCreation =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));

	/** Names of beans currently excluded from in creation checks. */
	// 用来保存当前从创建检查中排除的bean名称
	private final Set<String> inCreationCheckExclusions =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));

	/** List of suppressed Exceptions, available for associating related causes. */
	// 初始化过程中的异常列表
	@Nullable
	private Set<Exception> suppressedExceptions;

	/** Flag that indicates whether we're currently within destroySingletons. */
	// 标志是否在销毁BeanFactory过程中
	private boolean singletonsCurrentlyInDestruction = false;

	/** Disposable bean instances: bean name to disposable instance. */
	// 一次性bean实例:beanName -> 一次性实例。暂未明白
	private final Map<String, Object> disposableBeans = new LinkedHashMap<>();

	/** Map between containing bean names: bean name to Set of bean names that the bean contains. */
	// 包含的Bean名称之间的映射:BeanName  -> Bean包含的BeanName集合
	private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);

	/** Map between dependent bean names: bean name to Set of dependent bean names. */
	// bean dependent(依赖的集合) : beanName -> 依赖该beanName 的 bean,即 key代表的bean 被value 所依赖
	private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

	/** Map between depending bean names: bean name to Set of bean names for the bean's dependencies. */
	// bean 被哪些bean依赖 :  beanName -> beanName 所依赖的 bean。即 key 依赖于value这些bean
	private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);

1.1 关键缓存
下面挑出来几个关键缓存集合来描述:

singletonObjects :ConcurrentHashMap。最简单最重要的缓存Map。保存关系是 beanName :bean实例关系。单例的bean在创建完成后都会保存在 singletonObjects 中,后续使用直接从singletonObjects 中获取。
singletonFactories :HashMap。这是为了解决循环依赖问题,用于提前暴露对象,保存形式是 beanName : ObjectFactory<?>。
earlySingletonObjects :HashMap。这也是为了解决循环依赖问题。和 singletonFactories 互斥。因为 singletonFactories 保存的是 ObjectFactory。而earlySingletonObjects 个人认为是 singletonFactories 更进一步的缓存,保存的是 ObjectFactory#getObject的结果。
registeredSingletons :LinkedHashSet,用于保存注册过的beanName,
singletonsCurrentlyInCreation : 保存当前正在创建的bean。当一个bean开始创建时将保存其beanName,创建完成后将其移除
dependentBeanMap :保存bean的依赖关系,比如A对象依赖于 B对象,会出现 B :A。即保存的是key 被value依赖
dependenciesForBeanMap :保存bean的依赖关系,不过和dependentBeanMap 反了过来。A对象依赖于 B对象,会出现 A :B。保存的是key 依赖于 value

我们拿一个简单的场景解释一下 singletonFactories 和 earlySingletonObjects 的关系 。
下面的代码是 DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean) 。我们可以看到其判断逻辑,

锁定 singletonObjects,毕竟要操作 singletonObjects

从 singletonFactories 中获取 ObjectFactory 缓存

如果存在 ObjectFactory 缓存,则更进一步提取ObjectFactory#getObject 的singletonObject 对象。将singletonObject 保存到 earlySingletonObjects 缓存中,同时从 singletonFactories 中移除。

@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;
	}

1.2 图解

补上一张图,来看一看 A,B循环依赖 singletonFactories 和 earlySingletonObjects 的变化

在这里插入图片描述

 个人推测 : 在创建过程中会被添加到 singletonFactories 中,但当bean被循环依赖时会被添加到 earlySingletonObjects 中。也即是说 earlySingletonObjects 中的bean都是被循环依赖的。

2. BeanDefinition
这里简单介绍一下,顾名思义,BeanDefinition是bean的信息,一个BeanDefinition 描述和定义了创建一个bean需要的所有信息,属性,构造函数参数以及访问它们的方法。还有其他一些信息,比如这些定义来源自哪个类等等。

对于XML 配置方式的Spring方式来说, BeanDefinition 是配置文件 < bean > 元素标签在容器中的内容表示形式。<bean> 元素标签拥有class、scope、lazy-init等配置属性,BeanDefinition 则提供了相应的beanClass、scope、lazyinit属性,BeanDefinition 和 <bean> 中的属性是一一对应的。其中RootBeanDefinition 是最常用的实现类,一般对应< bean > 元素标签。

类似下图的定义:

在这里插入图片描述

需要注意的是 BeanDefinition 是一个接口,在Spring 中存在多种实现,具体请参考:https://blog.csdn.net/andy_zhang2007/article/details/85381148
https://www.cnblogs.com/loongk/p/12262101.html。

三、doGetBean 概述

下面我们开始进入正题,进行 AbstractBeanFactory#doGetBean的内容分析。这个方法是一切的核心(Bean的创建过程也是在这个方法中完成)。首先我们先来整体过一遍方法代码。后面将会对一些关键点进行详细解释。

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
		// 1. 提取出对应的beanName。会去除一些特殊的修饰符比如 "&"
		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		// 2. 尝试从缓存获取或者singletonFacotries中的ObjectFactory中获取。后续细讲
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			... 打印日志
			// 3. 返回对应的实例,有时候存在诸如BeanFactory的情况并不直接返回实例本身,而是返回指定方法返回的实例。这一步主要还是针对FactoryBean的处理。
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
		else {
			// 4. 只有单例情况才会尝试解决循环依赖,原型模式直接抛出异常。因为原型模式无法解决循环依赖问题。参考衍生篇关于循环依赖的内容
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
			// 获取父级的 BeanFactory
			BeanFactory parentBeanFactory = getParentBeanFactory();
			// 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);
				}
			}
			// 如果不仅仅做类型检查则是创建bean,这里需要记录
			if (!typeCheckOnly) {
				// 这里是将 当前创建的beanName 保存到 alreadyCreated 集合中。alreadyCreated 中的bean表示当前bean已经创建了,在进行循环依赖判断的时候会使用
				markBeanAsCreated(beanName);
			}

			try {
				// 6. 将当前 beanName 的 BeanDefinition 和父类BeanDefinition 属性进行一个整合
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				// 7. 寻找bean的依赖
                // 获取初始化的依赖项
				String[] dependsOn = mbd.getDependsOn();
				// 如果需要依赖,则递归实例化依赖bean
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						// 缓存依赖调用
						registerDependentBean(dep, beanName);
						try {
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// Create bean instance.
                // 8 针对不同的Scope 进行bean的创建
				// 实例化依赖的bean便可以实例化mdb本身了
				// singleton 模式的创建
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				else if (mbd.isPrototype()) {
					// Prototype 模式的创建
					// 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);
				}

				else {
					String scopeName = mbd.getScope();
					// 指定scope上实例化bean
					final Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						throw new BeanCreationException(beanName,
								"Scope '" + scopeName + "' is not active for the current thread; consider " +
								"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
								ex);
					}
				}
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}

		// Check if required type matches the type of the actual bean instance.
        // 9 类型转换
		// 检查需要的类型是否符合bean 的实际类型
		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());
			}
		}
		return (T) bean;
	}

综上所属,doGetBean的 大体流程如下:

将传入的beanName 转化为合适的beanName。因为这里可能传入bean的别名,比如 FactoryBean 这里就是传入 “&beanName” , 这一步就会将其转化为 “beanName”
尝试从单例缓存中获取 bean,主要是尝试从 singletonObjects 和 singletonFactories 中获取实例。(这一步中还使用了 earlySingletonObjects 来判断循环依赖的问题)
如果第二步获取到了bean,则会针对处理 FactoryBean 这种特殊情况,以获取到正确的bean。(因为Factorybean 的话可能需要将其 getObject 方法的返回值作为bean注入到容器中)。
如果第二步没有获取到bean,则会检测其原型模式下的循环依赖情况,如果原型模式下有循环依赖,则直接抛出异常,因为原型模式下无法解决循环依赖。
如果第四步没有抛出异常,则会判断 当前BeanFactory 中是否包含该beanName 的定义信息,如果不包含,则会递归去 parentBeanFactory 中去寻找beanName的定义信息.
随后查询beanName 的 BeanDefinition 是否具有 父类的BeanDefinition, 如果有,则将 父类的一些属性和子类合并,形成一个新的BeanDefinition : mdb
获取mdb中的 depends-on 属性,优先将依赖的bean创建,随后再创建当前bean。
到这一步,则说明当前bean尚未创建,则会根据 singleton 或者 prototype 或其他逻辑,走不同的流程来创建bean
创建bean结束后,根据调用者需要的类型进行一个类型转换。比如调用者希望返回一个Integer,这里得到的结果却是String,则会进行一个类型的转换。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值