Spring源码学习笔记(2)——Bean的加载

Spring源码学习笔记(2)——Bean的加载

一. Bean加载的核心流程

  1. 前面大概分析了Spring读取解析配置文件,并加载BeanDefinition的过程。本节详细整理下Bean的加载过程。首先贴上核心代码

    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    //提取对应的beanName
       final String beanName = transformedBeanName(name);
       Object bean;
    
       //首先检查缓存中或者实例工厂中是否有对应的的实例,因为在创建Singleton Bean的时候可能存在依赖注入的情况,而在创建依赖时,为了避免循环依赖,Spring创建Bean的原则是不等Bean创建完成,就会将创建Bean的ObjectFactory提早曝光,也就是将ObjectFactory加入到缓存中,一旦下一个Bean创建时需要依赖上一个Bean,就直接使用ObjectFactory
    
       //直接尝试从缓存获取或者从singletonFactories中ObjectFactory获取
       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 + "'");
               }
           }
    
           //返回创建的实例,如果是FactoryBean,则返回FactoryBean的getObject()方法创建的Bean
           bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
       }
    
       else {
           //只有Singleton的Bean才解决循环依赖的问题,Prototype的Bean会抛出下面的异常
           if (isPrototypeCurrentlyInCreation(beanName)) {
               throw new BeanCurrentlyInCreationException(beanName);
           }
    
           //如果beanDefinitionMap中也就是已加载的Bean中不存在beanName,则递归地从parentBeanFactory中查找
           BeanFactory parentBeanFactory = getParentBeanFactory();
           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 {
                   // No args -> delegate to standard getBean method.
                   return parentBeanFactory.getBean(nameToLookup, requiredType);
               }
           }
    
           //如果是要加载Bean,而不仅仅是做类型检查,则需要记录
           if (!typeCheckOnly) {
               markBeanAsCreated(beanName);
           }
    
           try {
               //将存储XML配置文件的GenericBeanDefinition转换成RootBeanDefinition,如果指定beanName是子Bean的话,同时会合并父Bean的相关属性
               final RootBeanDefinition本身
                   //Singleton模式的实例化mbd = getMergedLocalBeanDefinition(beanName);
               checkMergedBeanDefinition(mbd, beanName, args);
    
               //如果存在依赖,则递归实例化依赖的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);
                       getBean(dep);
                   }
               }
    
               //实例化所有依赖的Bean后,开始实例化RootBeanDefinition本身
               //Singleton模式的实例化
               if (mbd.isSingleton()) {
                   sharedInstance = getSingleton(beanName, () -> {
                       try {
                           return createBean(beanName, mbd, args);
                       }
                       catch (BeansException ex) {
                           destroySingleton(beanName);
                           throw ex;
                       }
                   });
                   bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
               }
    
               //Prototype模式的实例化
               else if (mbd.isPrototype()) {
                   Object prototypeInstance = null;
                   try {
                       beforePrototypeCreation(beanName);
                       prototypeInstance = createBean(beanName, mbd, args);
                   }
                   finally {
                       afterPrototypeCreation(beanName);
                   }
                   bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
               }
    
               //自定义Scope模式的实例化
               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, () -> {
                           beforePrototypeCreation(beanName);
                           try {
                               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;
           }
       }
    
       //检查需要的类型是否符合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;
    }

    当我们使用applicationContext.getBean(“beanName”)方法从容器中获取bean时,就会走到AbstractBeanFactory的doGetBean()方法,这是Spring容器加载bean的核心方法。下面对其核心流程进行介绍。

二. 提取实际的beanName

  1. 根据传入的name提取实际的beanName

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

    这里有两种情况:

    1. 传入的参数时FactoryBean的名称,会以&开头,这时需要调用BeanFactoryUtils

      的方法解析,去除&返回FactoryBean的name;

      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;
      }
    2. 传入的是别名alias,则需要SimpleAliasRegistry处理,根据注册的别名拿到实际的beanName。

      public 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;
      }

    三. 从缓存中获取单例Bean

    1. 在Spring中,Singleton类型的Bean只会创建一次,然后存放在缓存中,后面获取时就直接从缓存中获取。这里首先会尝试从缓存中获取Bean:

      @Override
      @Nullable
      public Object getSingleton(String beanName) {
        //设置true表示允许早期依赖
        return getSingleton(beanName, true);
      }
      protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        //如果缓存中存在实例,则直接返回
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      
            //如果缓存中实例为空,则先锁singletonObjects缓存,进行后续处理
            synchronized (this.singletonObjects缓存,进行后续处理) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                //如果此Bean之前正在被加载,则不处理
                if (singletonObject == null && allowEarlyReference) {
                    //当某些方法需要提前初始化时,会调用addSingletonFactory方法将其对应的ObjectFactory保存在singletonFactories中,也即保存其初始化策略
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    //如果存在预先初始化的ObjectFactory,则调用getObject()方法实例化Bean,并记录在缓存中。earlySingletonObjects与singletonFactories互斥
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return singletonObject;
      }
    2. 上面方法中涉及到Spring Singleton相关的一些缓存:

      1. singletonObjects:用于缓存所有Singleton的Bean,
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        // Register bean as disposable.
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张申傲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值