前面我们通过getBean的方法,分析了Spring是如何创建一个单例bean的,我们到现在为止只是看到了一些准备工作。比如检查是否存在prototype类型的bean正在创建,标记下当前的bean开始创建了,获取bean对应的BeanDefinition依赖提前初始化bean依赖的那些bean等。今天我们来分析下Spring的单例bean是如何创建的。
我们找到bean的实例化入口:
通过方法getSinleton获取单例bean的实例sharedInstance,然后进一步通过方法getObjectForBeanInstance,检查当前的bean是否需要通过FactoryBean来创建的。这里调用方法getSingleton除了传入参数beanName之外,还传入了一个匿名内部类作为参数,而且这个匿名内部类中执行了方法createBean,我们可以初步的判断,这个createBean方法应该是实例化bean的核心逻辑了,我们先到getSingleton方法开始分析:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 从单例缓存中获取bean的实例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 如果发现当前单例bean正在销毁,则不允许在创建单例bean(默认为false)
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// 记录当前beanName 对应的bean正在创建
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 调用简单工厂方法来实例化bean
singletonObject = singletonFactory.getObject();
// 设置当前bean是第一次过来创建单例bean
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
// 尝试从单例缓存中,获取beanName对应的单例bean
singletonObject = this.singletonObjects.get(beanName);
// 如果单例缓存中还找不到,则抛出异常
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 记录当前beanName对应的bean创建完成了
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 如果是第一次创建单例bean,将创建好的单例bean添加到相应的缓存中
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
可以看到,匿名内部类传入的参数变成了ObjectFactory类型的参数singletonFactory,那ObjectFactory是什么?我们可以到ObjectFactory中看下:
这个ObjectFactory就是一个接口,在这个接口中只提供了一个getObject方法,Spring默认会通过匿名内部类的方式来实现getObject方法,在getObject方法中添加了createBean方法来实例化bean的。我们通过这个ObjectFactory名称就可以知道,这ObjectFactory就是一个工厂,Spring 就是通过这个ObjectFactory工厂中的方法getObject来实例化bean的。这也是为什么Spring一直被称为专门是用来创建bean的工厂了。而且,ObjectFactory和我们前面讲得FactoryBean,在名称上看来确实挺像的,但是实际的差异还是很大的,如果一个bean没有实现FactoryBean接口,Spring默认就会通过ObjectFactory中封装的逻辑来实例化bean。但是,如果bean实现了FactoryBean接口,Spring还是会通过ObjectFactory中的逻辑先实例化一个bean,但是最终会通过FactoryBean中getObject方法获得单例bean。
我们继续看这个getSingleton方法:
方法里面的逻辑还是比较简单的,Spring在实例化bean之前,会调用beforeSingletonCreation记录当前的beanName对应的bean正在创建,接着就会调用singletonFactory中的getObject方法来实例化bean。在实例化bean之后,Spring有会调用afterSingletonCreation方法,来记录当前bean已经创建好了,并且将创建好的单例bean通过addSingleton方法添加到相应的缓存中。
beforeSingletonCreation 和 afterSingletonCreation 方法我们之前已经看过了。这两个方法分别就是在bean实例化之前,添加beanName到集合singletonsCurrentlyInCreation中,表示当前bean正在创建,而在bean实例化完成之后,再从集合singletonsCurrentlyInCreation中移除,表示当前bean已经创建完毕。
我们看下方法addSingleton中,spring是如何将实例化好的bean添加到缓存中的:
可以看到直接将单例bean添加到单例缓存singletonObjects中了。既然单例bean的实例都已经得到了,那就不需要早期单例缓存earlySingletonObjects以及单例工厂缓存singletonFactories中的数据了,所以直接就从这两个缓存中删除beanName对应的信息了。最后这里还有一个缓存registeredSingletons,通过名称我们就可以知道,缓存registeredSingletons就是用来记录Spring容器中已经创建好的单例bean的名称。
为了彻底搞懂Spring默认是如何实例化bean的,我们先回退到调用getSingleton方法的位置:
我们知道ObjectFactory类中getObject方法中的逻辑,其实就是在匿名内部类中封装的,在匿名内部类中,首先会通过方法createBean 来实例化bean的,如果实例化过程中出现异常,就会调用destroySingleton方法,来清除单例bean相关的缓存信息。
我们先从createBean方法开始入手分析:
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
// 解析BeanDefinition 中的class 属性,并通过发送创建相应的class
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
// 预先标记没有重载的方法
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 通过一个机会,可以通过后处理器BeanPostProcessors创建并返回一个代理的bean实例
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
// 开始实际创建bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
在createBean方法中,我们可以看到还是在做一些bean实例化前的准备工作,比如,在resolveBeanClass方法中先获取单例bean的Class对象,然后调用mbdToUse也就是BeanDefinition的prepareMethodOverrides方法,提前标记下需要覆盖的方法。对于prepareMethodOverrides方法,前面我们在BeanDefinition注册到Spring容器时已经讲解过了,如果bean标签中配置了属性lookup-method以及属性replaced-method的值,这就意味着bean中的某些方法就需要被覆写了。
我们看个案例了解下lookup-method和replaced-method:
可以看到User3继承BaseUser,而且实现了抽象方法getUser,同时也重写了方法say。
我们把User3 配置到xml上面:
在xml中我们将抽象类BaseUser配置上去,同时也给它添加了子标签lookup-method,在lookup-method标签中,指定了抽象方法getUser的实现,以User3中的为准,也就是说,后面在调用BaseUser的getUser方法时,实际上是动态调用User3中的getUser方法。
执行结果:
如果哪一天我们想替换say中的逻辑,完全可以写一个子类,然后在标签lookup-method中替换上去。
我们在来了解一下replaced-method的使用:
我们也创建一个类User4,类中包括一个方法say,然后我们再写一个类UserReplace,UserReplace实现了Spring提供的一个接口MethodReplacer,MethodReplacer是专门是用来替换方法的一个接口,然后我们在接口方法reimplement中,重新实现方法的逻辑。
把这个两个类配置到xml中:
执行结果:
lookup-method是用来寻找方法的,而replacer-method主要就是替换方法的,使用方式大概也就是这样。我们在实际开发过程中已经很少这两个方法了。
我们继续回到刚才的源码位置:
Spring首先会在bean中找到属性lookup-method以及属性replace-method配置的方法,然后才能覆盖它们对不对?但是,Spring在寻找方法时会担心,万一这些方法还有其他重载的方法该怎么办呢?所以,Spring在寻找方法时,就会根据参数或其他手段去重载方法中匹配寻找,比如一个bean中某个需要覆盖的方法,同时存在多个重载方法,这个寻找匹配的过程是比较耗时的,所以,Spring为了加快在bean中寻找目标方法的速度,我们来看下Spring都做了什么事情:
可以看到在prepareMethodOverrides方法中,通过ClassUtils中getMethodCountForName方法,判断bean中相同名称的方法数量,同一个名称的方法就一个,那就证明该方法根本就没有重载方法了。此时,Spring就会提前通过代码mo.setOverloaded(false),设置该方法不需要去重载方法中寻找,到时候要覆盖这个方法时,直接根据方法名称到bean中寻找即可,避免了在重载方法中寻找匹配方法的性能损耗。
接下来,我们继续看下createBean后面的逻辑:
接下来,会调用方法resolveBeforeInstantiation获取bean的实例,如果bean不为空就直接返回了。通过注释我们知道方法resolveBeforeInstantiation是Spring提供给bean后处理器BeanPostProcessor来创建一个代理对象的机会。我们知道通过自定义实现BeanPostProcessor,这样可以介入bean的实例化,而现正好就看到了第一个介入的入口了,这也是Spring给我们提供的一个重要的扩展点。我们到方法resolveBeforeInstancetiation中看下:
默认情况下,BeanDefinition中的属性beforeInstantiationResolved 为null,并且,我们最开始也没有注册任何相关的后处理器,所以方法hasInstantiationAwareBeanPostProcessors返回结果也是false,所以方法resolveBeforeInstantiation直接就returen 返回了。
上图这两个方法,我们通过名称就可以知道是在执行BeanPostProcessor中的前置和后置处理方法来实例化bean。我们先到applyBeanPostProcessorsBeforeInstantiation中看下:
首先会获取Spring容器中已经注册好的后处理器BeanPostProcessor,并且只会对类型为InstantiationAwareBeanPostProcessor的后处理器进行处理。通过名称InstantiationAwareBeanPostProcessor 我们可以知道这是一个能够感知到bean实例化的后置处理器,那这个InstantiationAwareBeanPostProcessor又是什么呢?我们看一下:
这个InstantiationAwareBeanPostProcessor继承了接口BeanPostProcessor,所以InstantiationAwareBeanPostProcessor从本质上来说也是一个bean的后处理器。而且,InstantiationAwareBeanPostProcessor 在BeanPostProcessor接口基础之上又新增好几个方法,其中,方法postProcessBeforeInstantiation 和 postProcessAfterInstantiation,主要在bean实例化之前和之后,添加一些自定义实例化bean的逻辑,而postProcessProperties 方法主要是为bean的实例化提供一些属性信息。总的来说,这个BeanPostProcessor是定义初始化bean的操作,而InstantiationAwareBeanPostProcessor是在定义实例化bean的操作,实例化可以理解为是从0 到1 创建一个bean 出来,而初始化可以理解为为bean填充属性赋值等过程。
我们回到之前看到位置:
因为我们是处于bean实例化之前,此时Spring就会调用bean实例化之前的前置处理方法postProcessorBeforeInstantiation,一旦这个方法实例化bean 成功了,Spring 就会直接返回实例化好的bean,而不会走Spring默认实例化bean的逻辑了。所以我们可以完全自定义InstantiationAwareBeanPostProcessor的实现类,在方法postProcessorBeforeInstantiation中定义bean实例化逻辑,这样的话,Spring就会按照我们定义好的逻辑来实例化bean了。
我们再回到刚才调用方法applyBeanPostProcessorsBeforeInstantiation的位置:
如果通过前置处理方法applyBeanPostProcessorsBeforeInstantiation得到bean的实例不为空。此时就会调用applyBeanPostProcessorsAfterInitialization。我们到方法applyBeanPostProcessorsAfterInitialization中看下:
这个applyBeanPostProcessorsAfterInitialization方法里调用的就不是接口InstantiationAwareBeanPostProcessor中的实例化bean的后处理方法了,而是BeanPostProcessor中的后置处理方法。默认情况下是没有注册后处理器InstantiationAwareBeanPostProcessor的,所以这个逻辑暂时是不会执行的。我们接着往下看:
看到以do为前缀的方法,我们基本上就可以知道,要真正开始执行Spring的默认实例化bean的逻辑了。
我们梳理一下今天的流程图: