前言
个人认为Spring最大的魅力就是 依赖注入,从这篇文章开始我们再次对Spring的 IOC 部分进行一些梳理和复习。首先我们先讲一下 BeanFactory 的getBean(String)。本文篇幅可能略长,请胖友们见谅
1 战略上俯视 getBean
1.1 getBean 的声明和实现
getBean
- 方法声明于
org.springframework.beans.factory.BeanFactory, - 实现于
org.springframework.beans.factory.support.AbstractBeanFactory
其实关于 BeanFactory 以及他的实现类有蛮多要讲的,我们后面有时间再细说
1.2 源码镇楼
1.2.1 getBean
/**
* 空壳方法,具体的操作其实在 doGetBean
* @param name the name of the bean to retrieve
* @return
* @throws BeansException
*/
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
- getBean其实就是一个空壳方法,具体的实现都在
doGetBean这个方法里(熟悉Spring胖友们可能对这种写法已经习惯了)
1.2.2 doGetBean
/**
* 获取bean
*
* @param name bean的name
* @param requiredType 获取的bean的类型,默认是null
* @param args 实例化参数,默认是null
* @param typeCheckOnly
* @param <T>
* @return
* @throws BeansException 抛出异常
*/
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
/**
* <1> 获取beanName
* 这一步操作主要是有2个原因
* 1. 别名,Spring是支持bean别名的,我们要向获取真正的bean,必须要拿到最原始的beanName
* 2. 工厂方法 当name以 & 字符开头时说明调用者想获取 FactoryBean本身,而不是FactoryBean所实现的类,
* 但是BeanFactory中 普通bean和 FactoryBean本身的存储方式都是一致的,所以需要将 & 符号移除
*/
String beanName = transformedBeanName(name);
Object beanInstance;
/**
* 从缓存中获取单例 bean。
* Spring 是使用 Map 作为 beanName 和 bean 单例bean实例的缓存的(其中key-> beanName, value -> bean)Map本身就不允许key重复
* 所以这里暂时可以把 getSingleton(beanName) 等价于 beanMap.get(beanName)。当然实际原理并没有这么简单哈
*/
Object sharedInstance = getSingleton(beanName);
/**
* 如果 sharedInstance == null,说明还没初始化好(BeanFactory并不会一开始就初始化好所有的bean,而是等到需要的时候才初始化--懒加载)
* 如果 sharedInstance !=null 那 args 也没啥用了,因为不会再初始化一次
*/
if (sharedInstance != null && args == null) {
//打印的一些日志,不需要理会,其中 isSingletonCurrentlyInCreation 是判断单例bean是不是在创建中
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
} else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
/**
* 1 sharedInstance 如果是个普通的单例bean,该方法会直接返回bean,
* 2 sharedInstance 如果是个FactoryBean类型的,则需要调用 getObject 获取真正的FactoryBean然后返回《在这里,普通bean 和FactoryBean被一视同仁,只不过获取方式不大一样而已》
*/
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
/**
* 走到这里则说明 sharedInstance 可能是空,有2中可能性
* 1 beanName对应的实例还没创建好,
* 2 beanName对应的实例可能在父容器中创建了,需要再父容器查找
*/
/**
* BeanFactory 不会缓存Prototype类型的bean,直接抛出异常
*/
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
/**
* 如果sharedInstance == null,先去父容器去查找
*/
//获取父容器
BeanFactory parentBeanFactory = getParentBeanFactory();
/**
* 如果父容器不为null, 且 beanDefinitionMap 不包含该bean
*/
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
/**
* 获取 name 对应的 beanName,如果 name 是以 & 字符开头,则返回 & + beanName
* 这里和上面有点区别,先是处理别名 然后如果该beanName是 factoryBean name的话,会把 & 还原
*/
String nameToLookup = originalBeanName(name);
/**
* 如果父容器是 AbstractBeanFactory 或者其子类,
*/
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
} else if (args != null) {
/**
* 如果初始化参数不为null
*/
return (T) parentBeanFactory.getBean(nameToLookup, args);
} else if (requiredType != null) {
/**
* 如果 requiredType 不为null
*/
return parentBeanFactory.getBean(nameToLookup, requiredType);
} else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
/**
* 如果 typeCheckOnly 参数为false, 标记该bean正在创建中
*/
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
/**
* 合并父 BeanDefinition 与子 BeanDefinition
*/
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
/**
* 检查是否有依赖,如果有的话,确保其依赖优先初始化
* 该方法获取当前bean的依赖项
*/
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
/**
* 检测是否存在 depends-on 循环依赖,若存在则抛异常。比如 A 依赖 B,B 又依赖 A,他们的配置如下:
* <bean id="beanA" class="BeanA" depends-on="beanB">
* <bean id="beanB" class="BeanB" depends-on="beanA">
* beanA 要求 beanB 在其之前被创建,但 beanB 又要求 beanA 先于它
* 创建。这个时候形成了循环,对于 depends-on 循环,Spring 会直接
* 抛出异常
*
* 这里会有2个Map分别是 dependentBeanMap dependenciesForBeanMap
* dependentBeanMap key-> beanName, value -> 依赖该bean的所有bean集合 记录谁依赖当前bean
* dependenciesForBeanMap key-> beanName, value->该bean依赖的所有bean 集合 记录当前bean依赖谁
* 思路清奇啊
*/
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
/**
* 这一步主要是注册依赖记录,不然上一步的数据木得呀
* 将当前beanName注册到 dependentBeanMap, 将dep注册到 dependenciesForBeanMap
*/
registerDependentBean(dep, beanName);
try {
/**
* 依次加载所依赖的bean,重复操作
*/
getBean(dep);
} catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
/**
* 如果是单例bean
*/
if (mbd.isSingleton()) {
/**
* 这里并没有直接调用 createBean 方法创建 bean 实例,而是通过
* getSingleton(String, ObjectFactory) 方法获取 bean 实例。
* getSingleton(String, ObjectFactory) 方法会在内部调用
* ObjectFactory 的 getObject() 方法创建 bean,并会在创建完成后,
* 将 bean 放入缓存中。关于 getSingleton 方法的分析,本文先不展开 后面的文章中进行分析
*/
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
/**
* 发生异常的话 销毁bean
*/
destroySingleton(beanName);
throw ex;
}
});
/**
* 如果bean是FactoryBean, 则调用工厂方法获取真正的bean,单例则直接返回
*/
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
/**
* 创建原型模式bean
*/
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
} finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
/**
* 其他类型的bean
*/
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
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);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
} catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
} catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
} finally {
beanCreation.end();
}
}
/**
* 会做一些类型转换的事情
*/
return adaptBeanInstance(name, beanInstance, requiredType);
}
个人觉得这2个beanMap很容易被搞混,这里特意贴出来,仅供参考
- dependentBeanMap key-> beanName, value -> 依赖该bean的所有bean集合 记录谁依赖当前bean
- dependenciesForBeanMap key-> beanName, value->该bean依赖的所有bean 集合 记录当前bean依赖谁
流程图如下
2 细节代码剖析
2.1 beanName转换
/**
* 返回beanName
* @param name
* @return
*/
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
/**
* 如果 name 是以 & 开头,则截取后面返回,该操作主要是给FactoryBean做特殊处理,毕竟在BeanFactory中,FactoryBean和普通Bean无差
* 比如 name = "&&&&&person",最终会被转成 person
* @param name
* @return
*/
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
/**
* 主要是出路别名,里面有循环
* 这里使用 while 循环进行处理,原因是:可能会存在多重别名的问题,即别名指向别名。比如下面的配置:
* <bean id="hello1" class="service.Hello"/>
* <alias name="hello1" alias="aliasA1"/>
* <alias name="aliasA1" alias="aliasB"/>
* <p>
* 上面的别名指向关系为 aliasB -> aliasA1 -> hello1,对于上面的别名配置,aliasMap 中数据
* 视图为:aliasMap = [<aliasB, aliasA1>, <aliasA1, hello1>]。通过下面的循环解析别名
* aliasB 最终指向的 hello1
*
* @param name
* @return
*/
public String canonicalName(String name) {
String canonicalName = name;
String resolvedName;
do {
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
2.2 从缓存中获取bean getSingleton
我们都知道, 对于单例 Bean Spring 只会实例化一次,那么如何保证多次获取bean的时候返回的都是同一个呢?答案就是 缓存, 当然这里说的缓存和 Redis 没有半毛钱关系哈! 废话不多说,上代码
@Override
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
/**
*
* @param beanName
* @param allowEarlyReference 是否允许其他bean引用正在创建的bean, 同时也是解决循环依赖的关键点
* @return
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
/**
* singletonObjects 是 ConcurrentHashMap 结构,key->beanName, value->bean
*/
Object singletonObject = this.singletonObjects.get(beanName);
/**
* 如果 singletonObject==null 表名未创建,或者正在创建中
*
*/
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
/**
* 从 earlySingletonObjects 中获取提前曝光的 bean,用于处理循环引用
*/
singletonObject = this.earlySingletonObjects.get(beanName);
/**
* 如果 singletonObject==null, 且允许提前曝光bean
*/
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
/**
* 从bean工厂缓存中获取对应 工厂类
*/
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
/**
* 如果工厂类不为null 直接获取且赋值给 singletonObject
* 将 singletonObject 放到 earlySingletonObjects 这个缓存中,可以解决后续的循环依赖
* 同时将beanFacotry移除,后续不会在用到了
*/
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
上述代码中有3个缓存集合,是面试中的重点,我们简单说说
| 缓存名 | 用途 |
|---|---|
singletonObjects | 用于存放完全初始化完成后的bean,可以直接使用 |
earlySingletonObjects | 用于存放还在初始化中的bean,用于解决循环依赖 |
singletonFactories | 用户存放bean工厂,bean工厂所产生的bean还未完全初始化号,其所生成的bean下一步会被放在 earlySingletonObjects 中 |
2.3 合并父子BeanDefinition
相信有部分胖友和我一样,对bean的合并 getMergedLocalBeanDefinition 有点摸不着头脑,其实我们说的父子 BeanDefinition 如下配置, stu 继承了person,可以覆盖父类中的配置
<bean id="person" class="com.fenghuolun.spring.nazha.bean.Person">
<property name="content" value="tec"/>
</bean>
<bean id="stu" parent="person">
<property name="content" value="child"/>
</bean>
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// 检测 mergedBeanDefinitions 是否已经包含了beanName对应的bean,如果已包含,直接返回
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null && !mbd.stale) {
return mbd;
}
//调用重载方法
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
throws BeanDefinitionStoreException {
return getMergedBeanDefinition(beanName, bd, null);
}
/**
*
* @param beanName
* @param bd
* @param containingBd
* @return
* @throws BeanDefinitionStoreException
*/
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
//同步锁
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
// containingBd 如果是null, 则 从缓存获取对应的baen赋值给 mbd
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null || mbd.stale) {
previous = mbd;
//如果 bd.getParentName()==null,说明无父配置,直接将当前的 BeanDefinition 升级为 RootBeanDefinition
if (bd.getParentName() == null) {
// 用bean
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
} else {
mbd = new RootBeanDefinition(bd);
}
} else {
BeanDefinition pbd;
try {
/**
* 通过老方法获取beanName
*/
String parentBeanName = transformedBeanName(bd.getParentName());
/**
* 判断父类beanName和子类BeanName是否相同,如果相同,说明父类bean一定在父容器中(因为容器底层采用的Map,key是唯一的)
*
*/
if (!beanName.equals(parentBeanName)) {
/**
* 再次调用 getMergedBeanDefinition,参数值未parentBeanName,用于合并父 BeanDefinition 和爷爷辈的BeanDefinition。
* 如果爷爷辈的 BeanDefinition 仍有父BeanDefinition,则继续合并
*/
pbd = getMergedBeanDefinition(parentBeanName);
} else {
/**
* 获取父容器,并判断,父容器的类型,若不是 ConfigurableBeanFactory 则判抛出异常
*/
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
} else {
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without a ConfigurableBeanFactory parent");
}
}
} catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
/**
* 以父 BeanDefinition 的配置信息为蓝本创建 RootBeanDefinition,也就是“已合并的 BeanDefinition”
* 同时用 子 BeanDefinition 中的属性覆盖父 BeanDefinition 中的属性
*/
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(bd);
}
/**
* 如果用户未配置scope属性,默认单例模式
*/
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(SCOPE_SINGLETON);
}
/**
* 改写 mdb的 scope属性
*/
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
return mbd;
}
}
2.4 从 FactoryBean 中获取 bean 实例
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 如果name以 & 开头
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
//如果 beanInstance 不是FactoryBean 抛出异常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
//设置mbd 为工厂Bean
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
/**
* 到了这一步,beanInstance 要么是工厂bean 要么是普通bean, 如果是普通bean直接返回
*/
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
//后续流程中 beanInstance 肯定是个 FactoryBean
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
} else {
/**
* 如果 mbd 为null(从 getBean方法进来的话, mbd肯定是null哈),从缓存中获取beanName对应的FactoryBean
* FactoryBean生成的单例bean都放在 factoryBeanObjectCache 这个Map中
*/
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
//如果 object == null, 将 beanInstance 转化为 FactoryBean
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// 合并 BeanDefinition
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
/**
* synthetic 字面意思是"合成的",这个字段还不大清楚是啥意思
*/
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 调用 getObjectFromFactoryBean 方法继续获取实例
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
/**
* 如果 factory是单例模式 且 singletonObjects 包含beanName,
* 注意 FactoryBean也有单例模式和非单例模式,和普通Bean没有区别
*/
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
//缓存中获取bean
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
//bean == null ,使用工厂获取bean
object = doGetObjectFromFactoryBean(factory, beanName);
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
//如果是 !synthetic
if (shouldPostProcess) {
//当前bean正在创建中,直接返回
if (isSingletonCurrentlyInCreation(beanName)) {
return object;
}
// 添加到 singletonsCurrentlyInCreation
beforeSingletonCreation(beanName);
try {
//后置处理,这里没有做啥事情其实
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
//从 singletonsCurrentlyInCreation 移除
afterSingletonCreation(beanName);
}
}
//FactoryBean 所创建的实例会被缓存在 factoryBeanObjectCache 中,供后续调用使用
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
需要重点关注下beforeSingletonCreation 和afterSingletonCreation
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
细心的胖友会发现singletonsCurrentlyInCreation 这个缓存又被用到哦 具体作用是啥,上门有具体的说明。这里就不多做赘述了。