上一篇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,则通过父容器获取beanif (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类型BeanDefinitionfinal 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,提前实例化需要依赖的Beanif (dependsOn != null) {for (String dep : dependsOn) {if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}// 注册依赖的beanregisterDependentBean(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);}// 如果是原型beanelse 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 {// 创建其他类型作用域beanreturn 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转化成指定类型的beanT 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类型BeanDefinitionfinal 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,提前实例化需要依赖的Beanif (dependsOn != null) {for (String dep : dependsOn) {if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}// 注册依赖的beanregisterDependentBean(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);}// 如果是原型beanelse 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 {// 创建其他类型作用域beanreturn 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。