导语
通过前面的几天文章,已经对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去做处理的。其实无非就是如下几步:
- 验证FactoryBean的正确性。
- 对非FactoryBean的不做任何处理。
- 对bean进行转换。
- 将从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源码深度解析(第二版)(郝佳)