Spring5源码分析(021)——IoC篇之bean加载
- 1、容器初始化(bean配置解析)
- 首先,通过多种方式加载相应的配置元数据 Configuration Metadata (使用 Resource 体系 和 ResourceLoader)
- 其次,对加载的配置进行解析,组装成对应的 BeanDefinition (BeanDefinition 体系 和 BeanDefinitionReader 体系)
- 然后,将解析后的 BeanDefinition 注册存储到 BeanDefinitionRegistry 中(BeanFactory 体系)
- 最后,完成容器初始化
- 2、bean加载和使用
- 容器的初始化只是完成了 bean 配置的解析,还需要通过 bean 加载阶段才能真正使用 bean ,这是通过显式或者隐式调用 BeanFactory#getBean(...) 时触发的
- bean 加载首先会检查所请求的对象是否已经加载初始化了,如果没有,则会根据解析注册的 bean 信息完成相关的初始化和依赖注入,然后将初始化完成的对象返回
- bean 加载完成后就可以直接使用返回的 bean 来进行相关操作了。
@Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); }
本文目录结构如下:
1、getBean(String name)
@Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); }
getBean(String name) 方法内部其实是委托给 doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) 进行处理,其参数说明如下:
- name : 需要获取的 bean 名称,可能是真正的 beanName ,有可能是别名,还可能是带 FactoryBean 前缀 & 的名称
- requiredType : 需要获取的 bean 的类型
- args : 创建 bean 时传递的参数,仅限于创建 bean 时使用
- typeCheckOnly : 是否仅仅只是类型检查
2、doGetBean(...)
/// org.springframework.beans.factory.support.AbstractBeanFactory /** * Return an instance, which may be shared or independent, of the specified bean. * <p>返回指定 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 { // 1、转换对应的 beanName // 会去掉 FactoryBean 工厂 bean 引用前缀 ( & ),并将别名(如果是)转化成映射的 beanName final String beanName = transformedBeanName(name); Object bean; // Eagerly check singleton cache for manually registered singletons. /* * 2、从缓存或者实例工厂中获取单例 bean 对象:检查缓存中或者实例工厂中是否有对应的 bean 实例 * 为什么需要使用这段代码,来检查缓存? * 因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免依赖循环, * Spring 创建 bean 的原则是不等 bean 创建完成就会将创建 bean 的 ObjectFactory 提前曝光, * 也就是将 ObjectFactory 加入到缓存中,一旦下个 bean 创建时需要依赖上个 bean 则直接使用 ObjectFactory */ // 检查注册的单例缓存中是否有对应的单例 Object sharedInstance = getSingleton(beanName); 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 + "'"); } } // 返回对应的实例,有时候存在诸如 FactoryBean 的情况下,可能返回 FactoryBean 本身, // 也有可能返回的是 FactoryBean 指定方法返回的实例 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // Fail if we're already creating this bean instance: // We're assumably within a circular reference. // 3、原型模式的依赖检查 // 只有在单例情况下才会尝试解决循环依赖,原型模式情况下,如果存在 A 中有 B 的属性, B 中有 A 的属性, // 那么当依赖注入的时候,就会产生A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,也就是下面的情况。 // 原型模式下如果存在循环依赖则会抛出异常 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // 4、检查 parentBeanFactory 是否存在对应的 bean // Check if bean definition exists in this factory. BeanFactory parentBeanFactory = getParentBeanFactory(); // 当前容器中没有找到,则从父类容器中加载 // 如果 beanDefinitionMap 中也就是在所有已经加载的类中不包括 beanName 指定的 bean, // 则尝试从 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 if (requiredType != null) { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } } // 5、如果不是仅仅做类型检查则是创建 bean ,这里需要进行记录 if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { // 6、将存储 XML 配置的 GenericBeanDefinition 转换成 RootBeanDefinition , // 如果指定的 beanName 是子 bean 的话同时会合并父类的相关属性 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // 7、处理依赖的 bean // Guarantee initialization of beans that the current bean depends on. // 若存在依赖则需要递归实例化依赖的 bean String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { // 循环依赖的情况,depends-on 是强制依赖 if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } // 缓存依赖调用 registerDependentBean(dep, beanName); try { // 递归调用获取依赖的 bean getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // 8、针对不同 scope 进行 bean 的实例化 // 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. // 显式从单例缓存中删除bean实例 // 因为单例模式下为了解决循环依赖,可能已经存在了,所以销毁它 destroySingleton(beanName); throw ex; } }); // 从bean实例中获取对象,获取Bean实例本身或其创建的对象(如果是 FactoryBean) bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } // prototype 原型模式下的创建(new) else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { // 1)、创建前的前置处理 beforePrototypeCreation(beanName); // 2)、创建 bean 实例对象 prototypeInstance = createBean(beanName, mbd, args); } finally { // 3)、创建后的后置处理 afterPrototypeCreation(beanName); } // 4)、从bean实例中获取对象,则获取Bean实例本身或其创建的对象(如果是 FactoryBean) bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } // 指定的 scope 下实例化 bean else { // 获取指定 scopeName 的 Scope 对象 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 { // 通过指定的 scope 对象来创建和实例化 bean Object scopedInstance = scope.get(beanName, () -> { // 1)、创建前的前置处理 beforePrototypeCreation(beanName); try { // 2)、创建 bean 实例对象 return createBean(beanName, mbd, args); } finally { // 3)、创建后的后置处理 afterPrototypeCreation(beanName); } }); // 4)、从bean实例中获取对象 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; } } // 9、类型转换 : 检查需要的类型是否符合 bean 的实际类型 // Check if required type matches the type of the actual bean instance. 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.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; }
比较少有的一个长方法,可见逻辑相当的复杂,根据上面给出的部分代码注释,可以粗略地了解 Spring 加载 bean 的整个过程,而对于加载过程所涉及的步骤大致如下:
- 1、转换对应的 beanName,参考 【2.1、转换对应的 beanName】
- 2、从缓存或者实例工厂中获取单例 bean 对象,参考 【2.2、从缓存中获取单例 bean】
- 3、原型模式的依赖检查,参考 【2.3、原型模式的依赖检查】
- 4、检查 parentBeanFactory 是否存在对应的 bean ,参考 【2.4、检查 parentBeanFactory 是否存在对应的 bean】
- 5、如果不是仅仅做类型检查则是创建 bean ,这里需要进行记录,参考 【2.5、将指定的 bean 标记为已创建或即将创建】
- 6、将存储 XML 配置的 GenericBeanDefinition 转换成 RootBeanDefinition ,参考 【2.6、将存储 XML 配置的 GenericBeanDefinition 转换成 RootBeanDefinition】
- 7、处理依赖 bean ,参考 【2.7、依赖处理】
- 8、针对不同 scope 进行 bean 的实例化,参考 【2.8、针对不同scope进行bean的创建】
- 9、类型转换 : 检查需要的类型是否符合 bean 的实际类型,参考 【2.9、类型转换】
2.1、转换对应的 beanName
/// org.springframework.beans.factory.support.AbstractBeanFactory // 1、转换对应的 beanName // 会去掉 FactoryBean 工厂 bean 引用前缀 ( & ),并将别名(如果是)转化成映射的 beanName final String beanName = transformedBeanName(name);
- 1、去除 FactoryBean 的前缀修饰符 “&”,例如传入的参数 name = "&myBeanName",那么首先会去除 & ,剩下的就是 “myBeanName”,这里还会去除重复的 & 前缀,具体参考 org.springframework.beans.factory.BeanFactoryUtils#transformedBeanName(String name)
- 2、取指定的 alias 所表示的最终的 beanName ,例如别名 A 指向名称为 B 的 bean 则返回 B;如果 B 也是别名,且别名 B 指向的是名称为 C 的 bean 则返回 C,具体参考 org.springframework.core.SimpleAliasRegistry#canonicalName(String name)
/// org.springframework.beans.factory.support.AbstractBeanFactory /** * Return the bean name, stripping out the factory dereference prefix if necessary, * and resolving aliases to canonical names. * <p>返回 beanName ,必要时去掉 FactoryBean 引用前缀 ( & ) ,并将别名解析为规范名称。 * @param name the user-specified name * @return the transformed bean name */ protected String transformedBeanName(String name) { return canonicalName(BeanFactoryUtils.transformedBeanName(name)); }
- 1、通过调用 BeanFactoryUtils#transformedBeanName(String name) 方法,去除重复的 FactoryBean 引用前缀修饰符 ( & ),代码如下:
- 这里的逻辑比较简单,就是直接去掉 name 中的 & 前缀(如有)
- transformedBeanNameCache 集合是为了缓存已经转换过的结果,方便下次获取时直接返回。
- 关于 FactoryBean 的小知识,后面会有相关介绍,参考下一篇:《Spring5源码分析(022)——IoC篇之bean加载:FactoryBean的用法》
/// org.springframework.beans.factory.BeanFactoryUtils /** * Cache from name with factory bean prefix to stripped name without dereference. * <p>缓存 {@link #transformedBeanName(String)} 已经转换好的结果(去掉 BeanFactory 前缀 & ) * @since 5.1 * @see BeanFactory#FACTORY_BEAN_PREFIX */ private static final Map<String, String> transformedBeanNameCache = new ConcurrentHashMap<>(); /** * Return the actual bean name, stripping out the factory dereference * prefix (if any, also stripping repeated factory prefixes if found). * <p>返回实际的 beanName,去掉 FactoryBean 前缀 &(如果有,也会去掉重复的前缀) * @param name the name of the bean * @return the transformed name * @see BeanFactory#FACTORY_BEAN_PREFIX */ public static String transformedBeanName(String name) { Assert.notNull(name, "'name' must not be null"); // 不是 & 开头直接返回 if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { return name; } // 去掉所有的 & 前缀,然后缓存到 transformedBeanNameCache 中 return transformedBeanNameCache.computeIfAbsent(name, beanName -> { do { beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); } while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)); return beanName; }); }
- 2、通过调用 SimpleAliasRegistry#canonicalName(String name) 方法,来获取最终的 beanName ,代码如下:
- 这里其实主要是一个循环获取 beanName 的过程,例如 a -> b , b -> c , c -> beanName,则最终返回 beanName 。
/// org.springframework.core.SimpleAliasRegistry /** * Determine the raw name, resolving aliases to canonical names. * <p>确定原始名称,将别名解析为规范名称。 * @param name the user-specified name * @return the transformed name */ public String canonicalName(String name) { String canonicalName = name; // 循环处理别名,例如 a -> b , b -> c , c -> beanName // Handle aliasing... String resolvedName; do { resolvedName = this.aliasMap.get(canonicalName); if (resolvedName != null) { canonicalName = resolvedName; } } while (resolvedName != null); return canonicalName; }
2.2、从缓存中获取单例 bean
/// org.springframework.beans.factory.support.AbstractBeanFactory // Eagerly check singleton cache for manually registered singletons. /* * 2、从缓存或者实例工厂中获取单例 bean 对象:检查缓存中或者实例工厂中是否有对应的 bean 实例 * 为什么需要使用这段代码,来检查缓存? * 因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免依赖循环, * Spring 创建 bean 的原则是不等 bean 创建完成就会将创建 bean 的 ObjectFactory 提前曝光, * 也就是将 ObjectFactory 加入到缓存中,一旦下个 bean 创建时需要依赖上个 bean 则直接使用 ObjectFactory */ // 检查注册的单例缓存中是否有对应的单例 Object sharedInstance = getSingleton(beanName); 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 + "'"); } } // 返回对应的实例,有时候存在诸如 FactoryBean 的情况下,可能返回 FactoryBean 本身, // 也有可能返回的是 FactoryBean 指定方法返回的实例 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); }
- 1、这里的从缓存中获取单例 bean ,其实也只是尝试加载,首先尝试从单例缓存 singletonObjects 中加载,然后再次尝试从 earlySingletonObjects 中加载,之后再尝试从 singletonFactories 中获取,因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖, Spring 中创建 bean 的原则是不等 bean 创建完成就会将创建 bean 的 ObjectFactory 并提前曝光加入到缓存中,一旦下一个 bean 创建时候需要依赖上一个 bean 则直接使用 ObjectFactory (这就是循环依赖的处理,后面的文章会对此进行重点讲解)。
- 2、如果从缓存中得到了 bean 的原始状态,还需要对 bean 进一步处理。缓存中记录的只是最原始的 bean 状态,并不一定是我们最终想要的 bean 。例如,当我们需要对 FactoryBean 即工厂 bean 进行处理,那么这里得到的其实是工厂 bean 的初始状态,但是我们真正需要的是工厂 bean 中定义的 factory-method 方法中返回的 bean ,而 getObjectForBeanInstance 方法就是来完成这些处理的,也有可能是需要返回 FactoryBean 本身,例如存在 & 前缀时。
2.3、原型模式的依赖检测
/// org.springframework.beans.factory.support.AbstractBeanFactory // Fail if we're already creating this bean instance: // We're assumably within a circular reference. // 3、原型模式的依赖检查 // 只有在单例情况下才会尝试解决循环依赖,原型模式情况下,如果存在 A 中有 B 的属性, B 中有 A 的属性, // 那么当依赖注入的时候,就会产生A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,也就是下面的情况。 // 原型模式下如果存在循环依赖则会抛出异常 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }
- 原型模式情况下,如果存在 A 中有 B 的属性, B 中有 A 的属性,那么当依赖注入的时候,就会产生A还未创建完的时候因为对于B的创建再次返回创建A,这就造成了造成循环依赖,也即是 isPrototypeCurrentlyInCreation(beanName) 为 true 的情况。
- 单例模式下,因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,在 Spring 中创建 bean 的原则是不等 bean 创建完成就会将创建 bean 的 ObjectFactory 并提前曝光加入到缓存中,一旦下一个 bean 创建时候需要依赖上一个 bean 则直接使用 ObjectFactory (第3步中提到的)。
2.4、检查 parentBeanFactory 是否存在对应的 bean
/// org.springframework.beans.factory.support.AbstractBeanFactory // 4、检查 parentBeanFactory 是否存在对应的 bean // Check if bean definition exists in this factory. BeanFactory parentBeanFactory = getParentBeanFactory(); // 当前容器中没有找到,则从父类容器中加载 // 如果 beanDefinitionMap 中也就是在所有已经加载的类中不包括 beanName 指定的 bean, // 则尝试从 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 if (requiredType != null) { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } }
从代码上看,如果当前缓存中没有对应的 bean 的话则直接转到父类工厂中去加载。这是存在继承的情况下才会出现的场景,也即是存在父类 BeanFactory 即 parentBeanFactory ,且当前 BeanFactory 中找到不到相关的 bean 定义(没有相关的bean定义 BeanDefinition ),就会委托 parentBeanFactory ,通过 parentBeanFactory 递归调用 getBean 方法进行获取 bean 。具体分析参考:《Spring5源码分析(024)——IoC篇之bean加载:parentBeanFactory和依赖处理》
2.5、类型检查
/// org.springframework.beans.factory.support.AbstractBeanFactory // 5、如果不是仅仅做类型检查则是创建 bean ,这里需要进行记录 if (!typeCheckOnly) { markBeanAsCreated(beanName); }
类型检查,将指定的 bean 标记为已创建或即将创建,具体分析参考:《Spring5源码分析(024)——IoC篇之bean加载:parentBeanFactory和依赖处理》
2.6、将存储 XML 配置的 GenericBeanDefinition 转换成 RootBeanDefinition
/// org.springframework.beans.factory.support.AbstractBeanFactory // 6、将存储 XML 配置的 GenericBeanDefinition 转换成 RootBeanDefinition , // 如果指定的 beanName 是子 bean 的话同时会合并父类的相关属性 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args);
前面从 bean 的解析过程中我们可以知道,从 xml 配置文件中读取到的 bean 信息是存储在 GenericBeanDefinition 中的,而 Spring 中所有的 bean 后续的处理都是针对 RootBeanDefinition 的,因此这里需要进行一个转换,转换的同时如果父类 bean 不为空的话,则会一并合并父类的属性。详细的分析请参考:《Spring5源码分析(024)——IoC篇之bean加载:parentBeanFactory和依赖处理》
2.7、依赖处理
/// org.springframework.beans.factory.support.AbstractBeanFactory // 7、处理依赖的 bean // Guarantee initialization of beans that the current bean depends on. // 若存在依赖则需要递归实例化依赖的 bean String[] dependsOn = mbd.getDependsOn(); 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 { // 递归调用获取依赖的 bean getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } }
因为 bean 的初始化过程中很可能会用到某些属性,而某些属性很可能是动态配置的,并且配置成依赖于其他的 bean ,那么这个时候就有必要先加载依赖的bean ,所以,在 Spring 的加载顺序中,在初始化某一个 bean 的时候首先会初始化这个 bean 所对应的依赖。详细的分析请参考:《Spring5源码分析(024)——IoC篇之bean加载:parentBeanFactory和依赖处理》
2.8、针对不同scope进行bean的创建
/// org.springframework.beans.factory.support.AbstractBeanFactory // 8、针对不同 scope 进行 bean 的实例化 // 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. // 显式从单例缓存中删除bean实例 // 因为单例模式下为了解决循环依赖,可能已经存在了,所以销毁它 destroySingleton(beanName); throw ex; } }); // 从bean实例中获取对象,获取Bean实例本身或其创建的对象(如果是 FactoryBean) bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } // prototype 原型模式下的创建(new) else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { // 1)、创建前的前置处理 beforePrototypeCreation(beanName); // 2)、创建 bean 实例对象 prototypeInstance = createBean(beanName, mbd, args); } finally { // 3)、创建后的后置处理 afterPrototypeCreation(beanName); } // 4)、从bean实例中获取对象,则获取Bean实例本身或其创建的对象(如果是 FactoryBean) bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } // 指定的 scope 下实例化 bean else { // 获取指定 scopeName 的 Scope 对象 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 { // 通过指定的 scope 对象来创建和实例化 bean Object scopedInstance = scope.get(beanName, () -> { // 1)、创建前的前置处理 beforePrototypeCreation(beanName); try { // 2)、创建 bean 实例对象 return createBean(beanName, mbd, args); } finally { // 3)、创建后的后置处理 afterPrototypeCreation(beanName); } }); // 4)、从bean实例中获取对象 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); } }
接触过 Spring 的都清楚,在 Spring 中存在着不同的 scope ,其中默认的是 singleton ,但是还有些其他的 scope 配置,如 prototye 、 request 、 session 等。在这个过程中,Spring 会根据不同的配置进行不同的初始化策略。详细的分析请参考:《Spring5源码分析(025)——IoC篇之bean加载:根据各种scope进行bean的实例化》
2.9、类型转换
/// org.springframework.beans.factory.support.AbstractBeanFactory // 9、类型转换 : 检查需要的类型是否符合 bean 的实际类型 // Check if required type matches the type of the actual bean instance. 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.isTraceEnabled()) { logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } }
经过前面的处理,程序到这里返回 bean 后已经基本结束了。通常对该方法的调用参数 requiredType 都为 null ,也即是前面通过 getBean(String name) 的方式来获取,但是可能会存在这样的情况,返回的 bean 其实是个 String ,但是 requiredType 却传入 Integer 类型,那么这时候类型转换就会起作用了,它的功能就是将返回的 bean 转换成 requiredType 所指定的类型。当然,String 转换成 Integer 是最简单的一种转换,在 Spring 中提供了各种各样的转换器,用户也可以自己扩展转换器来满足自定义需求。
3、参考
- [1]spring 官方文档 5.2.3.RELEASE:https://docs.spring.io/spring-framework/docs/5.2.3.RELEASE/spring-framework-reference/core.html
- [2]Spring源码深度解析(第2版),郝佳,P86-P91
- [3]相关注释和案例可参考笔者 github 链接:https://github.com/wpbxin/spring-framework