对XML文件的解析基本上已经大致的走了一遍,虽然没有能吸收多少,但是脑子中总是有些印象的,接下来看下spring中的bean的加载,这个比xml解析复杂的多。
这个加载,在我们使用的时候基本上是:
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beanFactory.xml"));
MyTestBean bean = (MyTestBean) beanFactory.getBean("myTestBean"); // 这个是bean的加载的使用

一、总体掌握

看看spring中的代码是如何实现的:
这个是在org.springframework.beans.factory.support包下的AbstractBeanFactory类

 @Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
} /**
* Return an instance, which may be shared or independent, of the specified bean.
* @param name the name of the bean to retrieve
* @param requiredType the required type of the bean to retrieve
* @param args arguments to use when creating a bean instance using explicit arguments
* (only applied when creating a new instance as opposed to retrieving an existing one)
* @param typeCheckOnly whether the instance is obtained for a type check,
* not for actual use
* @return an instance of the bean
* @throws BeansException if the bean could not be created
*/
@SuppressWarnings("unchecked")
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; /**
* 检查缓存中或者实例工厂中是否有对应的实例
* 为什么会首先使用这段代码呢?
* 因为在创建单例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 {
// 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();
// 在parentBeanFactory中检测
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
// 递归到BeanFactory中查找
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
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.
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 + "'");
}
// 缓存依赖调用
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本身了
// singleton模式的创建
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);
}
// Prototype模式创建
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);
}
// 指定scope上实例化bean
else {
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;
}

(1)转换对应的beanName
这里传入的参数name并不一定是beanName,可能是别名,也可能是FactoryBean,所以进行一系类的解析,这些解析内容如下
1)去除FactoryBean的修饰符,也就是name="&aa",那么首先会去除&,而使name=aa
2)取指定别名所表示的最终的beanName

(2)尝试从缓存中加载单例
单例在spring的同一个容器内只会被创建一次,后续在获取bean,就直接从单例缓存中获取了,当然,这里也只是尝试加载,
首先尝试从缓存中加载,如果加载不成功则再次尝试从singletonFactories中加载。因为在创建单例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
从代码上看,如果缓存没有数据的话,直接转到父类工厂上去加载了,这是为什么?可能我们忽略了
parentBeanFactory != null && !containsBeanDefinition(beanName)这里面判断条件,parentBeanFactory != null,parentBeanFactory如果为空,
其他一切都是浮云,但是还有一个条件,!containsBeanDefinition(beanName),它是在检测如果当前加载的XML配置文件中,不包含beanName多对应的
配置,只能去parentBeanFactory中尝试,然后再去递归的调用递归方法

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

(7)寻找依赖
因为bean的初始化过程很肯能用到某些属性,而某些属性可能是动态配置的,并且配置成依赖其他的bean,那么这个时候必须先加载依赖的bean,
spring的加载顺序中,在初始化一个bean的时候,首先会初始化这个bean所对应的依赖

(8)针对不同的scope进行bean的创建
spring根据不同的配置进行不同的初始化策略,默认的是singleton

(9)类型转换
程序到这里已经基本结束了,通常对该方法的调用参数requireType是为空的,但是可能会存在这样的情况,返回的bean其实是个String,但是
requireType却传入的是Integer类型,那么这时候本步骤就起作用了,他的功能是将返回的bean转换为requireType所指定的类型。

二、剥离,逐一分析

1、FactoryBean的使用

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

FactoryBean接口对于spring来说,占有重要地位,spring自身就提供了70多个FactoryBean的实现,从spring 3.0开始,FactoryBean开始支持泛型
接口声明为:

 public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}

接口中定义的三个方法:
1)T getObject():返回由FactoryBean创建的bean实例,如果isSignleton()返回的是true,则该实例会方放到spring容器中单实例缓存池中
2)default boolean isSingleton():判断创建bean的scope
3)Class<?> getObjectType():返回创建bean的类型

2、缓存中获取单例bean

单例在spring的同一容器中只会被创建一次,然后再获取bean直接从单例缓存中获取,当然,这里也只是尝试加载,首先尝试从缓存中加载,
然后再次尝试从singletonFactories中加载,因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,
spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建的时候依赖上个bean
则直接使用ObjectFactory
下面的额源码是在org.springframework.beans.factory.support包下DefaultSingletonBeanRegistry中

 @Override
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
} /**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@Nullable
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) {
// 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,而对于后续的所有内存操作都只为了循环依赖检测时候使用,这里有几个不同的map:
singletonObjects:用于保存BeanName和创建bean实例之间的关系,bean name -> bean instance
singletonFactories:用于保存BeanName和创建bean工厂之间的关系,bean name -> ObjectFactory
earlySingletonObjects:用于保存BeanName和创建bean实例之间的关系,与ingletonObjects不同的是,当一个单例bean被放到这里面后,那么当bean
还在创建过程中,就可以通过getBean方法获取到了,其目的是用来检测循环引用
registeredSingletons:用来保存所有当前已存在的bean

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

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

无论是从缓存中获取到bean还是从不同的scope策略中加载的bean都是最原始的bean状态,并不一定是我们最终想要的bean,而getObjectForBeanInstance
方法就是完成这个工作的
该方法是在org.springframework.beans.factory.support包下的AbstractBeanFactory类:

 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.
// containsBeanDefinition检测beanDefinitionMap中也就是所有已经记载的类中检测是否定义beanName
if (mbd == null && containsBeanDefinition(beanName)) {
// 将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition
// 如果指定BeanName 是子bean的话同时合并父类的相关属性
mbd = getMergedLocalBeanDefinition(beanName);
}
// 是否是用户定义的,而不是应用程序本身定义的
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}

这个方法其实大部分代码是在做一些功能性判断,真正的核心的代码交给了getObjectFromFactoryBean()方法来处理
此方法是在org.springframework.beans.factory.support包下的FactoryBeanRegistrySupport类
这个和作者在书中的源码有些不同的地方,应该是做了一些优化,注意一下这个地方,有些源码还是不懂为啥那么做

 /**
* 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()) {
// 从缓存中获取bean实例
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 从工厂bean中获取bean实例
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 (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
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) {
// bean需要做后续处理
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}

从工厂中获取bean实例的代码在doGetObjectFromFactoryBean()方法中,来看看
此方法是在org.springframework.beans.factory.support包下的FactoryBeanRegistrySupport类

 /**
* Obtain an object to expose from the given FactoryBean. --> 获得一个bean实例从所给的工厂bean中
* @param factory the FactoryBean instance
* @param beanName the name of the bean
* @return the object obtained from the FactoryBean
* @throws BeanCreationException if FactoryBean object creation failed
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException { Object object;
try {
// 需要权限验证 access是权限的意思
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 在工厂中创建bean实例
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;
}

这个能得到实例化的bean了,但是根据shouldPostProcess来进行后续的bean处理,走的是postProcessObjectFromFactoryBean()方法
org.springframework.beans.factory.support包下的FactoryBeanRegistrySupport类,这个是抽象类,找到实现该方法的类,那就是
org.springframework.beans.factory.support包下的AbstractAutowireCapableBeanFactory类,看一下这个类中源码实现:

 /**
* Applies the {@code postProcessAfterInitialization} callback of all
* registered BeanPostProcessors, giving them a chance to post-process the
* object obtained from FactoryBeans (for example, to auto-proxy them).
* @see #applyBeanPostProcessorsAfterInitialization
*/
@Override
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
} @Override
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的规则只有一条:尽可能保证所有bean初始化后都会调用注册的BeanPostProcessor的postProcessAfterInitialization
方法进行处理,也就是上面方法中的Object current = processor.postProcessAfterInitialization(result, beanName);这一行代码,可以针对此特性设计自己的
设计逻辑

4、获取单例

之前我们讲解了从缓存中获取单例的过程,那么,如果缓存中不存在已经加载的单例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, "Bean name must not be null");
// 全局变量需要同步
synchronized (this.singletonObjects) {
// 首先检查对应的bean是否已经加载过,因为singleton模式其实就是复用以创建的bean,所以这一步是必须的
Object singletonObject = this.singletonObjects.get(beanName);
// 如果为空才可以进行singleton的bean的初始化
if (singletonObject == null) {
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 + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 初始化bean
singletonObject = singletonFactory.getObject();
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.
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;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 加入缓存中
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}

上述代码中其实使用了回调方法,使得程序可以在单例创建的前后做一些准备及处理操作,而真正的获取单例bean的方法其实并不是在此方法中实现,
其逻辑是在ObjectFactory类型的实例singletonFactory中实现的,而这些准备和处理操作包括如下:
(1)检查缓存中是否已经加载过
(2)若没有加载,则记录beanName的正在加载状态
(3)加载单例前记录加载状态

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

 protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}

(4)通过调用参数传入的ObjectFactory的个体Object方法实例化bean
(5)加载单例后的处理方法调用
同步骤3的记录加载状态相似,当bean加载结束后需要移除缓存中对该bean的正在加载状态的记录,同一个类中

 protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}

(6)将结果记录至缓存并删除加载bean过程中所记录的各种辅助状态 同一个类中

 protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}

(7)返回处理结果
虽然我们了解了加载bean的逻辑架构,但是现在我们并没有开始对bean加载功能进行探索,之前提到过,bean的加载逻辑实在传入的ObjectFactory类型的参数
singletonFactory中定义的,我们反推参数的获取,得到以下代码:这我就不会往回反推参数,全局搜索的。。。
这段代码是在org.springframework.beans.factory.support包下AbstractBeanFactory类中,doGetBean()方法

 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;
}
});

ObjectFactory的核心部分只调用了createBean()方法,继续探索createBean()

5、准备创建bean
这里作者提出了一点在探索spring源码的过程中的一点规律:一个真正干活的函数其实是以do开头的,比如doGetObjectFromFactoryBean,而给我们错觉的函数
getObjectFromFactoryBean,其实只是从全局角度去做一些统筹工作,这个规则对createBean也不例外,看createBean如何统筹工作:

 /**
* Central method of this class: creates a bean instance,
* populates the bean instance, applies post-processors, etc.
* @see #doCreateBean
*/
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException { if (logger.isDebugEnabled()) {
logger.debug("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.
// 锁定class,根据设置的class属性或者根据beanName来解析Class,具体在实现逻辑在resolveBeanClass()方法中
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一个机会来返回代理来替代真正的实例
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.isDebugEnabled()) {
logger.debug("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);
}
}

来看下具体步骤和功能
(1)根据设置的class属性或者是beanName来解析Class
(2)对override属性进行标记和验证
这个其实spring中没有override-method这样的配置,但是spring是存在lookup-method和replace-method的,而这两个配置的加载其实
就是将配置统一存放到BeanDefinition中的methodOverride属性里,这个函数的操作其实就是针对这两个属性
(3)应用初始化前的后处理器,解析指定bean是否存在初始化前的短路操作
(4)创建bean

5.1 处理override属性

prepareMethodOverrides()方法在org.springframework.beans.factory.support包下的AbstractBeanDefinition类中

 public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exists.
if (hasMethodOverrides()) {
Set<MethodOverride> overrides = getMethodOverrides().getOverrides();
synchronized (overrides) {
for (MethodOverride mo : overrides) {
prepareMethodOverride(mo);
}
}
}
} //继续看prepareMethodOverride(mo)方法的源码,在同一个类中:
/**
* Validate and prepare the given method override.
* Checks for existence of a method with the specified name,
* marking it as not overloaded if none found.
* @param mo the MethodOverride object to validate
* @throws BeanDefinitionValidationException in case of validation failure
*/
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.
// 标记MethodOverride暂未被覆盖,避免参数类型的检查的开销
mo.setOverloaded(false);
}
}

spring是存在lookup-method和replace-method的,而这两个配置的加载其实就是将配置统一存放到BeanDefinition中的methodOverride属性里,
这两个方法的实现原理是在bean实例化的时候检测到存在MethodOverride,会动态的为当前bean生成动态代理并使用对应的拦截器为bean做增强处理,
相关逻辑实现在bean的实例化部分详细及讲解
但是,对于方法的匹配来讲,如果一个类中存在若干个重载方法,那么,在函数调用及增强的时候,还需要根据参数类型进行匹配,来最终确认当前调用的是
哪个函数。但是,spring将一部分匹配工作在这里完成了,如果当前类中的方法只有一个,那么就设置重载方法没有重载,这样在后续调用的时候便可以直接
使用找到的方法,而不需要进行方法的参数匹配验证了,而且还可以提前对方法存在性进行验证。

5.2 实例化的前置处理
在真正调用doCreat方法创建bean之前调用了一个代理的方法,resolveBeforeInstantiation(beanName, mbdToUse),对BeanDefinition中属性做了前置处理,
当然,无论其中是否有逻辑实现,我们都可以理解,因为真正的逻辑实现前后留有处理函数,也是可扩展的一种体现,但是,这并不是最重要的,在函数中
还提供了一个短路判断,这才是最关键的部分(TODO:这里不是很懂,为什么这个短路操作最关键!!!)
if (bean != null) {
  return bean;
}
当前置处理返回的结果如果不为空,那么直接略过后续的bean的创建而直接返回结果,这一特性虽然很容易被忽略,但是起着至关重要的作用,我们熟悉的AOP功能
就是在这里判断的

org.springframework.beans.factory.support包下AbstractAutowireCapableBeanFactory类中resolveBeforeInstantiation方法

 /**
* Apply before-instantiation post-processors, resolving whether there is a
* before-instantiation shortcut for the specified bean.
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @return the shortcut-determined bean instance, or {@code null} if none
*/
@Nullable
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.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, 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了

 @Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
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的初始化后尽可能保证将注册的后处理器postProcessAfterInitialization方法应用到bean中,
因为如果返回的bean不为空,那么便不会再次经历普通bean的创建过程,所以只能在这里应用后处理器的postProcessAfterInitialization方法

 在讲解从缓存中获取单例bean的时候提过,spring中的规则是在bean的初始化后尽可能保证将注册的后处理器postProcessAfterInitialization方法应用到bean中,
因为如果返回的bean不为空,那么便不会再次经历普通bean的创建过程,所以只能在这里应用后处理器的postProcessAfterInitialization方法
@Override
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;
}

6、循环依赖

6.1什么是循环依赖
循环依赖就是循环引用,就是两个或者多个bean 相互之间的持有对方,比如:CircleA调用了CircleB,CircleB引用了CircleC,CircleC引用了CircleA,则
他们最终反应成一个环,此处不是循环调用,循环调用是方法之前的调用

6.2spring如何解决循环依赖
spring容器循环依赖包括构造器循环依赖和setter循环依赖,首先来定义一下循环引用类:

 public class TestA{

     private TestB testB;

     public void a(){
testB.b();
} public void setTestB(TestB testB){
this.testB = testB;
} public TestB getTestB(){
return testB;
}
} public class TestB{ private TestC testC; public void b(){
testC.c();
} public void setTestC(TestC testC){
this.testC = testC;
} public TestC getTestC(){
return testC;
}
} public class TestC{ private TestA testA; public void c(){
testA.a();
} public void setTestA(TestA testA){
this.testA = testA;
} public TestA getTestA(){
return testA;
}
}

spring 中将循环依赖的处理分成了三种情况:
(1)构造器循环依赖
表示通过构造器注入构成的循环依赖,次依赖是无法解决的,只能抛出异常BeanCurrentlyInCreationException异常表示循环依赖
如在创建TestA类时,构造器需要TestB,在创建TestB 时又发现需要TestC,则又去创建TestC,最终在创建TestC时发现又需要TestA,从而形成一个环,没法创建

spring容器将每一个正在创建的bean标识符放在一个“当前创建bean池”,bean标识符在创建过程中将一直保持在这个池中,因此如果在创建过程中发现自己已经在
“当前创建bean池”中,将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的bean将从“当前创建bean池”中清除掉
看一段配置文件,来分析一下其中的,在spring中的创建过程 这其实就是上面代码在xml中的翻译

<bean id="testA" class="com.bean.TestA">
  <constructor-arg index="0" ref="testB" />
</bean>
<bean id="testB" class="com.bean.TestB">
  <constructor-arg index="0" ref="testC" />
</bean>
<bean id="testC" class="com.bean.testC">
  <constructor-arg index="0" ref="testA" />
</bean>

解析:
spring容器创建“testA”bean,首先去“当前创建bean池”查找是否当前bean正在创建,如果没发现,则继续准备其需要的构造器参数”testB“,并将”testA“
标识符当到“当前创建bean池”
spring容器创建“testB”bean,首先去“当前创建bean池”查找是否当前bean正在创建,如果没发现,则继续准备其需要的构造器参数”testC“,并将”testB“
标识符当到“当前创建bean池”
spring容器创建“testC”bean,首先去“当前创建bean池”查找是否当前bean正在创建,如果没发现,则继续准备其需要的构造器参数”testA“,并将”testC“
标识符当到“当前创建bean池”,但是当去创建testA时,发现该bean标识符在“当前创建bean池”中,因为表示循环依赖,抛出BeanCurrentlyInCreationException

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

 addSingletonFactory(beanName, new ObjectFactory(){
public Object getObject(){
return getEarlyBeanRefrence(beanName,mbd,bean);
}
});

具体步骤分析:
spring容器创建“testA”bean,首先根据无参构造器创建bean,并暴露一个“ObjectFactory”,用于返回一个提前暴露一个创建中的bean,并将“testA”标识符
当到“当前创建bean池”,然后进行setter注入“testB”

spring容器创建“testB”bean,首先根据无参构造器创建bean,并暴露一个“ObjectFactory”,用于返回一个提前暴露一个创建中的bean,并将“testB”标识符
当到“当前创建bean池”,然后进行setter注入“circle”

spring容器创建“testC”bean,首先根据无参构造器创建bean,并暴露一个“ObjectFactory”,用于返回一个提前暴露一个创建中的bean,并将“testC”标识符
当到“当前创建bean池”,然后进行setter注入“testA”,进行注入“testA”时由于提前暴露了“ObjectFactory”工厂,从而使它返回提前暴露一个创建中的bean

最后在依赖注入“testA”和“testB”,完成依赖注入

(3)protoType范围的依赖处理
对于“protoType”作用域bean,spring容器无法完成依赖注入,因为spring容器不进行缓存“protoType”作用域的bean,因此无法暴露一个创建中的bean
对于“singleston”作用域的bean,可以通过“setAllowCircularReferences(false)”来禁用循环引用

spring源码学习之bean的加载(一)的更多相关文章

  1. spring源码学习之bean的加载(二)

    这是接着上篇继续写bean的加载过程,好像是有点太多了,因为bean的加载过程是很复杂的,要处理的情况有很多,继续... 7.创建bean 常规的bean的创建时通过doCreateBean方法来实现 ...

  2. spring源码学习之bean的加载(三)

    接着二中的继续写,那个都超过1000行了,哈,需要重新写一个,要不太长了,我都看不下去了 7.4 初始化bean doCreateBean函数中有这样一行代码:这行代码中initializeBean函 ...

  3. Spring源码分析之Bean的加载流程

    spring版本为4.3.6.RELEASE 不管是xml方式配置bean还是基于注解的形式,最终都会调用AbstractApplicationContext的refresh方法: @Override ...

  4. 【Spring源码分析】非懒加载的单例Bean初始化过程(下篇)

    doCreateBean方法 上文[Spring源码分析]非懒加载的单例Bean初始化过程(上篇),分析了单例的Bean初始化流程,并跟踪代码进入了主流程,看到了Bean是如何被实例化出来的.先贴一下 ...

  5. 【Spring源码分析】非懒加载的单例Bean初始化前后的一些操作

    前言 之前两篇文章[Spring源码分析]非懒加载的单例Bean初始化过程(上篇)和[Spring源码分析]非懒加载的单例Bean初始化过程(下篇)比较详细地分析了非懒加载的单例Bean的初始化过程, ...

  6. Spring源码分析:非懒加载的单例Bean初始化前后的一些操作

    之前两篇文章Spring源码分析:非懒加载的单例Bean初始化过程(上)和Spring源码分析:非懒加载的单例Bean初始化过程(下)比较详细地分析了非懒加载的单例Bean的初始化过程,整个流程始于A ...

  7. Spring源码分析:非懒加载的单例Bean初始化过程(下)

    上文Spring源码分析:非懒加载的单例Bean初始化过程(上),分析了单例的Bean初始化流程,并跟踪代码进入了主流程,看到了Bean是如何被实例化出来的.先贴一下AbstractAutowireC ...

  8. 【Spring源码分析】非懒加载的单例Bean初始化过程(上篇)

    代码入口 上文[Spring源码分析]Bean加载流程概览,比较详细地分析了Spring上下文加载的代码入口,并且在AbstractApplicationContext的refresh方法中,点出了f ...

  9. Spring源码分析:非懒加载的单例Bean初始化过程(上)

    上文[Spring源码分析]Bean加载流程概览,比较详细地分析了Spring上下文加载的代码入口,并且在AbstractApplicationContext的refresh方法中,点出了finish ...

随机推荐

  1. RESTful API -- rules

    RESTful介绍 REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”或“表现层状态转化”. 推荐 ...

  2. <scrapy爬虫>爬取腾讯社招信息

    1.创建scrapy项目 dos窗口输入: scrapy startproject tencent cd tencent 2.编写item.py文件(相当于编写模板,需要爬取的数据在这里定义) # - ...

  3. 基于baseline、svd和stochastic gradient descent的个性化推荐系统

    文章主要介绍的是koren 08年发的论文[1],  2.3部分内容(其余部分会陆续补充上来).koren论文中用到netflix 数据集, 过于大, 在普通的pc机上运行时间很长很长.考虑到写文章目 ...

  4. Anaconda如何配置多版本Python

    https://blog.csdn.net/guanmaoning/article/details/80031279

  5. 【心无旁骛】vuex-typescript-example

    我不惮以最大的赞美去赞美这样的项目,真的是非常有创意又有能力. 先放上我喜欢的这个项目的开源地址:https://github.com/gluons/vuex-typescript-example 我 ...

  6. CF集萃3

    CF1118F2 - Tree Cutting 题意:给你一棵树,每个点被染成了k种颜色之一或者没有颜色.你要切断恰k - 1条边使得不存在两个异色点在同一连通块内.求方案数. 解:对每颜色构建最小斯 ...

  7. Redis多API开发

    目录 Redis API支持 redis-py安装方式 Python 连接redis 直接连接 使用连接池连接 Windows 连接redis数据库 一.下载Redis Desktop Manager ...

  8. skyline(TG,arcgis server)BS系统部署

    skyline的BS系统部署,正常情况下应该是TG来统一管理,SFS对矢量数据服务进行管理.但我们一直是试用许可安装的TG,发现SFS要么安装不成功,要么就是不稳定.对于Fly工程可以通过Publis ...

  9. linux命令统计文件中某个字符串出现的次数

    1.使用grep linux grep命令在我的随笔linux分类里有过简单的介绍,这里就只简单的介绍下使用grep命令统计某个文件这某个字符串出现的次数,首先介绍grep命令的几个参数,详细参数请自 ...

  10. MySQL数据库 数据库的引擎,模式,数据类型(更新中...)

    数据库的引擎:驱动数据的方式-数据库优化 前提:引擎是建表的时候规定的,提供给表使用的,不是数据库 mysql> show engines #展示所有引擎 #几种比较常见的引擎 # innodb ...