详解Spring 如何创建 Bean 对象?

时间:2021-11-20 17:35:25

详解Spring 如何创建 Bean 对象?

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

详解Spring 如何创建 Bean 对象?

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

如何创建单例对象?

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

值得注意是的:

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

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

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

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

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

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> { 

    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 如何创建 Bean 对象?

就是这样。

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

小结

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

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

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

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

原文地址:https://mp.weixin.qq.com/s/8YxzDPTAHm5RagI8mX1L7Q