在之前的文章中,我们分析了Spring的Ioc的初始化过程,实际上就是把 beanName 和 BeanDefinition 注册到DefaultListableBeanFactory的map中。
完成 bean 的注册之后, refresh() 还调用了很多后处理器的方法,其中有一个方法 finishBeanFactoryInitialization(),注释上面写着 Instantiateall remaining(non-lazy-init)singletons ,意味着非延迟加载的类,将在这一步实例化,完成类的加载
而我们使用到 context.getBean("beanName") 方法,如果对应的 bean 是非延迟加载的,那么直接就能拿出来进行使用,而延迟加载的 bean 就需要上面的步骤进行类的加载,加载完之后才能进行使用。接着分析一下Ioc的bean实例化过程:

一、getBean

当我们显示或者隐式地调用 BeanFactory#getBean(String name) 方法时,则会触发加载 Bean 阶段。代码如下:

// AbstractBeanFactory.java
@Override
public Object getBean(String name) throws BeansException {return doGetBean(name, null, null, false);
}

内部调用

//name :要获取 Bean 的名字
//requiredType :要获取 bean 的类型
//args :创建 Bean 时传递的参数。这个参数仅限于创建 Bean 时使用。
//typeCheckOnly :是否为类型检查。
doGetBean(String name, final Class<T> requiredType, Object[] args, boolean typeCheckOnly)

二、doGetBean

//真正实现向IOC容器获取Bean的功能,也是触发依赖注入功能的地方protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {//根据指定的名称获取被管理Bean的名称,剥离指定名称中对容器的相关依赖// 如果指定的是别名,将别名转换为规范的Bean名称
<1>       final String beanName = transformedBeanName(name);Object bean;// Eagerly check singleton cache for manually registered singletons.// 从缓存中获取已被创建过的单例Bean
<2>       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的工厂//     FactoryBean是创建创建对象的工厂Bean,两者之间有区别//获取给定Bean的实例对象,该对象要么是 bean 实例本身,要么就是 FactoryBean 创建的 Bean 对象//(为什么要再次获取呢,因为上面获取的sharedInstance不一定是完整的)
<3>           bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {// Fail if we're already creating this bean instance:// We're assumably within a circular reference.// 因为 Spring 只解决单例模式下的循环依赖,在原型模式下如果存在循环依赖则会抛出异常。
<4>           if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// Check if bean definition exists in this factory.//对IOC容器中是否存在指定名称的BeanDefinition进行检查,首先检查是否//能在当前的BeanFactory中获取的所需要的Bean,如果不能则委托当前容器//的父级容器去查找,如果还是找不到则沿着容器的继承体系向父级容器查找BeanFactory parentBeanFactory = getParentBeanFactory();//当前容器的父级容器存在,且当前容器中不存在指定名称的Beanif (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.//解析指定Bean名称的原始名称String nameToLookup = originalBeanName(name);// 若为 AbstractBeanFactory 类型,委托父类处理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是否需要进行类型验证,一般不需要
<5>           if (!typeCheckOnly) {//向容器标记指定的Bean已经被创建markBeanAsCreated(beanName);}try {//从容器中获取 beanName 相应的 GenericBeanDefinition 对象,并将其转换为 RootBeanDefinition 对象// 主要解决Bean继承时子类合并父类公共属性问题
<6>               final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);// 检查给定的合并的 BeanDefinition (是否为抽象类)checkMergedBeanDefinition(mbd, beanName, args);// Guarantee initialization of beans that the current bean depends on.// 处理所依赖的 bean @DependsOn()// 获取当前Bean所有依赖Bean的名称
<7>               String[] dependsOn = mbd.getDependsOn();//如果有依赖if (dependsOn != null) {for (String dep : dependsOn) {//校验该依赖是否已经注册过给当前 Beanif (isDependent(beanName, dep)) {//已注册,抛出异常throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}//没有,则先注册依赖的beanregisterDependentBean(dep, beanName);//递归调用getBean(),先生成依赖的beangetBean(dep);}}// Create bean instance.//创建单例Bean
<8>               if (mbd.isSingleton()) {//这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象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.//显式地从容器单例模式Bean缓存中清除实例对象destroySingleton(beanName);throw ex;}});//获取给定Bean的实例对象bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}//创建多例Beanelse if (mbd.isPrototype()) {//原型模式(Prototype)是每次都会创建一个新的对象Object prototypeInstance = null;try {//加载前置处理,默认的功能是注册当前创建的原型对象beforePrototypeCreation(beanName);//创建指定Bean对象实例prototypeInstance = createBean(beanName, mbd, args);}finally {//加载后置处理,默认的功能告诉IOC容器指定Bean的原型对象不再创建afterPrototypeCreation(beanName);}//获取给定Bean的实例对象bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}//要创建的Bean既不是Singleton也不是Prototype//如:request、session、application等生命周期else {String scopeName = mbd.getScope();final Scope scope = this.scopes.get(scopeName);//Bean定义资源中没有配置生命周期范围,则Bean定义不合法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的实例对象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实例对象进行类型检查
<9>       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>处: 具体分析,见2.1获取原始beanName<2>处: 具体分析,见2.2从缓存中获取单例bean<3>处: 具体分析,见2.3获取最终的bean实例对象<4>处: 具体分析,见2.4原型模式依赖检查(Prototype)和从 parentBeanFactory 获取 Bean<5>处: 具体分析,见2.5标记bean为已创建或即将创建<6>处: 具体分析,见2.6获取BeanDefinition<7>处: 具体分析,见2.7bean依赖处理<8>处: 具体分析,见2.8不同作用域bean的实例化<9>处: 具体分析,见2.9类型转换
  • 2.1.获取原始beanName

代码如下:

final String beanName = transformedBeanName(name);

继续深入,代码如下:

protected String transformedBeanName(String name) {return canonicalName(BeanFactoryUtils.transformedBeanName(name));}

BeanFactoryUtils.transformedBeanName(name)方法主要是去除 FactoryBean 的修饰符

//对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,//如果需要得到工厂本身,需要转义String FACTORY_BEAN_PREFIX = "&";public static String transformedBeanName(String name) {Assert.notNull(name, "'name' must not be null");String beanName = name;while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());}return beanName;}

ps: 如果一个factoryBean的名称为“student”,获取factoryBean创建的Bean时,使用getBean(“student”),获取factoryBean本身时,使用getBean("&student")
接着深入,最终代码如下:

/** Map from alias to canonical name */private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
//循环处理,从aliasMap中根据aliasName获取真实beanName,直到获取到的真实beanName为nullpublic String canonicalName(String name) {String canonicalName = name;// Handle aliasing...String resolvedName;do {resolvedName = this.aliasMap.get(canonicalName);if (resolvedName != null) {canonicalName = resolvedName;}}while (resolvedName != null);return canonicalName;}

主要是一个循环获取 beanName 的过程,例如,别名 A 指向名称为 B 的 bean 则返回 B,若 别名 A 指向别名 B,别名 B 指向名称为 C 的 bean,则返回 C

  • 2.2、从缓存中获取单例bean
    Spring 对单例模式的 bean 只会创建一次。后续,如果再获取该 Bean ,则是直接从单例缓存中获取,该过程就体现在 #getSingleton(String beanName) 方法中。代码如下:
 /** Cache of singleton objects: bean name --> bean instance *///单例bean的缓存private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/** Cache of singleton factories: bean name --> ObjectFactory *///单例对象工厂缓存private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);/** Cache of early singleton objects: bean name --> bean instance *///预加载单例bean缓存//存放的 bean 不一定是完整的private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);//对于单例模式的Bean整个IOC容器中只创建一次,不需要重复创建@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) {//从单例缓存中获取单例beanObject singletonObject = this.singletonObjects.get(beanName);//如果缓存中没有 并且 该bean正在创建if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {singletonObject = this.earlySingletonObjects.get(beanName);// earlySingletonObjects 中没有,且允许提前创建if (singletonObject == null && allowEarlyReference) {//从缓存中获取 ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {//从单例工厂中获取beansingletonObject = singletonFactory.getObject();//存入earlythis.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;}

这段代码很简单,流程如下:

第一步,从singletonObjects中获取Bean对象
第二步,如果获取不到且Bean正在创建中,从earlySingletonObjects获取Bean对象
第三步,如果获取不到且允许提前创建,从singletonFactories获取FactoryBean
第四步,如果不为null,则通过FactoryBean.getObject()获取Bean,然后将其加入到
earlySingletonObjects ,并且从 singletonFactories 删除,两者是互斥的,主要用来解决循环依赖的问题

总结就是:从这三个Map依次去取,取不到就取下一个Map

2.2.1、isSingletonCurrentlyInCreation
在上面的代码中又一个重要的方法isSingletonCurrentlyInCreation(beanName),代码如下:

private final Set<String> singletonsCurrentlyInCreation =Collections.newSetFromMap(new ConcurrentHashMap<>(16));public boolean isSingletonCurrentlyInCreation(String beanName) {return this.singletonsCurrentlyInCreation.contains(beanName);}

这个方法是用来判断当前Bean是否在创建中,看到是个Map,我们可以猜测,应该有一个地方在创建Bean的时候,会把正在创建的BeanName给put到这个Map中。

  • 2.3 获取最终的bean实例对象

2.3.1、getObjectForBeanInstance
当我们从getSingleton(beanName)拿到bean对象后,会接着调用getObjectForBeanInstance()方法,来获取最终的Bean实例

为什么这里要再获取一次Bean呢,之前明明都拿到了呀?

因为我们从缓存中获取的 bean 是最原始的 Bean ,并不一定是我们最终想要的 Bean。

怎么办呢?调用 #getObjectForBeanInstance(…) 方法,进行处理,该方法的定义为获取给定 Bean 实例的对象,该对象要么是 bean 实例本身,要么就是 FactoryBean 创建的 Bean 对象。

看代码:

//获取给定Bean的实例对象,主要是完成FactoryBean的相关处理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.//容器已经得到了Bean实例对象,这个实例对象可能是一个普通的Bean,//也可能是一个工厂Bean,如果是一个工厂Bean,则使用它创建一个Bean实例对象,//如果调用本身就想获得一个容器的引用,则指定返回这个工厂Bean实例对象//若为工厂类引用(name 以 & 开头) 且 Bean实例也不是 FactoryBeanif (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {//抛出异常throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());}// Now we have the bean instance, which may be a normal bean or a FactoryBean.//如果类型不是FactoryBean,直接返回if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {return beanInstance;}Object object = null;//若 BeanDefinition 为 null,则从缓存中加载 Bean 对象if (mbd == null) {//从Bean工厂缓存中获取给定名称的Bean实例对象object = getCachedObjectForFactoryBean(beanName);}// 若 object 依然为空,则可以确认,beanInstance 一定是 FactoryBean 。从而,使用 FactoryBean 获得 Bean 对象if (object == null) {// Return bean instance from factory.FactoryBean<?> factory = (FactoryBean<?>) beanInstance;// Caches object obtained from FactoryBean if it is a singleton.// 检测是否定义 beanNameif (mbd == null && containsBeanDefinition(beanName)) {//从容器中获取指定名称的Bean定义,如果继承基类,则合并基类相关属性mbd = getMergedLocalBeanDefinition(beanName);}//如果从容器得到Bean定义信息,并且Bean定义信息不是虚构的,//则让工厂Bean生产Bean实例对象boolean synthetic = (mbd != null && mbd.isSynthetic());//调用FactoryBeanRegistrySupport类的getObjectFromFactoryBean方法,//实现工厂Bean生产Bean对象实例的过程object = getObjectFromFactoryBean(factory, beanName, !synthetic);}return object;}

首先看下这个方法的流程:

1、类型检查,判断是否是FactoryBean
2、对非 FactoryBean 不做处理
3、对 bean 进行转换
4、处理 FactoryBean 类型:委托getObjectFromFactoryBean 方法进行处理。

走到这里,说明这个bean一定是FactoryBean类型的,再从Ioc容器中获取该beanName对应的BeanDefinition,如果不为null,且不是abstract,则调用getObjectFromFactoryBean方法获取bean实例
从这里可以看出, getObjectForBeanInstance(Object beanInstance, String name, String beanName,RootBeanDefinition mbd) 方法,分成两种情况:

第一种,当该实例对象为非 FactoryBean类型,直接返回给定的 Bean 实例对象 beanInstance 。
第二种,当该实例对象为FactoryBean 类型,从 FactoryBean ( beanInstance ) 中,获取 Bean实例对象。

2.3.2、getObjectFromFactoryBean
我们接着看第二种情况:

//Bean工厂生产Bean实例对象protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {//为单例模式且缓存中存在if (factory.isSingleton() && containsSingleton(beanName)) {//多线程同步,以防止数据不一致
1.1         synchronized (getSingletonMutex()) {//从缓存中获取指定的 factoryBean
1.2             Object object = this.factoryBeanObjectCache.get(beanName);if (object == null) {// 为空,则从 FactoryBean 中获取对象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 {1.3                     if (shouldPostProcess) {try {// 对从 FactoryBean 获取的对象进行后处理// 生成的对象将暴露给 bean 引用object = postProcessObjectFromFactoryBean(object, beanName);}catch (Throwable ex) {throw new BeanCreationException(beanName,"Post-processing of FactoryBean's singleton object failed", ex);}}//将生产的实例对象添加到Bean工厂缓存中
1.4                     this.factoryBeanObjectCache.put(beanName, object);}}return object;}}// 为空,则从 FactoryBean 中获取对象
2       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;}}

1、判断是否为单例并且缓存中存在 如果存在,则顺着1.1往下走,不存在,则走2的流程
1.1、sync加锁,锁住的是singletonObjects,和其他单例锁一样,保证全局唯一
1.2、从缓存factoryBeanObjectCache中获取Bean实例 如果获取不到,则调用doGetObjectFromFactoryBean()方法获取,实际最后调用的是factory.getObject()方法
1.3、如果需要后续处理( shouldPostProcess = true ),则进行下一步处理 postProcessObjectFromFactoryBean() 方法,对从 FactoryBean 处获取的 Bean
实例对象进行后置处理。其默认实现是直接返回 object 对象,不做任何处理。
1.4、加入到 factoryBeanObjectCache 缓存中
2、如果缓存中不存在,同样调用doGetObjectFromFactoryBean()获取bean实例

1.3的代码如下:

protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException {return object;}
//但是子类可以重写,例如应用后处理器等。

到这里,doGetBean()方法的2.2从缓存中获取单例bean和2.3获取最终的bean实例对象我们已经分析完了

  • 2.4、原型模式依赖检查(Prototype)和从 parentBeanFactory 获取 Bean

原型模式依赖检查,对应代码如下:

if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}

跟踪进去:

      /** Names of beans that are currently in creation */private final ThreadLocal<Object> prototypesCurrentlyInCreation =new NamedThreadLocal<>("Prototype beans currently in creation");
protected boolean isPrototypeCurrentlyInCreation(String beanName) {//从ThreadLocal中取出正在创建的prototypeObject curVal = this.prototypesCurrentlyInCreation.get();return (curVal != null &&(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));}

Spring 只处理单例模式下得循环依赖,对于原型模式的循环依赖直接抛出异常,Spring会把正在创建的原型模式Bean存入ThreadLoacl,在这里通过ThreadLoacl来判断当前Bean是否已经创建。

从 parentBeanFactory 获取 Bean,对应代码如下:

// Check if bean definition exists in this factory.//对IOC容器中是否存在指定名称的BeanDefinition进行检查,首先检查是否//能在当前的BeanFactory中获取的所需要的Bean,如果不能则委托当前容器//的父级容器去查找,如果还是找不到则沿着容器的继承体系向父级容器查找BeanFactory parentBeanFactory = getParentBeanFactory();//当前容器的父级容器存在,且当前容器中不存在指定名称的Beanif (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.//解析指定Bean名称的原始名称String nameToLookup = originalBeanName(name);// 若为 AbstractBeanFactory 类型,委托父类处理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);}}

如果当前容器缓存中没有相对应的 BeanDefinition 对象,则会尝试从父类工厂(parentBeanFactory)中加载,然后再去递归调用 getBean(…) 方法

  • 2.5、标记bean为已创建或即将创建
    对应代码如下:
//创建的Bean是否需要进行类型验证,一般不需要if (!typeCheckOnly) {//向容器标记指定的Bean已经被创建markBeanAsCreated(beanName);}

typeCheckOnly是doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly)方法中的一个参数,一般这个参数传的都是false

接着追踪markBeanAsCreated()方法:

protected void markBeanAsCreated(String beanName) {// 没有创建if (!this.alreadyCreated.contains(beanName)) {synchronized (this.mergedBeanDefinitions) {// 再次检查一次:DCL 双重校验if (!this.alreadyCreated.contains(beanName)) {clearMergedBeanDefinition(beanName);// 添加到已创建 bean 集合中this.alreadyCreated.add(beanName);}}}}

这里用到了单例模式中耳熟能详的双重校验

  • 2.6、获取BeanDefinition

对应代码如下:

//从容器中获取 beanName 相应的 GenericBeanDefinition 对象,并将其转换为 RootBeanDefinition 对象
//主要解决Bean继承时子类合并父类公共属性问题
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查给定的合并的 BeanDefinition (是否为抽象类)
checkMergedBeanDefinition(mbd, beanName, args);

这段代码注释很详细,就不多解释了。

  • 2.7、bean依赖处理

对应代码如下:

// Guarantee initialization of beans that the current bean depends on.// 处理所依赖的 bean @DependsOn()//获取当前Bean所有依赖Bean的名称
<1>   String[] dependsOn = mbd.getDependsOn();//如果有依赖if (dependsOn != null) {for (String dep : dependsOn) {//校验该依赖是否已经注册过给当前 Bean
<2>           if (isDependent(beanName, dep)) {//已注册,抛出异常throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}//没有,则先注册依赖的bean
<3>           registerDependentBean(dep, beanName);//递归调用getBean(),先生成依赖的bean
<4>           getBean(dep);}}

在spring中有一个@DependsOn注解,它的作用是依赖加载,比如A对象要在B对象加载之后才能加载,那么可以在A上面加@DependsOn(value = "B")注解,就可以达到我们的要求。
其实@DependsOn实现的原理就是上面这段代码。

<1>、通过我们前面从IoC容器中拿到的BeanDefinition,调用mbd.getDependsOn()方法,获取当前bean所有的依赖。
<2>、遍历这些依赖,判断此依赖是否已注册给当前的Bean <3>、没有,则先注册依赖的Bean
<4>、递归调用getBean(),先生成依赖的bean

<2>、遍历这些依赖,判断此依赖是否已注册给当前的Bean
代码:

 // 保存的是bean与其依赖的映射关系:B - > Aprivate final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);//保存的是bean与其依赖的映射关系:A - > Bprivate final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {if (alreadySeen != null && alreadySeen.contains(beanName)) {return false;}// 获取当前原始 beanNameString canonicalName = canonicalName(beanName);// 获取该bean依赖的其他bean集合Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);if (dependentBeans == null) {return false;}// 存在,则证明该依赖已经注册到bean中if (dependentBeans.contains(dependentBeanName)) {return true;}// 递归检测依赖for (String transitiveDependency : dependentBeans) {if (alreadySeen == null) {alreadySeen = new HashSet<>();}alreadySeen.add(beanName);if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {return true;}}return false;}

这段代码很简单,主要就是通过dependentBeanMap获取当前bean对应的所有依赖dependentBeans,然后判断是否已注册,接着递归检查依赖的Bean有没有依赖,如果有,就递归调用isDependent()检查

<3>、没有,则先注册依赖的Bean
如果没有注册依赖的Bean到该 Bean,则执行注册registerDependentBean(dep, beanName):

// 保存的是bean与其依赖的映射关系:B - > Aprivate final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);//保存的是bean与其依赖的映射关系:A - > Bprivate final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);//为指定的Bean注入依赖的Beanpublic void registerDependentBean(String beanName, String dependentBeanName) {// A quick check for an existing entry upfront, avoiding synchronization...//获取原始beanNameString canonicalName = canonicalName(beanName);Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);if (dependentBeans != null && dependentBeans.contains(dependentBeanName)) {return;}// No entry yet -> fully synchronized manipulation of the dependentBeans Set//先从容器中:bean名称-->全部依赖Bean名称集合找查找给定名称Bean的依赖Beansynchronized (this.dependentBeanMap) {//获取给定名称Bean的所有依赖Bean名称dependentBeans = this.dependentBeanMap.get(canonicalName);if (dependentBeans == null) {//为Bean设置依赖Bean信息dependentBeans = new LinkedHashSet<>(8);this.dependentBeanMap.put(canonicalName, dependentBeans);}//把映射关系存入集合dependentBeans.add(dependentBeanName);}//从容器中:bean名称-->指定名称Bean的依赖Bean集合找查找给定名称Bean的依赖Beansynchronized (this.dependenciesForBeanMap) {Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);if (dependenciesForBean == null) {dependenciesForBean = new LinkedHashSet<>(8);this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);}//把映射关系存入集合dependenciesForBean.add(canonicalName);}}

套用上面的例子,如果 A @DependsOn(value = “B”) ,也就是说A依赖于B,那么该方法registerDependentBean(dep, beanName)中,参数 dep 就是B,beanName 就是A。

这段代码中其实就是把bean之间的依赖关系注册到两个map中。

dependentBeanMap 存入(B,A)
dependenciesForBeanMap 存入(A,B)

<4>、递归调用getBean(dep),先生成依赖的bean
到了这一步,递归调用getBean(beanName)方法也就是doGetBean(beanName)重走当前流程,来先实例化依赖的Bean。等依赖的Bean实例化之后,当前bean再接着往下执行。

  • 2.8、不同作用域bean的实例化
    代码:
// Create bean instance.
//创建单例Bean
if (mbd.isSingleton()) {//这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象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.//显式地从容器单例模式Bean缓存中清除实例对象destroySingleton(beanName);throw ex;}});//获取给定Bean的实例对象bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}//创建多例Bean
else if (mbd.isPrototype()) {//原型模式(Prototype)是每次都会创建一个新的对象Object prototypeInstance = null;try {//加载前置处理,默认的功能是注册当前创建的原型对象beforePrototypeCreation(beanName);//创建指定Bean对象实例prototypeInstance = createBean(beanName, mbd, args);}finally {//加载后置处理,默认的功能告诉IOC容器指定Bean的原型对象不再创建afterPrototypeCreation(beanName);}//获取给定Bean的实例对象bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}//要创建的Bean既不是Singleton也不是Prototype
//如:request、session、application等生命周期
else {String scopeName = mbd.getScope();final Scope scope = this.scopes.get(scopeName);//Bean定义资源中没有配置生命周期范围,则Bean定义不合法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的实例对象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);}
}

这段代码很明显,分成了3个部分:

singleton Bean实例化
Prototype Bean实例化
其他类型 Bean 实例化(session,request等)

我们先来看singleton Bean实例化:

if (mbd.isSingleton()) {//这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象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.//显式地从容器单例模式Bean缓存中清除实例对象destroySingleton(beanName);throw ex;}});//获取给定Bean的实例对象bean = getObjectForBeanInstance(sharedInstance, name,beanName, mbd);}

Spring Bean 的作用域默认为 singleton 。还有其他作用域,如 prototype、request、session 等。不同的作用域会有不同的初始化策略。

  • 2.9、类型转换

代码:

// 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;

requiredType是 getBean() 方法可传入的一个参数,即可以根据指定的 beanName 和 requiredType 来获取Bean。但是一般情况下是不需要类型检查的,requiredType一般为null,如getBean(beanName),当requiredType不为null的时候走这段逻辑。至此,spring加载Bean也就是 getBean() 我们大致分析完了。

Spring Ioc 之 Bean的加载(1)(生命周期)相关推荐

  1. Spring Ioc 之 Bean的加载(3):createBean()

    createBean()是创建Bean的关键方法 一.createBean() 代码: //AbstractAutowireCapableBeanFactory.java protected Obje ...

  2. iOS之深入解析WKWebView加载的生命周期与代理方法

    一.前言 从 WebView 开始加载一条请求,到页面完整呈现这一过程发生了什么?无论是做 WebView 性能优化还是异常问题监控与排查,都离不开对WKWebView加载的生命周期与代理方法的剖析. ...

  3. asp.net C#母版页和内容页事件排版加载顺序生命周期

    asp.net C#母版页和内容页事件排版加载顺序生命周期 关于ASP页面Page_Load发生在事件之前而导致的问题已经喜闻乐见,对于问题的解释也很全面,但是如何解决问题则较少有人说明,我就再 简单 ...

  4. Fragment的懒加载与生命周期详解

    提示:本文仅为笔者学习记录 Fragment的懒加载与生命周期详解 什么是懒加载 了解Fragment的生命周期 onAttach onCreate onCreateView onActivityCr ...

  5. Spring源码——bean的加载

    前言 内容主要参考自<Spring源码深度解析>一书,算是读书笔记或是原书的补充.进入正文后可能会引来各种不适,毕竟阅读源码是件极其痛苦的事情. 本文主要涉及书中第五章的部分,依照书中内容 ...

  6. java 类加载生命周期_Java类的加载与生命周期

    一.概要: 类的生命周期从类的 加载.连接.初始化 开始,到类的 卸载结束: 二.几个阶段: 加载:查找并加载类的二进制数据.(把类的.class文件的二进制数据读入内存,存放在运行时数据区的方法区: ...

  7. iOS开发之控制器创建与加载(生命周期)

    1.如何创建一个控制器 控制器常见的创建方式有以下几种: (1)通过storyboard创建 (2)直接创建 MJViewController *mj = [[MJViewController all ...

  8. 【Spring】Spring常用配置-Bean的初始化和销毁(生命周期)

    转载请注明出处:http://blog.csdn.net/qq_26525215 本文源自[大学之旅_谙忆的博客] 分析 在我们实际开发的时候,经常会遇到在Bean使用之前或者之后做些必要的操作,Sp ...

  9. java 单例 生命周期_Rhythmk 一步一步学 JAVA (13) Spring-2 之Ben懒加载以及生命周期,单例...

    1.定义Demo类: package com.rhythmk.spring; public class User { public void Init () { System.out.println( ...

最新文章

  1. Microbiome:芝麻菜中肠杆菌科主导核心微生物组并贡献抗生素抗性组(简单套路16S+meta+培养组发高分文章)
  2. php中strtotime(date,js模仿php中strtotime()与date()函数实现方法
  3. win10用计算机名访问文件夹,win10系统提示你当前无权访问该文件夹的解决方法【图文教程】...
  4. php根据浏览器调用支付_Android通过外部浏览器调用微信H5支付,Android+PHP详解
  5. 中山大学计算机类专业分数线,中山大学计算机类专业2016年在广东理科高考录取最低分数线...
  6. python中http_Python中的HTTP错误
  7. Google Analytics(分析)网址构建器
  8. Web压力测试和手机App测试
  9. Pascal voc 数据集下载网址
  10. 小学计算机网络教室简介,陆桥实验小学计算机网络教室配备情况一览表(6页)-原创力文档...
  11. 华为员工去面试被淘汰后怒怼HR:华为出来的也能被拒,很无语
  12. ae合成设置快捷键_AE软件中最常用快捷键大全(学AE必备)
  13. 转载:.Net 程序集 签名工具sn.exe 密钥对SNK文件 最基本的用法
  14. PE文件资源解析(十一)对话框资源的解析
  15. python 基金净值_用Python抓取天天基金网基金历史净值数据
  16. 图库highcharts联合jquery ajax 后端取数据前端图表渲染
  17. Vue3 自定义指令:ClickOutside(点击当前区域之外的位置)
  18. Linux驱动开发之platform设备驱动实验【完整教程】
  19. 高级计算机体系结构知识点,高级计算机体系结构知识点.pdf
  20. 给360安全浏览器设置一个图片背景/主题

热门文章

  1. 117. Populating Next Right Pointers in Each Node II
  2. 第七章之main函数和启动例程
  3. Java中 equals() 和 == 的区别
  4. Android 屏幕常亮、低电量监听
  5. Photoshop用户必知必会的28个快捷键
  6. Python学习笔记:异步IO(2)
  7. win10下git的配置教程
  8. C语言中,指针在一个自定义且不带返回值是如何改变外部一些变量的(指针与函数的相互作用)
  9. 计算若干数据的汉明距离总和
  10. otsu阈值分割算法原理_大津二值化算法OTSU的理解