8358 2017-12-09 2024-08-01

我们先来看下bean的加载-准备阶段,此阶段主要是为真正开始创建bean做好前置工作(如处理FactoryBean、提前设置创建bean相关变量、后处理器应用、解决循环依赖等)。

下一节将重点关注一个bean是如何创建的,一个bean从诞生到消亡都会经历些什么。

一、getBean

TestBean bean = (TestBean)factory.getBean("testBean");

上面一行代码实现了什么样的功能,我们可以先快速体验一下Spring中代码是如何实现的。如下

// 来自BeanFactory接口
Object getBean(String name) throws BeansException;

// 来自AbstractBeanFactory
public Object getBean(String name) throws BeansException {
	return doGetBean(name, null, null, false);
}

@SuppressWarnings("unchecked")
protected <T> T doGetBean(
		final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
		throws BeansException {
	// 提取对应的beanName
	final String beanName = transformedBeanName(name);
	Object bean;
	
	/**
	 * 检查缓存中或者实例工厂中是否存在对应的实例
	 * 为什么首先会使用这段代码呢
	 * 因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,
	 * Spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光
	 * 也就是将ObjectFactory加入到缓存中,一旦下个bean创建时候需要依赖上个bean则直接使用ObjectFactory
	 */
	// Eagerly check singleton cache for manually registered singletons.
	// 直接尝试从缓存获取或者从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 {
		// 只有在单例情况下才会尝试解决循环依赖,原型模式情况下,如果存在A中有B的属性,B中有A的属性,
		// 那么当依赖注入时,就会产生当A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,
		// 也就是下面的情况:为true
		// Fail if we're already creating this bean instance:
		// We're assumably within a circular reference.
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}

		// Check if bean definition exists in this factory.
		BeanFactory parentBeanFactory = getParentBeanFactory();
		// 如果beanDefinitionMap中也就是所有已加载的类中不包括beanName,则尝试从父工厂读取
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			// Not found -> check parent.
			String nameToLookup = originalBeanName(name);
			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配置文件的GernericBeanDefinition转换为RootBeanDefinition,如果指定beanName是子bean的话,会合并父类的相关属性
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);

			// Guarantee initialization of beans that the current bean depends on.
			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 + "'");
					}
					// 缓存依赖调用
                    getBean(dep);
					registerDependentBean(dep, beanName);
				}
			}
			// 实例化依赖的bean后,便可以实例化mbd本身了,通过singleton模式的创建
			// Create bean instance.
			if (mbd.isSingleton()) {
				sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
					@Override
					public Object getObject() throws BeansException {
						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.
				Object prototypeInstance = null;
				try {
					beforePrototypeCreation(beanName);
					prototypeInstance = createBean(beanName, mbd, args);
				}
				finally {
					afterPrototypeCreation(beanName);
				}
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			}

			else {
				// 在指定的scope上实例化bean
				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, new ObjectFactory<Object>() {
						@Override
						public Object getObject() throws BeansException {
							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;
		}
	}
	// 检查需要的类型是否符合bean的实际类型
	// Check if required type matches the type of the actual bean instance.
	if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
		try {
			return getTypeConverter().convertIfNecessary(bean, requiredType);
		}
		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的加载经历了一个相当复杂的过程,其中涉及各种各样的考虑。相信读者细心阅读上面的代码,并参照部分代码注释,是可以粗略地了解整个Spring加载bean的过程。对于加载过程中所涉及的步骤大致如下:

1、转换对应的beanName

或许很多人不理解转换对应的beanName是什么意思,传入的参数name不就是beanName吗?其实不是,这里传入的参数可能是别名,也可能是FactoryBean,所以需要进行一系列的解析,这些解析内容包括如下方面:

  • 去除FactoryBean的修饰符,也就是如果name=“&aa”,那么首先会去除&而使name为aa。
  • 取指定alias所表示的最终beanName,例如别名A指向名称为B的bean则返回B。若别名A指向别名B,而别名B又指向名称为C的bean,则返回C。

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

单例在Spring的同一个容器内只会被创建一次,后续再获取bean,就直接从单例缓存中获取了。当然,这里只是尝试加载,首先尝试从缓存中加载,如果加载不成功则再次尝试从singletonFactory中加载。因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,在Spring中创建bean的原则是不等bean创建完就会创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建的时候需要依赖上一个bean则直接使用ObjectFactory(后文会有详细的讲解)。

3、bean的实例化

如果从缓存中得到了bean的原始状态,则需要对bean进行实例化。这里有必要强调一下,缓存中记录的只是最原始的bean状态,并不一定是我们最终想要的bean。举个例子,假如我们需要对工厂bean进行处理,那么这里得到的是其实是工厂bean的初始状态,但是我们真正需要的是工厂bean中定义的factory-method方法中返回的bean,而getObjectForBeanInstance就是完成这个工作的,后续会有详细的讲解。

4、原型模式的依赖检查

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

5、检测parentBeanFactory

当父工厂不为空且本地找不到目标bean,那么就会到父工厂去寻找。

6、转换GernericBeanDefinition

因为从XML配置文件中读取到的bean信息存储在GernericBeanDefinition中的,但是所有的bean后续处理都是针对于RootBeanDefinition的,所以这里需要进行一个转换,转换的同时如果父类不为空的话,则会一并合并父类的属性。

7、寻找依赖

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

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

我们都知道,在Spring中存在着不同的scope,其中默认的是singleton,但是还有些其他的配置诸如prototype、request之类的。在这个步骤中,Spring会根据不同的配置进行不同的初始化策略。

9、类型转换

程序到这里返回bean后已经基本结束了,通常对该方法的调用参数requiredType是为空的,但是可能会存在这样的情况,返回的bean其实是个String,但是requiredType却传入Integer类型,那么这时候本步骤就会起作用了,他的功能是将返回的bean转换为requiredType所制定的类型。当然,String转换为Integer是最简单的一种转换,在Spring中提供了各种各样的转换器,用户也可以自己扩展转换器来满足需求。

二、FactoryBean的使用

一般情况下,Spring通过反射机制利用bean的class属性指定实现类来实例化bean。在某些情况下,实例化bean过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量的配置信息,配置方式的灵活性是受限的,这是采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂接口,用户可以通过实现该接口定制实例化bean的逻辑。

FactoryBean接口对于Spring框架来说占有重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为了FactoryBean<T>的形式。其类结构如下

public interface FactoryBean<T> {

	T getObject() throws Exception;

	Class<?> getObjectType();

	boolean isSingleton();
}

当配置文件中<bean>的class属性配置的实现类时FactoryBean时,通过getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。例如:使用传统方式配置下面Card的<bean>时,Car的每个属性分别对应一个<property>元素标签。

public class car {
    private int maxSpeed;
    private String brand;
    private double price;
}

如果用FactoryBean的方式实现会简单一点,下例通过逗号分隔符的方式一次性地为Car的所有属性指定配置值:

public class CarFactoryBean implements FactoryBean<Car> {
    private String carInfo;
    public Car getObject() throw Exception{
        Car car = new Car();
        String[] infos = carInfo.split(",");
        car.setBrand(info[0]);
        car.setMaxSpeed(Integer.valueOf(info[1]));
        car.setPrice(Double.valueOf(info[2]));
        return car;
    }
    public Class<Car> getObjectType() {
        return Car.class;
    }
    public boolean isSingleton() {
        return false;
    }
    public String getCarInfo() {
        return this.carInfo;
    }
    public void setCarInfo(String carInfo) {
        this.carInfo = carInfo;
    }
}

有了这个CarFactoryBean后,就可以在配置文件中使用下面这种自定义的配置方式配置CarBean了:

<bean id="car" class="test.CarFactoryBean" carInfo="超级跑车, 400, 2000000"/>

当调用getBean("car")时,Spring通过反射机制发现CarFactoryBean实现了FactoryBean的接口,这时Spring容器就会调用接口方法CarFactoryBean#getObject()方法返回。如果希望获取CarFactoryBean的实例,则需要在使用getBean(beanName)方法时在beanName前先显式地加上”&“前缀,例如getBean("&car")。

三、缓存中获取单例bean

介绍过FactoryBean的用法后,我们就可以了解bean加载的过程了。前面已经提到过,单例在Spring的同一容器内只会被创建一次,后续再获取bean直接从单例缓存中获取,当然这里也只是尝试加载,首先尝试从缓存中加载,然后再次尝试从singletonFactory中加载。

因为创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,Spring创建bean的原则是不等bean创建完成就会创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建时需要依赖上一个bean,则直接使用ObjectFactory。代码如下

public Object getSingleton(String beanName) {
    // 参数true设置标示允许早期依赖
    return getSingleton(beanName, true);
}

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 检查缓存中是否存在单例
    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和singletonFactoriesy互斥
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

这个方法因为涉及循环依赖的检测,以及涉及很多变量的记录存取,所以让很多读者摸不着头脑。这个方法首先尝试从singletonObjects里面获取实例,如果获取不到再从earlySingletonObjects里面获取,如果还获取不到,再尝试从singletonFactories里面获取beanName对应的ObjectFactory,然后调用这个ObjectFactory里面的getObject来创建bean,而对于后续的所有内存操作都只为循环依赖检测时的使用,也就是allowEarlyReference为true的情况下才会使用。

这里涉及用于存储bean的不同map,可能让读者感到崩溃,简单解释如下:

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

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

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

无论是从缓存中获取到的bean还是通过不同的scope策略加载的bean都只是最原始的bean状态,并不一定是我们最终想要的bean。举个例子,假如我们需要对工厂bean进行处理,那么这里得到的其实是工厂bean的初始状态,但是我们真正需要的是工厂bean中定义的factory-method方法中返回的bean,而getObjectForBeanInstance方法就是完成这个工作的。代码如下

protected Object getObjectForBeanInstance(
        Object beanInstance, String name, String beanName, 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) && !(beanInstance instanceof FactoryBean)) {
        throw new BeanIsNotAFactoryException(transformedBeanName(name), 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.
    // 如果想要直接获取工厂实例而不是工厂的getObject方法,那么name应该加上前缀&
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }

    Object object = null;
    if (mbd == null) {
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
        // Return bean instance from factory.
        // 尝试从缓存中加载
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // Caches object obtained from FactoryBean if it is a singleton.
        // containsBeanDefinition方法检测所有已加载类中是否定义beanName
        if (mbd == null && containsBeanDefinition(beanName)) {
            // 将存储xml配置文件的GernericBeanDefinition转换为RootBeanDefinition
            // 如果指定benaName是子bean的话,会合并父bean的相关属性
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        // 是否是用户定义的而不是应用程序本身定义的
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}

从上面的代码来看,其实这个方法并没有什么重要的信息,太多是些辅助代码以及一些功能性的判断,而真正的核心代码却委托给了getObjectFromFactoryBean方法,我们先来看下getObjectForBeanInstance方法中所做的工作:

  • 对FactoryBean正确性的验证。
  • 对非FactoryBean不做任何处理。
  • 对bean进行转换。
  • 将从Factory中解析bean的工作委托给getObjectFromFactoryBean方法。

我们看下getObjectFromFactoryBean方法,代码如下

/**
 * Obtain an object to expose from the given FactoryBean.
 * @param factory the FactoryBean instance
 * @param beanName the name of the bean
 * @param shouldPostProcess whether the bean is subject to post-processing
 * @return the object obtained from the FactoryBean
 * @throws BeanCreationException if FactoryBean object creation failed
 * @see org.springframework.beans.factory.FactoryBean#getObject()
 */
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 {
                    if (object != null && shouldPostProcess) {
                        try {
                            // 调用ObjectFactory的后处理器
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        }
                        catch (Throwable ex) {
                            throw new BeanCreationException(beanName,
                                    "Post-processing of FactoryBean's singleton object failed", ex);
                        }
                    }
                    this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
                }
            }
            return (object != NULL_OBJECT ? object : null);
        }
    }
    else {
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (object != null && shouldPostProcess) {
            try {
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        return object;
    }
}

先跟踪上面出现的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(new PrivilegedExceptionAction<Object>() {
                    public Object run() throws Exception {
                        	// 发现目标
                            return factory.getObject();
                        }
                    }, acc);
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            // 发现目标
            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 && isSingletonCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(
                beanName, "FactoryBean which is currently in creation returned null from getObject");
    }
    return object;
}

上面我们已经讲述了FactoryBean的调用方法,如果bean声明为FactoryBean类型,则当提取bean时提取的并不是FactoryBean,而是FactoryBean中对应getObject方法返回的bean。但是,我们看到在第一个方法中调用doGetObjectFromFactoryBean后并没有直接返回结果,而是进行通过postProcessObjectFromFactoryBean方法二次加工,跟踪至AbstractAutowireCapableBeanFactory类,代码如下

@Override
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 beanProcessor : getBeanPostProcessors()) {
        result = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;
}

对于后处理器的使用我们还未过多接触,后续章节会使用大量篇幅介绍,这里,我们只需了解在Spring获取bean的规则中有这样一条:尽可能保证所有bean初始化后都会调用注册的BeanPostProcessor的postProcessAfterInitialization方法进行处理,在实际开发中过程大可针对此特性设计自己的业务逻辑。

五、获取单例

之前我们了解了从缓存中获取单例的过程,那么,如果缓存中不存在已经加载的单例bean就需要从头开始bean的加载过程了,而Spring中使用getSingleton的重载方法实现bean的加载过程。代码如下

/**
 * Return the (raw) singleton object registered under the given name,
 * creating and registering a new one if none registered yet.
 * @param beanName the name of the bean
 * @param singletonFactory the ObjectFactory to lazily create the singleton
 * with, if necessary
 * @return the registered singleton object
 */
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "'beanName' must not be null");
    // 全局需要同步
    synchronized (this.singletonObjects) {
        // 首先检查对应的bean是否已经加载过
        Object singletonObject = this.singletonObjects.get(beanName);
        // 如果为空才可以进行单例bean的初始化
        if (singletonObject == null) {
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException(beanName,
                        "Singleton bean creation not allowed while the 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 recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<Exception>();
            }
            try {
                // 初始化bean
                singletonObject = singletonFactory.getObject();
            }
            catch (BeanCreationException ex) {
                if (recordSuppressedExceptions) {
                    for (Exception suppressedException : this.suppressedExceptions) {
                        ex.addRelatedCause(suppressedException);
                    }
                }
                throw ex;
            }
            finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                afterSingletonCreation(beanName);
            }
            // 创建完bean之后
            addSingleton(beanName, singletonObject);
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }
}

上述的代码中其实是使用了回调方法,使得程序可以在单例创建的前后做一些准备及处理操作,而真正的获取单例bean的方法其实并不是在此方法中实现的,其实现逻辑是在ObjectFactory类型的实例singletonFactory中实现的。而这些准备及处理操作包括如下内容:

  • 检查缓存中是否已经加载过单例bean。
  • 若没有加载,则记录beanName的正在加载状态。
  • 加载单例前记录加载状态。

可能你会觉得beforeSingletonCreation方法是个空实现,里面没有任何逻辑,但其实不是,这个函数中做了一个很重要的操作:记录加载状态,也就是通过this.singletonsCurrentlyInCreation方法将当前正要创建的bean记录在缓存中,这样便可以对循环依赖进行检测。代码如下

/**
 * Callback before singleton creation.
 * <p>The default implementation register the singleton as currently in creation.
 * @param beanName the name of the singleton about to be created
 * @see #isSingletonCurrentlyInCreation
 */
protected void beforeSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.containsKey(beanName) &&
            this.singletonsCurrentlyInCreation.put(beanName, Boolean.TRUE) != null) {
        throw new BeanCurrentlyInCreationException(beanName);
    }
}
  • 通过调用参数传入的ObjectFactory的getObject方法实例化bean。
  • 加载单例后的处理方法调用。

同上面类似,当bean加载结束后需要移除缓存中对该bean的正在加载状态的记录。代码如下

/**
 * Callback after singleton creation.
 * <p>The default implementation marks the singleton as not in creation anymore.
 * @param beanName the name of the singleton that has been created
 * @see #isSingletonCurrentlyInCreation
 */
protected void afterSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.containsKey(beanName) &&
            !this.singletonsCurrentlyInCreation.remove(beanName)) {
        throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
    }
}
  • 将结果记录至缓存并删除加载bean过程中所记录的各种辅助状态。代码如下
/**
 * Add the given singleton object to the singleton cache of this factory.
 * <p>To be called for eager registration of singletons.
 * @param beanName the name of the bean
 * @param singletonObject the singleton object
 */
protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
        this.singletonFactories.remove(beanName);
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName);
    }
}

六、准备创建bean

我们不可能指望一个方法内完成一个复杂的逻辑,而且我们跟踪了这么多的Spring代码,经历了这么多方法,或多或少也发现了一些规律:一个真正干活的方法其实是以do开头的,比如doGetObjectFromFactoryBean;而给我们错觉的方法,比如getObjectFromFactoryBean,其实是从全局角度去做一些统筹工作的。这个规律对于createBean也不例外,那么让我们看下createBean方法中做了哪些准备工作。代码如下

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating instance of bean '" + beanName + "'");
    }
    // Make sure bean class is actually resolved at this point.
    resolveBeanClass(mbd, beanName);

    // Prepare method overrides.
    try {
        mbd.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
                beanName, "Validation of method overrides failed", ex);
    }

    try {
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
        Object bean = resolveBeforeInstantiation(beanName, mbd);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "BeanPostProcessor before instantiation of bean failed", ex);
    }

    Object beanInstance = doCreateBean(beanName, mbd, args);
    if (logger.isDebugEnabled()) {
        logger.debug("Finished creating instance of bean '" + beanName + "'");
    }
    return beanInstance;
}

从代码中我们可以总结出方法完成的具体步骤及功能:

  • 根据设置的class属性或者根据className来解析Class。
  • 对override属性进行标记及验证。

很多读者可能不知道这个方法的作用,因为在Spring的配置里面根本就没有诸如override-method之类的配置,那么这个方法到底时干什么用的呢?

其实在Spring中确实没有override-method这样的配置,但是如果读过前面的部分,可能会有所发现,在Spring配置中是存在lookup-method和replace-method的,而这两个配置的加载其实就是将配置统一存放在BeanDefinition中的methodOverrides属性里,而这个方法的操作其实也就是针对于这两个配置的。

  • 应用初始化前的后处理器,解析指定bean是否存在初始化前的短路操作。
  • 创建bean。

我们首先看下对于override属性标记及验证的逻辑实现。

1、处理override属性

查看源码中AbstractBeanDefinition类的prepareMethodOverrides方法

public void prepareMethodOverrides() throws BeanDefinitionValidationException {
    // Check that lookup methods exists.
    MethodOverrides methodOverrides = getMethodOverrides();
    if (!methodOverrides.isEmpty()) {
        for (MethodOverride mo : methodOverrides.getOverrides()) {
            prepareMethodOverride(mo);
        }
    }
}

protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
    int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
    if (count == 0) {
        throw new BeanDefinitionValidationException(
                "Invalid method override: no method with name '" + mo.getMethodName() +
                "' on class [" + getBeanClassName() + "]");
    }
    else if (count == 1) {
        // Mark override as not overloaded, to avoid the overhead of arg type checking.
        mo.setOverloaded(false);
    }
}

通过以上两个方法的代码你能体会到它所要实现的功能吗?之前反复提到过,在Spring配置中存在lookup-method和replace-method两个配置功能,而这个两个配置的加载其实就是将配置统一存放在BeanDefinition中的methodOverrides属性,这两个功能实现原理其实是在bean实例化的时候如果检测到存在methodOverrides属性,会动态地为当前bean生成代理并使用对应的拦截器为bean做增强处理,相关逻辑实现在bean的实例化部分再详细介绍。

但是,这里要提到的是,对于方法的匹配来讲,如果一个类中存在若干个重载方法,那么,在方法调用及增强的时候还需要根据参数类型来匹配,来最终确认当前调用的到底时哪个方法。Spring将一部分匹配的工作在这里完成了,如果当前类的方法只有一个,那么就设置该方法为没有被重载,这样在后续的调用的时候便可以直接使用找到的方法,而不需要进行方法的参数验证了,而且还可以提前对方法存在性进行验证,正可谓一箭双雕。

2、实例化的前置处理

在真正调用doCreate方法创建bean的实例前使用了方法**resolveBeforeInstantiation()**对BeanDefinition中的属性做了前置处理。当然,无论其中是否有相应的逻辑实现我们都可以理解,因为真正逻辑实现前后留有处理方法也是可扩展的一种体现,但是,这并不是最重要的,在方法中还提供了一个短路判断,这才是最为关键的部分。

Object bean = resolveBeforeInstantiation(beanName, mbd);
if (bean != null) {
    return bean;
}

当进过前置处理后返回的结果如果不为空,那么会直接略过后续的bean的创建而直接返回结果。这一特性虽然很容易被忽略,但是却起着至关重要的作用,我们熟知的AOP功能就是基于这里判断的。

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    // 如果尚未被解析 
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // Make sure bean class is actually resolved at this point.
        if (mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName);
            if (bean != null) {
                bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

此方法中最吸引我们的无疑是两个方法applyBeanPostProcessorsBeforeInstantiationapplyBeanPostProcessorsAfterInitialization。这两个方法的实现非常简单,无非是对后处理器中的所有InstantiationAwareBeanPostProcessor类型的后处理器进行postProcessBeforeInstantiation方法和BeanPostProcessorpostProcessAfterInitialization方法的调用。

1、实例化前的后处理器应用

bean的实例化前调用,也就是将AbstractBeanDefinition转换为BeanWrapper前的处理。给子类一个修改BeanDefinition的机会,也就是说当程序经过这个方法后,bean可能已经不是我们认为的bean了,而是或许成为一个经过处理的代理bean,可能是通过cglib生成的,也可能是通过其他技术生成的。后面会有详细介绍,此时我们只需知道,在bean的实例化前会调用后处理器的方法进行处理。代码如下

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName)
        throws BeansException {

    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
            if (result != null) {
                return result;
            }
        }
    }
    return null;
}

2、实例化后的后处理器应用

在讲解从缓存中获取单例bean的时候就提到过,Spring中的规则是在bean的初始化后尽可能保证将注册的后处理器的postProcessBeforeInstantiation方法应用到该bean中,因为如果返回的bean不为空,那么便不会再次经历普通bean的创建过程,所以只能在这里应用后处理器的postProcessBeforeInstantiation方法。代码如下

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        result = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;
}

下篇我们将继续讲解bean的创建,即createBean方法。

七、循环依赖

实例化bean是一个非常复杂的过程,而其中最比较难以理解的就是对循环依赖的解决。

1、什么是循环依赖

循环依赖就是循环引用,就是两个或多个bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,则它们最终反映为一个环。此处不是循环调用,循环调用是方法之间的环调用。

循环调用是无法解决的,除非有终结条件,否则就是死循环,最终导致内存溢出错误。

2、Spring解决循环依赖

Spring容器循环依赖包括构造器循环依赖setter循环依赖字段循环依赖,那Spring是如何解决循环依赖的呢?首先让我们来定义循环引用类:

public Class TestA {
    private TestB testB;
    public void a() {
        testB.b();
    }
    public TestB getTestB() {
        return testB;
    }
    public void setTestB(TestB testB) {
        this.testB = testB;
    }
}

public Class TestB {
    private TestC testC;
    public void b() {
        testC.c();
    }
    public TestC getTestC() {
        return testc;
    }
    public void setTestC(TestC testC) {
        this.testC = testC;
    }
}

public Class TestC {
    private TesA testA;
    public void c() {
        testA.a();
    }
    public TestA getTestA() {
        return testA;
    }
    public void setTestB(TesA testA) {
        this.testA = testA;
    }
}

在Spring中将循环依赖的处理分为三种情况。

1、构造器循环依赖

表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出BeanCurrentlyInCreationException异常标示循环依赖。

如在创建TestA类时,构造器需要TestB类,那将去创建TestB,再创建TestB时,又需要创建TestC类,则又去创建TestC,最终在创建TestC时发现又需要创建TestA,从而形成一个环,无法创建。

Spring容器将每一个正在创建的bean标识符放在一个“当前创建bean池”中,bean标识符在创建过程中将一直保持在这个池中,因此如果在创建bean过程中发现自己已经在“当前创建bean池”中,将抛出BeanCurrentlyInCreationException异常标示循环依赖;而对于创建完毕的bean将从“当前创建bean池”中清除掉。

2、setter循环依赖

表示通过setter注入方式构成的循环依赖。对于setter注入造成的依赖是通过Spring容器提前曝光刚完成构造器注入但未完成其他步骤(如setter注入)的bean来完成的,而且只能解决单例作用域的bean循环依赖。通过提前曝光一个单例工厂方法,从而使其他bean能引用到该bean,如下代码所示

addSingletonFactory(beanName, new ObjectFactory() {
    public Object getObject() throw BeanException {
        return getEarlyBeanReference(beanName, mod, bean);
    }
});

具体步骤如下:

  • Spring容器创建单例“testA”的bean,首先根据无参构造器创建bean,并曝光一个“ObjectFactory”用于返回一个提前暴露的正在创建的bean,并将“testA”标识符放到“当前创建bean池”,然后进行setter注入“testB”。
  • Spring容器创建单例“testB”的bean,首先根据无参构造器创建bean,并曝光一个“ObjectFactory”用于返回一个提前暴露的正在创建的bean,并将“testB”标识符放到“当前创建bean池”,然后进行setter注入“testC”。
  • Spring容器创建单例“testC”的bean,首先根据无参构造器创建bean,并曝光一个“ObjectFactory”用于返回一个提前暴露的正在创建的bean,并将“testC”标识符放到“当前创建bean池”,然后进行setter注入“testA”。j进行注入testA时由于提前暴露了ObjectFactory工厂,从而使用它提起暴露一个创建中的bean。
  • 最后在依赖注入testB和testA,完成setter注入。

字段循环依赖同setter循环依赖。

3、prototype范围的依赖处理

对于“prototype”作用域的bean,Spring容器无法完成依赖注入,因为Spring容器不进行缓存“prototype”作用域的bean,因此无法提前曝光一个正在创建的bean。

对于singleton作用域的bean,可以通过setAllowCircularReferences(false)来禁用循环引用。

3、通俗理解

对于循环依赖,其实也不难理解。Spring都是通过反射来创建bean的,一个bean在虚拟机层面大致会经历以下三步:

  1. 对象初始化:cls.newInstance(a, b, c),这一步是前提,用于暴露earlyBeanReference
  2. 填充属性:field.set(obj, autowireValue)
  3. 回调方法:method.invoke(obj, autowireParams)
public static void main(String[] args) throws Exception {
    // 1.确定加载类
    Class<?> cls = Class.forName("test.Test");

    // 2.确定构造方法
    Constructor[] cons = cls.getDeclaredConstructors();
    // 假设是第一个
    Constructor constructor = cons[0];
    constructor.setAccessible(true);

    // 3.初始化对象,执行构造方法
    // 这就是我们的原始引用,earlyBeanReference
    // 假设构造方法有两个入参,如果依赖其他bean,会先触发其他bean的初始化
    Object obj = constructor.newInstance(new Object(), new Object());

    // 4.填充字段,比如@Resource、@Autowired
    Field[] own = cls.getDeclaredFields();
    Field[] parent = cls.getFields();
    // 假设是第一个
    Field field = own[0];
    field.setAccessible(true);
    field.set(obj, new Object());

    // 5.回调方法,比如@Autowired修饰、@PostConstruct等
    Method[] ownM = cls.getDeclaredMethods();
    Method[] parentM = cls.getMethods();
    Method method = ownM[0];
    method.setAccessible(true);
    method.invoke(obj);
}

上述例子可能对你理解有所帮助,当然实际情况会远比这复杂得多。

总访问次数: 220次, 一般般帅 创建于 2017-12-09, 最后更新于 2024-08-01

进大厂! 欢迎关注微信公众号,第一时间掌握最新动态!