[Spring]Spring的getBean路线-doGetBean

188 阅读12分钟

doGetBean的总体流程

  • 尝试从缓存中获取Bean.
  • 判断是否有循环依赖.
  • 判断能否从当前容器获取Bean,不能则递归从父容器中获取.
  • 合并BeanDefiniton,并检查BeanDefiniton,作为createBean的材料.
  • 根据声明的DependsOn去实例化需要提前实例化的Bean.
  • 根据不同的Scope:single、prototype、其他scope使用不同的创建Bean策略.
  • 对Bean做类型检查.

1. 尝试从缓存中获取Bean

	protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {
		// 返回Bean名称,必要时去除工厂取消引用前缀,并将别名解析为规范名称
		// 通过三种形式获取beanName.
		// 1. 原始的beanName.2. FactoryBean->&beanName. 3. alias
		String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		// 尝试从单例缓存集合中获取bean实例
		Object sharedInstance = getSingleton(beanName);
		// 省略....
}

要从缓存中获取Bean,首先要转换出真正的beanName.
我们注册在Spring中的Bean,其名称有三种形式:

  1. beanName.即Bean本身持有的名称,如UserDao这个Bean,Spring会自动为其生成"userDao".
  2. alias.别名,如果你想指定Bean的名称,可以在@Bean中指定该Bean的别名.示例: @Bean({"personC", "Kobe"})
  3. FactoryBean.容器工厂的Bean,对这类Bean会返回其实现类中的getObject对象.名称通常为"&beanName".
    Spring通过transformedBeanName来转换出beanName:
    如果是beanName,返回beanName.
    如果是别名,返回beanName.
    如果是FactoryBean,并且传入的beanName以("&beanName")的形式,返回beanName.
    当获取到beanName后,Spring尝试从缓存中获取bean实例.
  • DefaultSingletonBeanRegistry#getSingleton
	@Override
	@Nullable
	public Object getSingleton(String beanName) {
	    // 第二个参数为是否允许立即加载,这里传入的是true
		return getSingleton(beanName, true);
	}

2. Spring的三级缓存

  • singletonObjects: 存储完整的Bean.
  • earlySingletonObjects: 半成品的Bean,未进行属性赋值.
  • singletonFactories: 提前暴露的对象实例,仅仅做了实例化,未具备属性.
	/** Cache of singleton objects: bean name to bean instance. */
	/** 一级缓存:单例对象缓存池,beanName->Bean,其中存储的是完整的Bean.*/
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** Cache of singleton factories: bean name to ObjectFactory.<br>
	 *  三级缓存:单例工厂的缓存,beanName->ObjectFactory,添加进去的时候实例未具备属性.<br>
	 *  用于保存beanName和创建Bean工厂之间的关系map,单例Bean在创建之初过早暴露出去的Factory.<br>
	 *  为什么采用工厂方法,是因为有些Bean是需要被代理的,总不能把代理前的暴露出去那就毫无意义了.<br>
	 * */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/** Cache of early singleton objects: bean name to bean instance.<br>
	 * 早期的单例对象,beanName->ObjectFactory,存储的是实例化后,属性未赋值的单例对象.<br>
	 * 执行了工厂方法生产出来的bean被放进去之后.<br>
	 * 那么当bean在创建过程中,就可以通过getBean方法获取到.<br>
	 * */

	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

3.从三级缓存中获取对象实例

  • DefaultSingletonBeanRegistry#getSingleton
	/**
	 * Return the (raw) singleton object registered under the given name.
	 * <p>Checks already instantiated singletons and also allows for an early
	 * reference to a currently created singleton (resolving a circular reference).<br>
	 * 返回以给定名称注册的(原始)单例对象。<br>
	 * 检查已经实例化的单例,并且还允许对当前创建的单例的早期引用(解析循环引用)。<br>
	 * 单例对象只能存在三级缓存中的某一级,此处会尝试从一级、二级、三级中进行获取.<br>
	 * @param beanName the name of the bean to look for
	 * @param allowEarlyReference whether early references should be created or not
	 * @return the registered singleton object, or {@code null} if none found
	 */
	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 尝试从一级缓存中获取完整的Bean
		Object singletonObject = this.singletonObjects.get(beanName);
		// 如果完整的单例Bean没有被创建出来,创建中的Bean的名字会被保存在singletonsCurrentlyInCreation中
		// 也就是说,当前所需要获取的bean是否是singleton的,并且处于创建中的形态
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			// 同步锁,开始对缓存对象进行操作.
			// 这里作为锁还有一个原因是二级缓存和三级缓存都是HashMap,需要一个锁来控制这两个map的操作
			synchronized (this.singletonObjects) {
				// 尝试从二级缓存earlySingletonObjects中获取半成品的Bean。
				// 二级缓存存储的是未对属性进行添加的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;
	}

Spring默认支持循环依赖,在这个getSingleton()中,根据beanName去一级、二级、三级缓存中进行查找:

  1. 尝试从一级缓存中查找完整的Bean实例,找到则直接返回.
  2. 如果无法从一级缓存中查找,对一级缓存进行上锁,然后尝试从二级缓存中查找半成品的Bean.找到直接返回.
  3. 从三级缓存中查找,找到则放入二级缓存,同时为了保证一个对象实例为单例,将该实例从第三级缓存中进行移除.

4. 检测循环依赖.

protected <T> T doGetBean(
		String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
		throws BeansException {
	// 省略若干代码....
	
	// 尝试从单例缓存集合中获取bean实例
	Object sharedInstance = getSingleton(beanName);
	// 如果之前已经创建过该单例bean,并且args为空(单例 bean不可以用这个args,它是为多例设计的)
	if (sharedInstance != null && args == null) {
		if (logger.isTraceEnabled()) {
			// 如果Bean还在创建中,则说明是循环依赖.
			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,直接返回,如果是factoryBean,则返回它的getObject.
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
	
	// 省略若干代码....
}

尝试从缓存中获取对象实例后,如果该共享对象实例不为空且参数为空,那么进行循环依赖的检测:
1.如果该beanName出现在singletonsCurrentlyInCreation中,那么证明是循环依赖.
2.否则为缓存的Bean实例.
通过getObjectForBeanInstance返回对象实例.该方法会判断bean是否为FactoryBean,则通过其getObject获取Bean实例:
在访问FactoryBean的过程中,先从FactoryBean缓存中获取(单例模式下,仅存在一个FactoryBean),如果没有则调用其getObject方法,此处Spring使用了双重检测锁机制来创建FactoryBean.值得一读.

	protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		if (factory.isSingleton() && containsSingleton(beanName)) {
			// 上同步锁
			synchronized (getSingletonMutex()) {
				// 双重检测锁机制,先从缓存中获取,多线程下可能别的线程已完成该单例Bean的创建.
				Object object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
					// 调用getObject工厂方法创建Bean实例
					object = doGetObjectFromFactoryBean(factory, beanName);
					// Only post-process and store if not put there already during getObject() call above
					// (e.g. because of circular reference processing triggered by custom getBean calls)
					// 如果在getObject期间别的线程异步进行了bean的创建,那么使用更早的版本,以保证单例
					// 为什么出现两次从缓存读取的操作,因为用户自定义的getObject可能会出现异步,所以这里需要再进行一次判断
					Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
					if (alreadyThere != null) {
						object = alreadyThere;
					}
					else {
						// Spring的内部类不会进入到这个方法,因为Spring不允许第三方框架通过后置处理器更改其内部类
						if (shouldPostProcess) {
							// 该Bean实例是否有别的线程在尝试创建,但是未进行后置处理
							if (isSingletonCurrentlyInCreation(beanName)) {
								// Temporarily return non-post-processed object, not storing it yet..
								return object;
							}
							// 后置处理完成前,先加入缓存中锁定起来
							beforeSingletonCreation(beanName);
							try {
								// 触发BeanPostProcessor.第三方框架可以使用AOP来包装Bean实例
								// 对Bean实施创建上的后置处理
								object = postProcessObjectFromFactoryBean(object, beanName);
							}
							catch (Throwable ex) {
								throw new BeanCreationException(beanName,
										"Post-processing of FactoryBean's singleton object failed", ex);
							}
							finally {
								// 锁定解除
								afterSingletonCreation(beanName);
							}
						}
						if (containsSingleton(beanName)) {
							// 放入缓存中,证明单例已经创建完成了.
							this.factoryBeanObjectCache.put(beanName, object);
						}
					}
				}
				return object;
			}
		}
		else {
			// 非单例直接getObject
			Object object = doGetObjectFromFactoryBean(factory, beanName);
			if (shouldPostProcess) {
				try {
					object = postProcessObjectFromFactoryBean(object, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
				}
			}
			return object;
		}
	}

5.如果从缓存中获取不到Bean实例,开始着手创建Bean.

// 如果scope->prototype,singleton.但是在缓存中无法找到
		else {
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			// 如果scope为prototype并且仍然处于创建的状态,那么可以认为是处于循环依赖中了.
			// 针对prototype的循环依赖,spring无法解决,此处会抛出异常
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
			BeanFactory parentBeanFactory = getParentBeanFactory();
			// 如果在当前容器中无法找到指定名称的bean,此时递归去parentFactory查找.
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				// 针对FactoryBean,将Bean的&重新拼上
				String nameToLookup = originalBeanName(name);
				// 如果parentBeanFactory属于AbstractBeanFactory实例
				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.
					// 如果没有参数,委托父级容器根据指定名称和type进行查找
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					// 委派父级容器根据指定名称查找.
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}

			if (!typeCheckOnly) {
				// 如果不是仅仅做类型检测则创建bean
				markBeanAsCreated(beanName);
			}

			try {
				// 将父类的BeanDefinition与子类的BeanDefinition进行合并覆盖
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				// 对合并的BeanDefiniton进行检测,主要判断是否为abstract.
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				// 获取当前Bean所有依赖的Bean名称
				String[] dependsOn = mbd.getDependsOn();
				// 如果当前Bean设置了dependsOn的属性(用来指定Bean初始化即销毁时的顺序)
				// <bean id = A ,Class = "xxx.xxx.A" depends-on = "B">
				// <bean id = B ,Class = "xxx.xxx.B">
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						// 检测该依赖是否已经注册给当前Bean
						// A-dependsOn-B
						// B-dependsOn-A
						// 如果是这种情况,直接抛出异常
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						// 缓存依赖调用,dep->被依赖的beanName
						registerDependentBean(dep, beanName);
						try {
							// 递归调用getBean,注册Bean之间的依赖(C->B->A)
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// Create bean instance.
				// 如果BeanDefiniton为单例
				if (mbd.isSingleton()) {
					// 匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
					// 关键方法:单例类实例化的入口
					sharedInstance = getSingleton(beanName, () -> {
						try {
							// 创建单例bean的入口.
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							// 显性从单例缓存中删除bean实例.
							// 因为单例模式下为了解决循环依赖,可能留有残余的信息,此处进行销毁
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
  1. 在真正的创建单例Bean之前,Spring会先检查当前beanName是否在prototypesCurrentlyInCreation中,prototypesCurrentlyInCreation是一个ThreadLocal的Set集合,其中存储了当前正在创建的多例BeanName集合,Spring不支持prototye作用域的循环依赖,所以会抛出一个BeanCurrentlyInCreationException.
  2. 向上递归获取父容器,尝试找到该beanName的对象实例.这里有点像类加载时的双亲委派机制去加载bean.
  3. 检查是否为类型检查,如果不仅仅是类型检查,那么Spring知晓为创建Bean了,会开始在一个alreadyCreated的Set集合中加入该BeanName的名称.这里会存储已经创建好的或者正在创建中的beanName.并且进行clearMergedBeanDefinition操作。
  4. 如果从父容器无法获取,开始进行进行创建Bean之前的一些准备工作,例如getMergedLocalBeanDefinition,检测当前的RootBeanDefinition是否为abstract的.同时,如果bean声明了dependsOn,还会进行相应的注册逻辑,同时递归调用getBean方法进行Bean的初始化.
    注意:dependsOn是不可以有循环声明的.因为dependsOn显示声明了Bean创建的顺序,如果还存在循环声明,就会乱套.
  5. 经过上面的校验后,如果Bean的作用域为singleton,就开始进行createBean操作了.此处Spring是调用了一个重载的getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法.而createBean作为ObjectFactory这个函数式接口的代码块进行了传递.在这个getSingleton中,Spring会调用传进来的singletonFactory.getObject()方法,实际上,就是调用的createBean.
  • DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory<?> singletonFactory)
	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		// 上同步锁
		synchronized (this.singletonObjects) {
			// 从一级缓存中获取Bean实例
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				// 如果当前容器正在当前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 + "'");
				}
				// 查看当前bean是否可以进行加载
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// 传入的lambda代码块逻辑在这里执行.
					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;
					}
					// 从singletonsCurrentlyInCreation中移除当前beanName的信息,因为已经完成了bean的创建了
					afterSingletonCreation(beanName);
				}
				// 如果创建了一个新的单例Bean,将其添加到一级缓存中.
				// 同时为了保证一个单例Bean只出现一次,将其从二级、三级缓存中进行移除
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}
  1. 如果当前bean的scope为prototype,直接进行createBean,原型模式下,每次getBean都会创建新的对象实例.
				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					// 如果是原型模式,创建一个实例,在原型模式下,每次getBean都会产生一个新的实例
					Object prototypeInstance = null;
					try {
						// 将当前创建的Bean标记为创建中
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						// 完成创建后,从prototypesCurrentlyInCreation移除beanName
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

7.如果bean的scope不是singletonprototype,则调用scope.get()来选择合适的加载策略.
8.做类型校验,这里不做重点的阐述.