Spring源码深度解析系列——bean的加载《一》

导语

通过前面的几天文章,已经对xml的解析流程进行了阐述,那么在Spring中bean的工作就完成了?其实还没有,在第一篇文章“Spring源码深度解析系列——Bean的基本实现”的测试类中,第一行的代码是对bean解析的操作,第二句便是开始实行bean的加载动作了。那么这篇文章,就是对bean这样的一个加载流程进行讲解。

 

一、初入Bean加载

在说bean的加载之前,我们先来重新看下Spring的测试例子:

    @Test
    public void stringTest() {
        BeanFactory bf = new XmlBeanFactory(new ClassPathResource("springTest.xml"));
        Student st = (Student) bf.getBean("student");
        System.out.println(st);
 
    }

从上面的例子中,可以看出第二行的代码便是开始对bean的加载工作了,那么就先进去看下这个getBean("student")方法中代码的具体实现了吧。代码如下:

	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}
	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		// 提取对应的beanName
		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		/**
		 * 检查缓存中或者实例工厂中是否有对应的实例
		 * 为什么首先会使用这段代码呢?
		 * 因为在创建单例bean的时候,会储存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,
		 * Spring创建bean的原则是不等bean创建完成,就会将创建bean的ObjectFactory提早曝光,也就是将ObjectFactory加入到缓存中,
		 * 一旦下一个bean创建的时候需要依赖上一个bean,则直接使用ObjectFactory
		 */
		// 直接尝试从缓存获取,或者singletonFactories中的ObjectFactory中获取
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isDebugEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			// 返回对应的实例,有时候存在存储如BeanFactory的情况并不是直接返回实例本身,而是返回指定方法返回的实例
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			// 只有在单例情况下才会尝试解决循环依赖,原型模式情况下,如果存在:
			// A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,也就是当下情况
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
			BeanFactory parentBeanFactory = getParentBeanFactory();
			//如果BeanDefinitionMap中,也就是所有已经加载的类中不包括beanName,则尝试从parentBeanFactory中检测
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				String nameToLookup = originalBeanName(name);
				// 如果parentBeanFactory是否是AbstractBeanFactory的实例对象,则递归调用doGetBean方法
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				// 递归到BeanFactory中寻找
				else if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
			}

			// 如果不是仅仅做类型检查,则创建bean,这里要进行记录
			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			try {
				// 将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition,如果指定BeanName是子Bean的话,同时会合并父类的相关属性
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				//  若存在依赖则需要,递归实例化依赖的bean
				String[] dependsOn = mbd.getDependsOn();
				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.
				// 实例化依赖的bean后便可以实例化mbd本身了,
				// 单例模式的创建
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							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.
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

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

				else {
					// 指定的scope上实例化
					String scopeName = mbd.getScope();
					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.
		// 检查需要的类型是否符合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.isDebugEnabled()) {
					logger.debug("Failed to convert bean '" + name + "' to required type '" +
							ClassUtils.getQualifiedName(requiredType) + "'", ex);
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}

从上面代码的量来看,bean的加载的复杂程度便显而易见了,其中涉及各样的考量,从上面的代码中我们也可以粗略看出bean加载的过程,关于其中的步骤我们先看看时序图,然后结合图再粗略的进行文字描述一下,图如下:

结合代码和时序图上,可以总结bean加载的大体过程有如下几步:

1. 转换对应的beanName

在这里所传入的参数name,其实并非就是beanName,这里的参数可能是别名,也有可能是FactoryBean,所以需要进行一些列的解析。需要解析的内容如下:

  • 去除FactoryBean的修饰符,也就是如果那么name="&aa",那么要先去除&符号。
  • 取指定alias锁表示的最终beanName,例如别名A指向B,那么久返回B;如果别名A指向B,而B又指向C,那么就返回C。

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

单例在Spring中只会被创建依稀,后续再次获取bean,就会直接从单例的缓存中获取了。不过这里只是尝试加载,当加载不成功的时候,才会再次从singletonFactories中加载。因为在创建单例bean的时候,会有依赖注入的情况,而在创建的时候为了避免产生循环依赖,在创建bean的时候,是bean还未被创建完成时,就会事先将创建bean的ObjectFactory提前暴露到缓存中去,一旦下一个bean创建的时候需要依赖上一个bean,这样便可以直接使用ObjectFactory了。

3. bean的实例化

如果再缓存中得到了bean的原始状态后,是需要对其进行实例化的。这里需要声明一下,缓存中所记录的bean都只是最原始的状态,并非我们所想要的最终的bean。譬如,需要对工厂bean进行处理,这里所得到的bean的状态就是最初始的,而我们真正需要的是工厂bean中定义的factory-method方法中返回的bean,而getObjectForBeanInstance就是做这样的工作的。

4. 原型模式的依赖检查

只有在单例的情况下,才会去尝试解决循环依赖的问题。如果A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,也就是isPrototypeCurrentlyInCreation(beanName)为true的时候。

5. 检查parentBeanFactory

从代码中,我们可以看出,如果缓存中没有数据的话,会转到父类工厂上去加载。原因是因为parentBeanFactory如果为空,那么一切都没什么意义了,其中 !containsBeanDefinition(beanName)也是比较重要的,它的功用是为了检测如果当前加载的XML中不包含beanName所对应的配置,就只能到parentBeanFactory去尝试了,然后递归调用getBean方法。这里还要注意parentBeanFactory instanceof AbstractBeanFactory这样的一个条件,如果parentBeanFactory是AbstractBeanFactory的实例对象,则调用doGetBean方法。

6. 将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition

因为在XML中读取到的bean信息是存在在GernericBeanDefiniton中的,但是所有的bean后续处理都是针对于RootBeanDefinition的,因此这里需要进行转换,转换的时候,如果父类的bean不为空,则一并合并父类的属性。

7. 寻找依赖

因为在bean的初始化过程中,会用到一些属性,而这些属性可能是动态配置的,并且配置成了依赖于其他的bean,在这个时候就必须要先加载所依赖的bean。

8. 针对不同的scope进行bean 的创建

9. 类型转换

代码运行到此,也差不多就结束了。这里通常该方法的调用参数requiredType是为空的,但也有这样的情况,返回的bean是个String,但requiredType却传入Integer类型。此时就会起到作用了,它的主要功能就是将返回的bean转换为requiredType所指定的类型。其实,步骤运行到这里,bean的加载也就差不多了。这个时候就反悔了我们所需要的bean。

二、FactoryBean的使用

一般情况下,Spring都是通过反射机制来实例化bean的。但是在有些情况下,实例化的bean是很复杂的。如果按照传统的方式,则需要在<bean>中提供大量的配置信息,配置方式的灵活性就受限了。这时采用编码的形式是会得到一个简单的方案。Spring总提供了FactoryBean这样的一个接口,用户可以通过该接口定制实例化bean的逻辑。

FactoryBean接口在Spring框架中的作用是很大的,在Spring3.0开始,FactoryBean便支持泛型了:

public interface FactoryBean<T> {

	@Nullable
	T getObject() throws Exception;

	@Nullable
	Class<?> getObjectType();

	default boolean isSingleton() {
		return true;
	}

}

在这个接口中,定义了3个方法:

  • T getObject():返回由BeanFactory创建的实例,如果isSingleton返回true,则该实例会放到单例缓存中。
  • boolean isSingleton():返回由FactoryBean创建的bean实例的作用域是singleton还是prototype。
  • Class<?> getObjectType():返回FactoryBean创建的bean类型。

当在配置文件<bean>的class属性配置的实现类是FactoryBean时,会通过getBeanClass()方法返回的却不是FactoryBean本身,而是FactoryBean#getObject() 方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。

三、从缓存中获取单例bean

刚说明了一下FactoryBean的一些基本功用后,现在便可以正式开始了解bean加载的过程了。前面也说过,Spring容器中单例只会被创建一次,后续会在缓存中获取。不过这里也只是尝试加载。首先是尝试在缓存中加载,然后在尝试从singletonFactories中去加载。因为创建单例bean,会存在依赖注入的情况,而在创建的时候又为了避免产生循环依赖,所以Spring会在创建bean的时候,不等bean创建完成,会先把创建bean的ObjectFactory暴露到缓存中,当创建下一个bean的时候,依赖了上一个bean,此时就可以直接使用ObjectFactory了。

	public Object getSingleton(String beanName) {
		return getSingleton(beanName, true);
	}
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 检查缓存中是否存在单例(这里便设计了:double checked locking)
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			// 如果为空,则锁定全局变量,并进行处理
			synchronized (this.singletonObjects) {
				// 如果此bean正在加载,则不进行处理
				singletonObject = this.earlySingletonObjects.get(beanName);
				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;
	}

在这个方法中,因为涉及到了循环依赖的检测,所以涉及了很多变量的记录与存取。在这里首先尝试从singletonObjects里面获取实例,如果获取不到了,才会从earlySingletonObjects中获取,如果还是获取不到,则再尝试从singletonFactories中获取beanName对应的ObjectFactory,然后才调用ObjectFactory中getObject来创建bean,并放到earlySingletonObjects中,并且从singletonFactories中remove掉这个ObjectFactory,对于后续所有的内存操作,其实都只是为了解决循环依赖的问题。也就是在allowEarlyReference为true的时候。

在这里还涉及了存储bean的不同map,基本功用如下:

  • singletonObjects:用于保存beanName和创建bean之间的实例关系,bean name ——> bean instance。
  • singletonFactories:用于保存beanName和穿件bean的工厂之间的关系,bean name ——> ObjectFactory。
  • earlySingletonObjects:这个也是保存beanName和创建bean实例之间的关系,与singletonObjects的不同点是在当前一个单例bean被放到后面后,那么当bean还在被创建的过程中,就可以通过getBean方法获取到了,其主要目的就是为了检测循环引用的问题。
  • registeredSingletons:用来保存当前所有已注册的bean。

四、从bean的实例中获取对象

在doGetBean方法中,getObjectForBeanInstance是一个使用率很高的方法,不管是从缓存中获得bean,还是根据不同的scope策略加载bean。我们得到bean的实例后,要做的第一件事就是调用这个方法来检验正确性,其实就是检测当前bean是否是FactoryBean类型的bean。如果是,那么需要调用该bean对应的FactoryBean的getObject方法作为返回。

不敢是通过才缓存中获取,还是通过不同scope的策略加载的bean,都是最原始的bean,也就不是我们最终想要的bean,那么我们来看看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.
		// 如果指定的name是与工厂先关的(以&为前缀),且beanInstance又不是FactoryBean类型,验证不通过
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
		}

		// Now we have the bean instance, which may be a normal bean or a FactoryBean.
		// If it's a FactoryBean, we use it to create a bean instance, unless the
		// caller actually wants a reference to the factory.
		// 现在有了个bean的实例,这个实例可能会是正常的bean,或者是FactoryBean
		// 如果是FactoryBean使用它创建实例,但是如果用户想要直接获取工厂实例而不是工厂的getObject方法对应的实例,那么传入的name应该加入前缀&
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

		Object object = null;
		if (mbd == null) {
			// 尝试从缓存中获取bean
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// Return bean instance from factory.
			// 到这里已经明确知道beanInstance一定是FactoryBean类型了
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			// 是否定义beanName
			if (mbd == null && containsBeanDefinition(beanName)) {
				// 将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition,如果指定BeanName 是子Bean的话,同时会合并父类的相关属性。
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			// 是否用户定义的,而不是程序本身定义的。
			boolean synthetic = (mbd != null && mbd.isSynthetic());
                        // 核心代码
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

上面代码中基本上都是一些辅助性的功能,其核心功能是委托给getObjectFromFactoryBean去做处理的。其实无非就是如下几步:

  1. 验证FactoryBean的正确性。
  2. 对非FactoryBean的不做任何处理。
  3. 对bean进行转换。
  4. 将从Factory中解析bean的工作交给getObjectFromFactoryBean。
	protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		// 如果是单例模式
		if (factory.isSingleton() && containsSingleton(beanName)) {
			synchronized (getSingletonMutex()) {
				Object object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
					// 核心处理
					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)
					Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
					if (alreadyThere != null) {
						object = alreadyThere;
					}
					else {
						// 如果Object不为空,且shouldPostProcess为true
						if (shouldPostProcess) {
							if (isSingletonCurrentlyInCreation(beanName)) {
								// Temporarily return non-post-processed object, not storing it yet..
								return object;
							}
							// 调用前置处理器
							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 {
								afterSingletonCreation(beanName);
							}
						}
						if (containsSingleton(beanName)) {
							this.factoryBeanObjectCache.put(beanName, object);
						}
					}
				}
				return object;
			}
		}
		else {
			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;
		}
	}

虽然上面的代码看上去的量很多,但是很遗憾的是,仍然不都是我们所想要的。其中如果Object不为null且且shouldPostProcess为true,则调用Object后置处理器,但是它的功用是检测返回的bean是否为单例,它依旧把核心功能的处理交给了doGetObjectFromFactoryBean去处理的。首先来看下后置处理的postProcessObjectFromFactoryBean代码:

	protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
		return applyBeanPostProcessorsAfterInitialization(object, 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;
	}

这里我们只需要知道Spring的bean处理中有后置处理这样一个规则就行了,后面会在再进行讲解。还是先看看上面所说的 doGetObjectFromFactoryBean的核心代码:

	private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
			throws BeanCreationException {

		Object object;
		try {
			// 需要权限验证
			if (System.getSecurityManager() != null) {
				AccessControlContext acc = getAccessControlContext();
				try {
					object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
				// 直接调用getObject方法
				object = factory.getObject();
			}
		}
		catch (FactoryBeanNotInitializedException ex) {
			throw new BeanCurrentlyInCreationException(beanName, ex.toString());
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
		}

		// Do not accept a null value for a FactoryBean that's not fully
		// initialized yet: Many FactoryBeans just return null then.
		if (object == null) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(
						beanName, "FactoryBean which is currently in creation returned null from getObject");
			}
			object = new NullBean();
		}
		return object;
	}

上面代码中,已经体现了FactoryBean的调用,如果生命的bean为FactoryBean类型,则提取bean的时候并不是BeanFactory,而是FactoryBean中对应的getObject方法返回的bean,而doGetObjectFromFactoryBean便就是实现此功能的。不过上述代码中,除了调用object = factory.getObject(),并没有返回我们想要的结果。

由于篇幅原因,本篇文章就先到这里了!!!!

参考:Spring源码深度解析(第二版)(郝佳)

发布了41 篇原创文章 · 获赞 8 · 访问量 4261

猜你喜欢

转载自blog.csdn.net/zfy163520/article/details/95173686