Spring 如何创建 bean 对象?

WriteOnRead

共 24133字,需浏览 49分钟

 ·

2021-03-10 08:57

前情回顾

前文「Spring 如何从 IoC 容器中获取对象?」从整体上分析了如何从 Spring IoC 容器获取一个 bean 对象。该逻辑由 AbstractBeanFactory#doGetBean 方法实现,主要流程如下:

本文进一步深入细节,主要分析如何创建 singleton(单例)类型的对象。

如何创建单例对象?

从流程图可以看出,当获取一个 bean 对象时,Spring 会首先尝试从缓存中获取单例对象。

值得注意是的:

  1. 只有对象是单例的场景,即 scope 为 singleton 时才会缓存对象。
  2. 这里其实涉及到了所谓的「三级缓存」,为了更容易理解三级缓存,本文先研究这个 bean 对象是什么时候放入缓存的,后面再研究三级缓存。

既然能取,必然有地方把 bean 对象存入了缓存,那缓存中的数据是从哪里来的呢?

下面主要分析单例对象是如何创建、并放入缓存中的。

该逻辑在 AbstractBeanFactory#doGetBean 方法中,主要代码如下(保留了创建单例 bean 对象的代码,其他部分暂时忽略):

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    // ...

    protected <T> doGetBean(
            String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)

            throws BeansException 
{

        String beanName = transformedBeanName(name);
        Object bean;

        // 从缓存中获取单例 bean 对象
        Object sharedInstance = getSingleton(beanName);
        
        // 缓存中不存在 bean 对象
        else {

            // ...

            try {
                // 获取 BeanDefinition
                RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

                // 获取依赖的 bean 对象
                // 若创建一个 bean 对象时依赖其他对象,则先创建被依赖对象
                // ...

                // 创建 scope 为 singleton(单例)的对象
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            // ...
                        }
                    });
                    // 处理 FactoryBean 的场景
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

                // 创建 scope 为 prototype 的对象
                else if (mbd.isPrototype()) {
                    // ...
                }

                // 创建其他类型对象
                else {
                    // ...
                }
            }
            catch (BeansException ex) {
                // ...
            }
        }

        // 类型检查

        return (T) bean;
    }
}

其实就是这个 DefaultSingletonBeanRegistry#getSingleton 方法,代码如下:

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    // 单例 bean 对象缓存(beanName, bean)
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "Bean name must not be null");
        synchronized (this.singletonObjects) {
            // 先从缓存中获取 bean 对象
            Object singletonObject = this.singletonObjects.get(beanName);
            // 缓存中不存在时再去创建
            if (singletonObject == null) {
                // ...
                // 创建单例对象前
                beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet<>();
                }
                try {
                    // 创建单例对象
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }
                // catch ...
                finally {
                    if (recordSuppressedExceptions) {
                        this.suppressedExceptions = null;
                    }
                    // 创建单例对象后
                    afterSingletonCreation(beanName);
                }
                if (newSingleton) {
                    // 将对象添加到缓存
                    addSingleton(beanName, singletonObject);
                }
            }
            // 缓存中有的话直接返回
            return singletonObject;
        }
    }

}

getSingleton 方法会先从缓存 singletonObjects(其实就是一个 Map)中获取 bean 对象,如果缓存有就直接返回,否则再去创建。创建成功后,会把该对象存入缓存。

创建的逻辑在哪呢?

看代码是通过 ObjectFactory#getObject 方法来创建的,ObjectFactory 是一个函数式接口:

@FunctionalInterface
public interface ObjectFactory<T{
    getObject() throws BeansException;
}

这个方法的实现是什么呢?退回上一层,即 getBean 方法,看这里:

sharedInstance = getSingleton(beanName, () -> {
    try {
        // 创建 bean 对象
        return createBean(beanName, mbd, args);
    }
    catch (BeansException ex) {
        // ...
    }
});

这里用到了 Lambda 表达式,将如下表达式作为参数:

() -> {
    try {
        // 创建 bean 对象
        return createBean(beanName, mbd, args);
    }
    catch (BeansException ex) {
        // ...
    }
}

创建 bean 对象的逻辑就在这个 createBean 方法中,它在 AbstractAutowireCapableBeanFactory 类中:

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory 
{

    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException 
{

        RootBeanDefinition mbdToUse = mbd;

        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        // Prepare method overrides.
        try {
            mbdToUse.prepareMethodOverrides();
        }
        // catch ...

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            // 这里可能返回代理对象
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        // catch ...

        try {
            // 创建 bean 对象
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isTraceEnabled()) {
                logger.trace("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        // catch ...
    }
}

值得注意的是,resolveBeforeInstantiation 方法其实是跟 AOP 实现相关的,可能在这里生成代理对象就返回了。由于现在主要分析 IoC 的流程,因此这里暂时略过,有兴趣的朋友们可以自行研究。

这里继续沿着主线逻辑走。

创建 bean 对象是在 doCreateBean 方法中实现的,如下:

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory 
{

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

        // Instantiate the bean.
        // 1. 实例化 bean
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        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 ...
                mbd.postProcessed = true;
            }
        }

        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            // 2. 填充属性
            populateBean(beanName, mbd, instanceWrapper);
            // 3. 初始化
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        // catch ...

        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);
                        }
                    }
                    // ...
                }
            }
        }

        // Register bean as disposable.
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        // catch ...

        return exposedObject;
    }

}

注意:Instantiate 和 Initialize 虽然看起来有点像,但它俩不是一回事,前者是“实例化”,后者是“初始化”。

这个方法看起来有点长,但最主要的事情只有三件:

  1. 创建 bean 对象:createBeanInstance 方法
  2. 填充属性:populateBean 方法
  3. 初始化 bean:initializeBean 方法

这几个方法内部其实都有一大堆堆堆堆堆……的代码,再对照一下前面给出的整体流程图:

就是这样。

本文在前文整体分析的基础上又进一步细化,先到这里吧,后面再继续分析~

小结

如何从 Spring IoC 容器中获取 bean 对象?前文对此进行了整体流程的分析。

本文在前文的基础上又进一步细化,主要从整体上探讨了 Spring 如何创建单例的 bean 对象,整体上分为三个步骤:

  1. 创建 bean 对象
  2. 填充 bean 属性
  3. 初始化 bean 对象

至于这三个步骤具体又做了什么,且听下回分解。

有点「自顶向下」的感觉了,这就是「金字塔原理」?


浏览 24
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报