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;
}
此方法中最吸引我们的无疑是两个方法applyBeanPostProcessorsBeforeInstantiation和applyBeanPostProcessorsAfterInitialization。这两个方法的实现非常简单,无非是对后处理器中的所有InstantiationAwareBeanPostProcessor类型的后处理器进行postProcessBeforeInstantiation方法和BeanPostProcessor的postProcessAfterInitialization方法的调用。
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在虚拟机层面大致会经历以下三步:
- 对象初始化:cls.newInstance(a, b, c),这一步是前提,用于暴露earlyBeanReference
- 填充属性:field.set(obj, autowireValue)
- 回调方法: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
欢迎关注微信公众号,第一时间掌握最新动态!