上一篇Spring源码十六:Bean名称转化我们讨论doGetBean的第一个方法transformedBeanName方法,了解Spring是如何处理特殊的beanName(带&符号前缀)与Spring的别名机制。今天我们继续往方法下面看:
doGetBean
这个方法比较长,之所以每次都放到这里也是方便大家回忆,一次两次肯定记不住的,不过具体到某个章节讨论的点,在代码后面的截图都会给大家标注出来的。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 获取转换后的Bean名称
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 检查单例缓存中是否有手动注册的单例Bean
// 这里是三级缓存处理方法入
Object sharedInstance = getSingleton(beanName);
// 如果单缓存中存在则直接从缓存中获取,
// 如果不存在就走else分支,进行实例化
if (sharedInstance != null && args == null) {
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 + "'");
}
}
// 获取Bean的实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 如果当前bean还未被实例化,则在这个判断中准备实例化
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 如果bean的类型是prototype且正在创建,直接抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
// 检查Bean定义是否存在于当前工厂
/// 获取容器的父容器
BeanFactory parentBeanFactory = getParentBeanFactory();
// 存在父容器,且当前容器没有beanName的BeanDefinition,则通过父容器获取bean
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
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 if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
// 标记bean已经开始创建,其实就是将当前beanName 放入alreadyCreated容器中
markBeanAsCreated(beanName);
}
// 进入实例化bean阶段
// 1、处理BeanDefinition:合并同名的BeanDefinition、是否达到实例化标准
// 2、处理依赖的Bean,如果存在依赖其他的bean则递归所有需要依赖的bean,提前实例化需要依赖的Bean
// 3、开始创建Bean实例对象:根据作用域分类处理:
// 3.1 单例bean创建:创建单例bean的实例对象注册到容器中、获取容器中的对象
// 3.2.原型bean创建:实例化前置准备工作、创建原型bean实例对象注册都容器中、原型bean实例化后置处理、获取容器中的对象
// 3.3 其他bean创建:实例化前置准备工作、创建其他类型bean实例对象注册都容器中、其他类型bean实例化后置处理、获取容器中的对象
// 4、返回响应处理,根据入参转化bean的类型
try {
// 合并容器中beanName对应的BeanDefinition,得到新的root类型BeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 校验合并后的rootBeanDefinition是否达到实例化标准,abstractFlag默认是false,如果是true则抛出异常
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// 获取当前beanName所依赖的BeanNames数组
String[] dependsOn = mbd.getDependsOn();
// 如果依赖的bean不为空,则注册这些bean且递归调用getBean,提前实例化需要依赖的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 + "'");
}
// 注册依赖的bean
registerDependentBean(dep, beanName);
try {
// 递归调用getBean,需要依赖的Bean先实例化
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
// 判断beanDefinition是单例?
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
//是单例:则开始创建单例bean的实例
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实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 如果是原型bean
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实例对象
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 其他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, () -> {
// 创建其他类型作用域bean的前置准备工作
beforePrototypeCreation(beanName);
try {
// 创建其他类型作用域bean
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.
// 如果requiredType,且bean类型与入参要求不一致,则需要惊喜转换
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
// 将BeanDefinition转化成指定类型的bean
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
寻找实例化bean的入口
原型Bean校验
Spring中默认都是懒加载的单例bean,有因为单例bean全局唯一的特性,Spring为了提升性能避免频繁创建所以引入的缓存。将实例化过的bean放入缓存中。如下getSingleton方法就是判断单例缓存中是否存在同名的bean如果存在,则if逻辑。因为我们是第一次创建,缓存中自然没有我们的bean,所以进入else逻辑。
进入else逻辑,第一个处理方法如下,看到方法名称与注释大概也能这个方法是做了个基础校验,如果Bean的作用域是原型类型,且此时bean正在创建则抛出异常,说明
进入方法内部看下:
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null &&
(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}
方法isPrototypeCurrentlyInCreation中有一个集合prototypesCurrentlyInCreation,主要的逻辑就是判断下集合中是否存在beanName,prototype类型的bean实例每次来获取时都会创建一个新的bean实例,所以Spring也就没必要为这种类型的bean进行缓存;没有存放的缓存所以,一旦发现名称为beanName的bean正在创建,就会抛出异常来终止本次bean的创建。
当前容器没有beanName的BeanDefinition尝试去父容器获取
接着往下看:
有上述代码可知道:如果当前的Spring容器的父类容器是存在的,并且当前Spring容器中不存在beanName对应的BeanDefinition,就会到Spring的父类容器中获取bean的实例了。
进入originalBeanName方法看下:
protected String originalBeanName(String name) {
String beanName = transformedBeanName(name);
if (name.startsWith(FACTORY_BEAN_PREFIX)) {
beanName = FACTORY_BEAN_PREFIX + beanName;
}
return beanName;
}
这个方法要注意下,他对name进行了处理,先通过transformedBeanName方法获取转换后的名称,然后在判断原始参数传入的name是否以&开头,如果是则在拼上去,至于为啥怎么做后面在看,这里心眼有个印象:知道主要是处理FactoryBean好。
咱们再接着往下看:
上述代码就比较简单,无非是根据入参情况,去父类容器获取bean。
可以看到默认传入的都是false,这里还是简单看下markBeanAsCreate方法:
protected void markBeanAsCreated(String beanName) {
if (!this.alreadyCreated.contains(beanName)) {
synchronized (this.mergedBeanDefinitions) {
if (!this.alreadyCreated.contains(beanName)) {
// Let the bean definition get re-merged now that we're actually creating
// the bean... just in case some of its metadata changed in the meantime.
clearMergedBeanDefinition(beanName);
this.alreadyCreated.add(beanName);
}
}
}
}
上述方法判断集合alreadyCreated中是否存在beanName,alreadyCreated是用来记录已经创建了的bean的名称。
上述方法有一个double check不知道小伙伴有没有注意到,这个在框架内部还是有很多地方有使用到的。作用嘛,当然这也是为了避免多线程并发的问题,方法中最为关键的,就是在集合alreadyCreated中添加beanName,并且清除了beanName对应BeanDefinition相关的信息。
可以发现到目前为止都是准备工作,真正的入口就在下面:咱们我们接着往下看
Bean实例步骤
// 进入实例化bean阶段
// 1、处理BeanDefinition:合并同名的BeanDefinition、是否达到实例化标准
// 2、处理依赖的Bean,如果存在依赖其他的bean则递归所有需要依赖的bean,提前实例化需要依赖的Bean
// 3、开始创建Bean实例对象:根据作用域分类处理:
// 3.1 单例bean创建:创建单例bean的实例对象注册到容器中、获取容器中的对象
// 3.2.原型bean创建:实例化前置准备工作、创建原型bean实例对象注册都容器中、原型bean实例化后置处理、获取容器中的对象
// 3.3 其他bean创建:实例化前置准备工作、创建其他类型bean实例对象注册都容器中、其他类型bean实例化后置处理、获取容器中的对象
// 4、返回响应处理,根据入参转化bean的类型
try {
// 合并容器中beanName对应的BeanDefinition,得到新的root类型BeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 校验合并后的rootBeanDefinition是否达到实例化标准,abstractFlag默认是false,如果是true则抛出异常
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// 获取当前beanName所依赖的BeanNames数组
String[] dependsOn = mbd.getDependsOn();
// 如果依赖的bean不为空,则注册这些bean且递归调用getBean,提前实例化需要依赖的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 + "'");
}
// 注册依赖的bean
registerDependentBean(dep, beanName);
try {
// 递归调用getBean,需要依赖的Bean先实例化
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
// 判断beanDefinition是单例?
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
//是单例:则开始创建单例bean的实例
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实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 如果是原型bean
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实例对象
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 其他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, () -> {
// 创建其他类型作用域bean的前置准备工作
beforePrototypeCreation(beanName);
try {
// 创建其他类型作用域bean
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;
}
}
在上述代码中备注已经把try代码块的处理逻辑给大家分析了,这里简单总结下:
-
合并BeanDefinition:首先,Spring容器会合并同名的BeanDefinition,确保每个Bean的配置是最新的,并且检查BeanDefinition是否满足实例化的条件。
-
检查依赖关系:如果Bean定义了依赖关系(通过
depends-on
属性),Spring容器会先注册并实例化这些依赖的Bean。如果检测到循环依赖,会抛出异常。 -
创建Bean实例:根据Bean的作用域(单例、原型或其他自定义作用域),Spring容器会采取不同的实例化策略:
- 单例Bean:如果Bean是单例的,Spring容器会创建一个实例并将其注册到单例缓存中。
- 原型Bean:如果Bean是原型的,每次请求都会创建一个新的实例。
- 其他作用域Bean:对于其他自定义作用域的Bean,Spring容器会根据作用域的定义来创建和管理Bean的生命周期。
-
处理Bean的创建异常:如果在创建过程中发生异常,Spring容器会进行清理工作,并抛出异常。
-
获取Bean实例:最后,根据需要,Spring容器会返回Bean的实例或其代理。
小结
本篇咱们通过doGetBean方法一步一步进入,先是跳过了三级缓存获取单例bean方法,然后着重看了了原型Bean创建前的校验、父容器创建bean的场景,以及Spring容器在创建Bean实例时所遵循的步骤和逻辑。下一篇我们将探索Spring是如何来实例化bean。