前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring 如何创建 bean 对象?

Spring 如何创建 bean 对象?

作者头像
WriteOnRead
发布2021-03-12 16:12:03
9740
发布2021-03-12 16:12:03
举报
文章被收录于专栏:WriteOnReadWriteOnRead

前情回顾

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

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

如何创建单例对象?

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

值得注意是的:

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

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

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

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

代码语言:javascript
复制
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    // ...

    protected <T> 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 方法,代码如下:

代码语言:javascript
复制
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 是一个函数式接口:

代码语言:javascript
复制
@FunctionalInterface
public interface ObjectFactory<T> {
    T getObject() throws BeansException;
}

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

代码语言:javascript
复制
sharedInstance = getSingleton(beanName, () -> {
    try {
        // 创建 bean 对象
        return createBean(beanName, mbd, args);
    }
    catch (BeansException ex) {
        // ...
    }
});

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

代码语言:javascript
复制
() -> {
    try {
        // 创建 bean 对象
        return createBean(beanName, mbd, args);
    }
    catch (BeansException ex) {
        // ...
    }
}

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

代码语言:javascript
复制
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 方法中实现的,如下:

代码语言:javascript
复制
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 对象

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

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-03-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 WriteOnRead 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前情回顾
  • 如何创建单例对象?
  • 小结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档