Spring第四周

Spring解密 - Bean的加載流程

入口

public class Application {

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");

        Person person = context.getBean("person", Person.class);

        System.out.println(person.toString());
    }
}

BeanFactory 的由來

1.查看getBean()的源碼.

public class AbstractApplicationContext{

    @Override
    public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
        assertBeanFactoryActive();
        // getBeanFactory() 是怎么來的往枷?我們接著看
        return getBeanFactory().getBean(name, requiredType);
    }
}

2.應用程序的上下文

在 new ClassPathXmlApplicationContext("bean.xml"); 中去扣,跳轉到重載的構造方法中怪与,發(fā)現(xiàn)如下代碼

public class ClassPathXmlApplicationContext {

    public ClassPathXmlApplicationContext(
            String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
            throws BeansException {

        super(parent);
        // 解析 bean.xml 文件
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }
}

它的目的是將普通路徑解析為 類(classpath) 路徑資源名稱。多個配置文件的情況下巡语,后加載的 Bean 會覆蓋先前定義好的 Bean翎蹈,這樣做的目的是為了通過額外的XML文件來特意重寫某個 Bean。這里我們可以看到調用了一個 refresh()男公,它的作用是什么呢荤堪?
3.初始化

刷新容器

public class AbstractApplicationContext {

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 準備刷新上下文
            prepareRefresh();
            // 通知子類,刷新內部 BeanFactory(創(chuàng)建 BeanFactory 的入口)
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        }
    }

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        // 跟蹤該方法
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }
}

初次加載完 bean.xml 后枢赔,肯定會進入到 refresh() 方法中澄阳,這個時候會做容器初始化的工作,也就是 標簽解析踏拜、Bean加載 等等工作.

創(chuàng)建 DefaultListableBeanFactory

public class AbstractRefreshableApplicationContext {

    @Override
    protected final void refreshBeanFactory() throws BeansException {
        // 判斷是否存在
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            // 創(chuàng)建 DefaultListableBeanFactory
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                // 然后賦值給 beanFactory 變量
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

    // 提取 BeanFactory
    @Override
    public final ConfigurableListableBeanFactory getBeanFactory() {
        synchronized (this.beanFactoryMonitor) {
            if (this.beanFactory == null) {
                throw new IllegalStateException("BeanFactory not initialized or already closed - " +
                        "call 'refresh' before accessing beans via the ApplicationContext");
            }
            return this.beanFactory;
        }
    }
}

從上面的代碼塊中碎赢,我們可以看到 如果已經存在 beanFactory,將銷毀舊的實例速梗,然后在創(chuàng)建新的 DefaultListableBeanFactory肮塞,最后 getBeanFactory() 就可以正常使用了襟齿。

Bean 加載
整個 Bean 的裝載過程中,重點圍繞 AbstractBeanFactory

public abstract class AbstractBeanFactory {

    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        // 別名轉換
        final String beanName = transformedBeanName(name);
        Object bean;

        // 檢查緩存中是否存在 該 Bean 的單例(Bean默認的Scope = singleton)
        // 比如容器初始化的時候或者其他地方調用過getBean枕赵,已經完成了初始化
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
        //執(zhí)行一次logger.isDebugEnabled()這樣的判斷花費的時間大概是寫日志時間的萬分之一
            if (logger.isDebugEnabled()) {
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                            "' that is not fully initialized yet - a consequence of a circular reference");
                } else {
                    logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
            // 返回實例猜欺,F(xiàn)actoryBean 的情況下,并不是直接返回實例本身而是返回指定方法返回的實例
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            // 存在循環(huán)依賴則報錯
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // 判斷工廠中是否含有當前 Bean 的定義
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // 如果沒有拷窜,查詢父工廠
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                            nameToLookup, requiredType, args, typeCheckOnly);
                }
                else if (args != null) {
                    // 執(zhí)行帶有 args 參數(shù)的 getBean 方法
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    // 如果沒有參數(shù)开皿,執(zhí)行標準的 getBean 方法 
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }

            if (!typeCheckOnly) { // 如果不是做類型檢查,則需要標記此 Bean 正在創(chuàng)建之中
                markBeanAsCreated(beanName);
            }

            try {
                // 將存儲XML配置文件的GernericBeanDefinition轉換成RootBeanDefinition篮昧,如果BeanName是子Bean的話會合并父類的相關屬性
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);

                // 獲取依賴的 Bean
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        registerDependentBean(dep, beanName);
                        getBean(dep);
                    }
                }

                // 終于開始創(chuàng)建 Bean 實例了赋荆,如果是單例的,那么會創(chuàng)建一個單例的匿名工廠懊昨,
                // 如果是原型模式的糠睡,則不需要創(chuàng)建單例的工廠的,其他的如 request疚颊、session 作用域的,則根據自身的需要
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);// 調用默認構造函數(shù)信认,有興趣自己跟進下代碼
                        }
                        catch (BeansException ex) {
                            // Explicitly remove instance from singleton cache: It might have been put there
                            // eagerly by the creation process, to allow for circular reference resolution.
                            // Also remove any beans that received a temporary reference to the bean.
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

                else if (mbd.isPrototype()) {
                    // It's a prototype -> create a new instance.
                    Object prototypeInstance = null;
                    try {
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

                else {
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
                    try {
                        Object scopedInstance = scope.get(beanName, () -> {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                afterPrototypeCreation(beanName);
                            }
                        });
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }
                    catch (IllegalStateException ex) {
                        throw new BeanCreationException(beanName,
                                "Scope '" + scopeName + "' is not active for the current thread; consider " +
                                "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                                ex);
                    }
                }
            }
            catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }

        // 類型檢查材义,如果不能進行類型轉換,則拋出異常
        if (requiredType != null && !requiredType.isInstance(bean)) {
            try {
                T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
                if (convertedBean == null) {
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
                return convertedBean;
            }
            catch (TypeMismatchException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Failed to convert bean '" + name + "' to required type '" +
                            ClassUtils.getQualifiedName(requiredType) + "'", ex);
                }
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        }
        return (T) bean;
    }
}

一步一步的分析

轉換 BeanName

final String beanName = transformedBeanName(name);

protected String transformedBeanName(String name) {
    return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

去除 FactoryBean 的修飾符嫁赏,最終取指定 alias 所表示的 beanName其掂。因為有可能獲取到以 & 開頭的 FactoryBean,所以要進行轉化

加載單例

檢查緩存中是否存在 該 Bean 的單例(Bean默認的Scope = singleton)潦蝇,如容器初始化的時候或者其他地方已經調用過 getBean() 完成了初始化

Object sharedInstance = getSingleton(beanName);

默認在裝載 Bean 的時候會先去檢查 singletonObjects 是否存在款熬,如果存在直接提取緩存的。

public class DefaultSingletonBeanRegistry {

    /** 保存 BeanName 和創(chuàng)建 bean 實例之間的關系 bean name --> bean instance */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /** 保存 BeanName 和創(chuàng)建 bean 實例的工廠之間的關系 bean name --> ObjectFactory */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    /** 保存 BeanName 和創(chuàng)建 bean 實例之間的關系 bean name --> bean instance */
    /** 與 singletonObjects 不同的是當一個單例 bean 被放到里面后攘乒,那么在 bean 在創(chuàng)建過程中贤牛,就可以通過 getBean 方法獲取到,可以用來檢測循環(huán)引用则酝。 **/
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

    /** 保存當前所有已注冊的 bean */
    private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // 嘗試從緩存獲取實例
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                // 若該 bean 正在加載則不處理
                singletonObject = this.earlySingletonObjects.get(beanName);
                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;
    }
}

構建實例(無緩存情況)

緩存中沒有殉簸,那就當場構建一個 bean 出來,可以看到 getSingleton(String beanName, ObjectFactory<?> singletonFactory) 有兩個參數(shù)

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    synchronized (this.singletonObjects) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            // 記錄加載狀態(tài)沽讹,般卑,以便對循環(huán)依賴進行檢測
            beforeSingletonCreation(beanName);
            singletonObject = singletonFactory.getObject();
            // 移除加載狀態(tài)
            afterSingletonCreation(beanName);
            addSingleton(beanName, singletonObject);
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }
}

構建 ObjectFactory
此處與其說是構建 ObjectFactory ,不如說是在創(chuàng)建一個單例 Bean

if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, () -> {
        try {
            // 對 JDK8 lambda 表達式熟悉的小伙伴就不會陌生了
            return createBean(beanName, mbd, args);
        }
        catch (BeansException ex) {
            destroySingleton(beanName);
            throw ex;
        }
    });
    // 劃重點了
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

創(chuàng)建 Bean

public class AbstractAutowireCapableBeanFactory {

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

        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        // 首先判斷需要創(chuàng)建的bean是否可以被實例化爽雄,這個類是否可以通過類裝載器來載入蝠检。
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        // 準備方法覆蓋
        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // 用 BeanPostProcessors 返回代理來替代真正的實例(如果 Bean 配置了 PostProcessor,那么這里返回的是一個代理)
            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 {
            // 重點來了
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isDebugEnabled()) {
                logger.debug("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        catch (BeanCreationException ex) {
            // A previously detected exception with proper bean creation context already...
            throw ex;
        }
        catch (ImplicitlyAppearedSingletonException ex) {
            // An IllegalStateException to be communicated up to DefaultSingletonBeanRegistry...
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
        }
    }
}

在創(chuàng)建 Bean 之前挚瘟,Spring 還做了不少工作叹谁。

  • 判斷創(chuàng)建的 bean 是否可以被實例化饲梭,這個類是否可以通過 ClassLoader 來載入,根據設置的 class 屬性或根據 className 來解析 class本慕。
  • 對覆蓋進行標記并驗證排拷,在 Spring 配置中存在 lookup-mothod 和 replace-method 的,這兩個配置的加載時將配置統(tǒng)一存放在 BeanDefinition 中的 methodOverrides 屬性里锅尘,這個方法的操作也是針對于這兩個配置的监氢;
  • 應用初始化前的后處理器,最后創(chuàng)建 bean藤违。在 createBean() 方法里執(zhí)行完 resolveBeforeInstantiation 方法后浪腐,如果創(chuàng)建了代理且不為空的話就直接返回,否則需要進行常規(guī) bean 的創(chuàng)建顿乒,這個創(chuàng)建過程是在 doCreateBean 中完成的

初始化 Bean
上面 createBean 交給了 doCreateBean 來創(chuàng)建 bean (上面還有一個重要的方法getObjectForBeanInstance议街,在后面分析)

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

    // 實例化 Bean
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // 根據指定 bean 使用相應策略創(chuàng)建實例(正確情況會調用無參構造函數(shù))
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // 獲取實例化好的 Bean(Person person = new Person()),此處還未進行賦值
    final Object bean = instanceWrapper.getWrappedInstance();
    // 獲得實例化好的 class
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    // 記錄創(chuàng)建 Bean 的 ObjectFactory璧榄,初始化前調用 post-processors特漩,可以讓我們在 bean 實例化之前做一些定制操作
    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;
        }
    }

    // 檢測循環(huán)依賴,是否需要提早初始化(只能解決單例Bean)
    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");
        }
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    // 初始化bean實例骨杂。
    Object exposedObject = bean;
    try {
        // 在這個方法里面初始化對象涂身,配置 xml 中的各種屬性
        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) {
        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);
                    }
                }
                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;
}

上面源碼完成的操作可以概括為以下幾點

  • RootBeanDefinition 是不是單例,如果是單例先移除緩存
  • 實例化 bean搓蚪,將 RootBeanDefinition 轉換為 BeanWrapper
  • 使用 MergedBeanDefinitionPostProcessor蛤售,Autowired注解 就是通過此方法實現(xiàn)類型的預解析;
  • 解決循環(huán)依賴問題
  • 在 populateBean() 中填充屬性妒潭,配置在 XML 中的各種屬性
  • 注冊到 DisposableBean 中
  • 完成創(chuàng)建并返回 Bean 的實例
    接下來看下 Spring 是如何創(chuàng)建 bean 實例的悴能。跟蹤 createBeanInstance() 方法

創(chuàng)建Bean實例

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // 獲取 beanClass , 要先確保 Bean 是正確的雳灾,已經解析到當前節(jié)點了
    Class<?> beanClass = resolveBeanClass(mbd, beanName);

    if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
    }

    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }

    // 若工廠方法不為空則使用工廠方法初始化
    if (mbd.getFactoryMethodName() != null)  {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // Shortcut when re-creating the same bean...
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    // 如果已經解析過則使用解析好的構造方法不需要再次鎖定
    if (resolved) {
        if (autowireNecessary) {
            // 構造方法自動注入
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            // 使用默認構造方法
            return instantiateBean(beanName, mbd);
        }
    }

    // 根據參數(shù)解析構造方法
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null ||
            mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // 沒有特殊處理的情況下漠酿,只需使用無參數(shù)的構造函數(shù)。
    return instantiateBean(beanName, mbd);
}

可以看出如果在 RootBeanDefinition 中存在 factoryMethodName屬性佑女,或者說配置文件中配置了 factory-method记靡,那么 Spring 會嘗試使用 instantiateUsingFactoryMethod(beanName, mbd, args) 方法根據 RootBeanDefinition 中的配置生成bean實例。然后再解析構造方法并進行實例化团驱,Spring 會根據參數(shù)及類型判斷使用哪個構造方法進行實例化摸吠。判斷調用哪個構造方法的過程會采用緩存機制,如果已經解析過則不需要重復解析而是從 RootBeanDefinition 中的屬性 resolvedConstructorOrFactoryMethod 緩存的值去取嚎花,否則需再次解析寸痢。

populateBean 屬性注入

這塊代碼比較多,就不貼出來了

在 populateBean 方法的中的主要處理流程:

  • InstantiationAwareBeanPostProcessor 處理器的 postProcessAfterInstantiation 方法控制程序是否繼續(xù)填充屬性紊选;
  • 根據注入類型提取依賴的 bean啼止,并存入 PropertyValues 中道逗;
  • InstantiationAwareBeanPostProcessor 處理器的 postProcessPropertyValues 方法對屬性在填充前再次處理(主要還是驗證屬性);
  • 將所有 PropertyValues 中的屬性填充到 BeanWrapper 中献烦;

initializeBean 初始化Bean
Spring 的 bean 配置時有一個 init-method 屬性滓窍,這個屬性的作用是在 bean 實例化前調用 init-method 指定的方法進行需要的操作,現(xiàn)在就進入這個方法了巩那;Spring 執(zhí)行過 bean 的實例化吏夯,并且進行屬性填充后,就會調用用戶設定的初始化方法即横。

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        // 特殊bean處理
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        // 調用配置的 init-method
        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;
}

最后加載完 Bean 并執(zhí)行完初始化操作后噪生,一個 bean 的加載基本就結束了。

增強的 Bean
通過上面的描述东囚,我們已經知道了一個的 Bean 是如何初始化的跺嗽,已經具備普通 Bean 的功能。但是 Spring 還提供了一種增強的 Bean(FactoryBean)页藻,具備 factory 能力的 Bean桨嫁,這個能力主要在 getObjectForBeanInstance 得到。

public class AbstractBeanFactory {

    protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    
        // 如果想要獲取 FactoryBean 本身,那么 beanInstance 必須是 FactoryBean 的實例
        if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
        }
    
        // 如果 instance 不是 FactoryBean 實例,或者想要獲取的就是 FactoryBean 實例份帐,那么直接返回就好
        if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
            return beanInstance;
        }
    
        Object object = null;
        if (mbd == null) {
            // 獲取緩存的實例
            object = getCachedObjectForFactoryBean(beanName);
        }
        if (object == null) {
            // 緩存中沒有對象,那么從頭準備 bean defition 實例化一個
            FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
            // Caches object obtained from FactoryBean if it is a singleton.
            if (mbd == null && containsBeanDefinition(beanName)) {
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            boolean synthetic = (mbd != null && mbd.isSynthetic());
            // 在這里面獲得最終的FactoryBean
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末瞧甩,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子弥鹦,更是在濱河造成了極大的恐慌,老刑警劉巖爷辙,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件彬坏,死亡現(xiàn)場離奇詭異,居然都是意外死亡膝晾,警方通過查閱死者的電腦和手機栓始,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來血当,“玉大人幻赚,你說我怎么就攤上這事‰瘢” “怎么了落恼?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長离熏。 經常有香客問我佳谦,道長,這世上最難降的妖魔是什么滋戳? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任钻蔑,我火速辦了婚禮啥刻,結果婚禮上,老公的妹妹穿的比我還像新娘咪笑。我一直安慰自己可帽,他們只是感情好,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布窗怒。 她就那樣靜靜地躺著映跟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪兜粘。 梳的紋絲不亂的頭發(fā)上申窘,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機與錄音孔轴,去河邊找鬼剃法。 笑死,一個胖子當著我的面吹牛路鹰,可吹牛的內容都是我干的贷洲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼晋柱,長吁一口氣:“原來是場噩夢啊……” “哼优构!你這毒婦竟也來了?” 一聲冷哼從身側響起雁竞,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤钦椭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后碑诉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體彪腔,經...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年进栽,在試婚紗的時候發(fā)現(xiàn)自己被綠了德挣。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡快毛,死狀恐怖格嗅,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情唠帝,我是刑警寧澤屯掖,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站襟衰,受9級特大地震影響懂扼,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一阀湿、第九天 我趴在偏房一處隱蔽的房頂上張望赶熟。 院中可真熱鬧,春花似錦陷嘴、人聲如沸映砖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽邑退。三九已至,卻和暖如春劳澄,著一層夾襖步出監(jiān)牢的瞬間地技,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工秒拔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留莫矗,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓砂缩,卻偏偏與公主長得像作谚,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子庵芭,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內容