Spring源码-创建单例bean的过程

一.简介

对于实例化好的单例bean,getBean(String)方法并不会再一次去创建,而是从缓存中获取。如果某个bean还未实例化,这个时候就无法命中缓存,此时,就要根据bean的配置信息去创建这个bean了。相较于getBean(String)方法的实现逻辑,创建bean的方法create(String,RootBeanDefinition,Object[])及所调用的方法逻辑更加复杂一些,本次就先从大体上分析createBean方法逻辑。

二.源码分析

2.1 创建bean实例的入口

我们首先要知道createBean方法在哪些被调用,如下:

public T doGetBean(...) {
    // 省略不相关代码
    if (mbd.isSingleton()) {
        sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
            @Override
            public Object getObject() throws BeansException {
                try {
                    return createBean(beanName, mbd, args);
                }
                catch (BeansException ex) {
                    destroySingleton(beanName);
                    throw ex;
                }
            }
        });
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
    // 省略不相关代码
}

上面是doGetBean方法的代码片段,从中可以发现调用了createBean方法。createBean方法被匿名工厂类的getObject方法包裹,但是这个匿名工厂类并未直接调用getObject方法,而是将自身作为参数传递给getSingleton(String,ObjectFactory)方法。getSingleton这个方法实现我们之前讲过,逻辑如下:

1.先从singletonObjects集合获取bean实例,若不为空,直接返回

2.若为空,进入创建bean实例阶段。先将beanName添加到singletonCurrentlyInCreation

3.通过getObject方法调用createBean方法创建bean实例

4.将beanName从singletonCurrentlyInCreation集合中移除

5.将<beanName,singletonObject>映射缓存到singletonObjects集合中

从上面的分析中,了解可createBean在什么时候和地方被调用,下来需要了解createBean做了什么事情。

2.2 createBean

源码分析如下:

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;

    // 解析 bean 的类型
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    try {
        // 处理 lookup-method 和 replace-method 配置,Spring 将这两个配置统称为 override method
        mbdToUse.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                beanName, "Validation of method overrides failed", ex);
    }

    try {
        // 在 bean 初始化前应用后置处理,如果后置处理返回的 bean 不为空,则直接返回
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                "BeanPostProcessor before instantiation of bean failed", ex);
    }

    // 调用 doCreateBean 创建 bean
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    if (logger.isDebugEnabled()) {
        logger.debug("Finished creating instance of bean '" + beanName + "'");
    }
    return beanInstance;
}

执行流程如下:

1.根据设置的class属性或者根据className来解析class

2.对override属性进行标记及验证。在Spring配置中是存着lookup-method和replace-method的,而这两个配置的加载就是讲配置同一存放在BeanDefinition中的methodOverrides属性里,而这个函数的操作其实也就是针对这两个配置的。

3.应用初始化前的后处理器,解析指定bean是否存在初始化的短路操作。

4.创建bean。

2.3 验证和准备override方法

在Spring配置中是存着lookup-method和replace-method的,而这两个配置的加载就是讲配置同一存放在BeanDefinition中的methodOverrides属性里,这两个功能实现原理其实是在bean实例化的时候如果检测到methodOverrides属性里,会动态地为当前bean生成代理并使用对应的拦截器对bean做增强处理,相关逻辑实现在bean实例化会讲到。

public void prepareMethodOverrides() throws BeanDefinitionValidationException {
    MethodOverrides methodOverrides = getMethodOverrides();
    if (!methodOverrides.isEmpty()) {
        Set<MethodOverride> overrides = methodOverrides.getOverrides();
        synchronized (overrides) {
            // 循环处理每个 MethodOverride 对象
            for (MethodOverride mo : overrides) {
                prepareMethodOverride(mo);
            }
        }
    }
}

protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
    // 获取方法名为 mo.getMethodName() 的方法数量,当方法重载时,count 的值就会大于1
    int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
    // count = 0,表明根据方法名未找到相应的方法,此时抛出异常
    if (count == 0) {
        throw new BeanDefinitionValidationException(
                "Invalid method override: no method with name '" + mo.getMethodName() +
                "' on class [" + getBeanClassName() + "]");
    }
    // 若 count = 1,表明仅存在已方法名为 mo.getMethodName(),这意味着方法不存在重载
    else if (count == 1) {
        // 方法不存在重载,则将 overloaded 成员变量设为 false
        mo.setOverloaded(false);
    }
}

上面的源码中,prepareMethodOverrides方法循环调用了prepareMethodOverride 方法,并没其他的太多逻辑。主要准备工作都是在 prepareMethodOverride 方法中进行的。prepareMethodOverride 这个方法主要用于获取指定方法的方法数量 count,并根据 count 的值进行相应的处理。count = 0 时,表明方法不存在,此时抛出异常。count = 1 时,设置 MethodOverride 对象的overloaded成员变量为 false。这样做的目的在于,提前标注名称mo.getMethodName的方法不存在重载,在使用 CGLIB 增强阶段就不需要进行校验,直接找到某个方法进行增强即可。

2.4 实例化的前置处理

用户通过实现 BeanPostProcessor 接口,并将实现类配置到 Spring 的配置文件中(或者使用注解),即可在 bean 初始化前后进行自定义操作。

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    // 检测是否解析过,mbd.beforeInstantiationResolved 的值在下面的代码中会被设置
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                // 应用前置处理
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    // 应用后置处理
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        // 设置 mbd.beforeInstantiationResolved
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

2.4.1 实例化前的后处理器应用

bean的实例化前调用,也就是将AbstractBeanDefinition转换为BeanWrapper前的处理。给子类一个修改BeanDefinition机会,也就是说当程序经过这个方法后,bean可能不是我们认为的bean了,而是或许称为了一个经过处理代理的bean,也可能是通过cglib生成的也可能是通过其他技术生成的。

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        // InstantiationAwareBeanPostProcessor 一般在 Spring 框架内部使用,不建议用户直接使用
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            // bean 初始化前置处理
            Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
            if (result != null) {
                return result;
            }
        }
    }
    return null;
}

2.4.2 实例化后的后处理器应用

Spring中的规则是在bean的初始化后尽可能保证将注册的后处理器的postProcessAfterInitialization方法应用到该bean中,因为如果返回的bean不为空,那么便不会再次经历普通bean的创建过程,所以只能在这里应用后置处理器postProcessAfterInitialization。

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
       // bean 初始化后置处理
        result = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;
}

2.5 调用 doCreateBean 方法创建 bean

当经历过后resolveBeforeInstantiation方法之后,程序有两个选择,如果创建了代理或者重写了InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法并在方法的postBeforeInstantiation中改变了bean,则直接返回就行,否则就要惊醒常规bean的创建,常规bean的创建就是doCreateBean中完成的。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
        throws BeanCreationException {

    /* 
     * BeanWrapper 是一个基础接口,由接口名可看出这个接口的实现类用于包裹 bean 实例。
     * 通过 BeanWrapper 的实现类可以方便的设置/获取 bean 实例的属性
     */
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        // 从缓存中获取 BeanWrapper,并清理相关记录
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        /* 
         * 创建 bean 实例,并将实例包裹在 BeanWrapper 实现类对象中返回。createBeanInstance 
         * 中包含三种创建 bean 实例的方式:
         *   1. 通过工厂方法创建 bean 实例
         *   2. 通过构造方法自动注入(autowire by constructor)的方式创建 bean 实例
         *   3. 通过无参构造方法方法创建 bean 实例
         *
         * 若 bean 的配置信息中配置了 lookup-method 和 replace-method,则会使用 CGLIB 
         * 增强 bean 实例。后面会解析到
         */
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // 此处的 bean 可以认为是一个原始的 bean 实例,暂未填充属性
    final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
    Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
    mbd.resolvedTargetType = beanType;

    // 这里又遇到后置处理了,此处的后置处理是用于处理已“合并的 BeanDefinition”。
    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;
        }
    }

    /*
     * earlySingletonExposure 是一个重要的变量,这里要说明一下。该变量用于表示是否提前暴露
     * 单例 bean,用于解决循环依赖。earlySingletonExposure 由三个条件综合而成,如下:
     *   条件1:mbd.isSingleton() - 表示 bean 是否是单例类型
     *   条件2:allowCircularReferences - 是否允许循环依赖
     *   条件3:isSingletonCurrentlyInCreation(beanName) - 当前 bean 是否处于创建的状态中
     * 
     * earlySingletonExposure = 条件1 && 条件2 && 条件3 
     *                        = 单例 && 是否允许循环依赖 && 是否存于创建状态中。
     */
    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");
        }
        // 添加工厂对象到 singletonFactories 缓存中
        addSingletonFactory(beanName, new ObjectFactory<Object>() {
            @Override
            public Object getObject() throws BeansException {
                // 获取早期 bean 的引用,如果 bean 中的方法被 AOP 切点所匹配到,此时 AOP 相关逻辑会介入
                return getEarlyBeanReference(beanName, mbd, bean);
            }
        });
    }

    Object exposedObject = bean;
    try {
        // 向 bean 实例中填充属性,populateBean 方法也是一个很重要的方法,后面会专门写文章分析
        populateBean(beanName, mbd, instanceWrapper);
        if (exposedObject != null) {
            /*
             * 进行余下的初始化工作,详细如下:
             * 1. 判断 bean 是否实现了 BeanNameAware、BeanFactoryAware、
             *    BeanClassLoaderAware 等接口,并执行接口方法
             * 2. 应用 bean 初始化前置操作
             * 3. 如果 bean 实现了 InitializingBean 接口,则执行 afterPropertiesSet 
             *    方法。如果用户配置了 init-method,则调用相关方法执行自定义初始化逻辑
             * 4. 应用 bean 初始化后置操作
             * 
             * 另外,AOP 相关逻辑也会在该方法中织入切面逻辑,此时的 exposedObject 就变成了
             * 一个代理对象了
             */
            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) {
            // 若 initializeBean 方法未改变 exposedObject 的引用,则此处的条件为 true。
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
            else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<String>(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.");
                }
            }
        }
    }

    try {
        // 注册销毁逻辑
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }

    return exposedObject;
}

方法的执行流程如下:

1.如果是单例则需要清理缓存

2.实例化bean,将BeanDefinition转换为BeanWrapper。这里的转换有:

  • 如果存在工厂方法则使用工厂方法进行初始化
  • 一个类有多个构造函数,每个构造函数都有不同的参数,所以需要参数锁定构造函数并进行初始化
  • 如果既不存在工厂方法也不存在带有参数的构造函数,则使用默认的构造函数进行bean的实例化

3.应用 MergedBeanDefinitionPostProcessor 后置处理器相关逻辑

4.根据条件决定是否提前暴露 bean 的早期引用(early reference),用于处理循环依赖问题

5.属性填充,将所有属性填充到bean的实例中

6.循环依赖检查,在这个步骤里会检测已经加载的bean是否已经出现了依赖循环,并判断是否需要抛出异常。

7.注册DisposableBean,以便于销毁时候调用

8.完成创建并返回

 

参考:Spring IOC 容器源码分析 - 创建单例 bean 的过程

           《Spring源码深度解析》

Spring源码-创建单例bean的过程Spring源码-创建单例bean的过程 WYFVV 发布了107 篇原创文章 · 获赞 12 · 访问量 2万+ 私信 关注
上一篇:3.2spring源码系列----循环依赖源码分析


下一篇:Spring IoC 依赖注入(二)源码分析