Spring IoC 源码系列(四)bean创建流程与循环依赖问题分析

创建单例 bean 的代码细节在 org.springframework.beans.factory.support.AbstractBeanFactory#getBean 中,getBean 顾名思义是获取 bean 的流程,如果 bean 不存在的话会先创建,创建前与创建后的具体流程在下一篇文章里进行总结。这里只对创建 bean 的流程进行详细的分析。

1.入口

AbstractBeanFactory 有一个方法 org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean,这个方法很长,这里只贴出了创建单例 bean 相关的代码。

    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
         ......
        if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, () -> {
                try {
                    // 创建 bean
                    return createBean(beanName, mbd, args);
                }
                catch (BeansException ex) {
                    // 创建过程中出现异常销毁 bean
                    destroySingleton(beanName);
                    throw ex;
                }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }
        ......
    }

2.creatBean 方法预览

mbd 是融合了父子容器配置的 beanDefinition,关于父子容器配置可以参考:Spring中的父子容器

    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {
        RootBeanDefinition mbdToUse = mbd;
        // 获取 beanDefinition 中的 class 属性
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        try {
            // 覆盖方法(meta、lookup-method、replace-method)校验,判断是否该方法是否重载
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
        beanName, "Validation of method overrides failed", ex);
        }

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            // 实例化对象前的处理,且可以创建代理 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);
        }

        try {
            // 创建 bean
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isTraceEnabled()) {
    logger.trace("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
        mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
        }
    }
  1. beanDefinition 中解析 bean class
  2. 覆盖方法校验,主要是 lookup-method、replace-method,判断是否有这两个方法的重载
  3. 判断实例化之前是否需要创建代理 bean,如果需要,则通过 InstantiationAwareBeanPostProcessor 提前创建 bean
  4. 创建 bean 实例

Spring 提供了lookup-methodreplace-method 两种类型类型的 overrides 方法,基于一种可拔插的方式改变 bean 的方法,平时在项目中很少会用到,具体的用法可以参考:Spring高级配置:lookup-method, replaced-method

3.doCreateBean 创建 bean

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        // 使用 BeanWrapper 包装创建的 bean
        if (instanceWrapper == null) {
            // 创建 bean
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        // 获取包装的 bean 实例对象(暂未填充属性)与 class 对象
        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 {
                    // 如果有配置 MergedBeanDefinitionPostProcessor 类型的后置处理,则修改 beanDefinition
                    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,可以用来解决循环依赖
        boolean earlySingletonExposure = (mbd.isSingleton() // 单例模式
                && this.allowCircularReferences &&          // 允许循环依赖
                isSingletonCurrentlyInCreation(beanName));  // 当前 bean 正在被创建
        if (earlySingletonExposure) {
            if (logger.isTraceEnabled()) {
                logger.trace("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            // 将工厂对象放入 singletonFactories 中,可以用来解决循环依赖
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            //  对 bean 进行填充,将各个属性值注入
            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) {
            // 从缓存中获取提前暴露的 bean
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    // 这个 bean 可能不是完整的 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. 创建 bean,并使用 BeanWrapper 进行包装
  2. 执行 MergedBeanDefinitionPostProcessor 后置处理
  3. 判断是否需要提前曝光 bean,如果需要,将 bean 加入到 singletonFactories map 缓存中,可以用来解决 bean 之间的循环依赖问题
  4. 通过 populateBean 方法填充 bean 依赖的属性
  5. 激活 bean 的…Aware 配置,执行 BeanPostProcessor 的前置处理,执行 InitializingBean 回调,执行 BeanPostProcessor 的后置处理,这几个过程都不是必须的,如果没有配置是不会执行的
  6. 注册销毁回调

这个方法处理的流程很多,其中 createBeanInstance 方法用于创建 bean 实例,这里先不分析创建 bean 的具体细节,感兴趣的可以关注后面的总结。

4.bean 之间的循环依赖

这里可以引申出一个面试中长问的知识点:Spring 是如何解决 bean 之间的循环依赖。下面来分析一下:

上面的方法中用 earlySingletonExposure 判断这个 bean 是否需要提前曝光出去,如果需要提前曝光会执行 addSingletonFactory 方法,将未填充依赖的 bean 保存到 singletonFactories 中,接着会执行 populateBean 方法,用于注入 bean 依赖的属性。

    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(singletonFactory, "Singleton factory must not be null");
        synchronized (this.singletonObjects) {
            if (!this.singletonObjects.containsKey(beanName)) {
                this.singletonFactories.put(beanName, singletonFactory);
                this.earlySingletonObjects.remove(beanName);
                this.registeredSingletons.add(beanName);
            }
        }
    }

假如 A 依赖 B,而 B 又依赖与 A,且 A 需要提前暴露,那么 A 会被保存到 singletonFactories 中,此时 A 还不是完整的 bean,因为还没有注入依赖的 B,接着执行 populateBean 方法,发现 A 依赖与 B,于是会通过 getBean 方法创建 B,getBean 调用 doGetBean,而在 doGetBean 方法中会提前调用 getSingleton 方法,判断该 bean 是否已经被创建。下面是具体的代码

    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        ......
        Object sharedInstance = getSingleton(beanName);
        ......
        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);
        }
        ......
    }

    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                if (singletonObject == null && allowEarlyReference) {
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return singletonObject;
    }

此时 B 还没有创建,于是执行初始化操作,在 B 注入依赖的时候发现依赖于 A 对象,于是调用 getBean 去获取 A 对象,当指定到 getSingleton 方法时会从 singletonFactories 中获取到提前暴露的 A 对象,这样 B 依赖与 A 的问题就解决了,此时 B 也已经创建完毕,于是 A 就注入了一个初始化完全的 B 对象。

5.initializeBean 处理流程

这个方法会执行所有的 BeanPostProcessor,这里把代码流程提出来供大家参考。

    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                // 激活 Aware 方法,对特殊的 bean 处理:Aware、BeanClassLoaderAware、BeanFactoryAware
                invokeAwareMethods(beanName, bean);
                return null;
            }, getAccessControlContext());
        }
        else {
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // 前置处理,用户可以实现 BeanPostProcessor 进行自定义业务处理
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            // 如果用户实现了 InitializingBean 接口或者自定义了 init 方法,进行回调
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        }
        if (mbd == null || !mbd.isSynthetic()) {
            // 后置处理
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

参考

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值