Spring 創(chuàng)建Bean流程

開篇

?在Spring 獲取Bean流程文章中已經梳理了getBean的整個過程句伶,這篇文章主要著重講講Bean的創(chuàng)建過程,順便著梳理下init-method魁亦、afterPropertiesSet、postProcessBeforeInitialization、postProcessAfterInitialization的調用過程缩举。


調用順序

<bean id="sampleBean" class="com.lntea.spring.demo.bean.SampleBean" init-method="prepare"></bean>

public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

說明
初始化過程中執(zhí)行的順序:

  • BeanPostProcessor的初始化前置回調方法postProcessBeforeInitialization()。
  • InitializingBean接口的初始化方法afterPropertiesSet()匹颤。
  • init-method初始化方法仅孩。
  • BeanPostProcessor的初始化后置回調方法postProcessAfterInitialization()。


Bean創(chuàng)建流程

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {

    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 {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
        }

        try {
            // 給 BeanPostProcessors 一個機會用來返回一個代理類而不是真正的類實例
            // AOP 的功能就是基于這個地方
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
        }

        try {
            // 執(zhí)行真正創(chuàng)建 bean 的過程
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            return beanInstance;
        }
        catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
        }
        catch (Throwable ex) {
        }
    }
}

說明:

  • 1印蓖、首先解析指定 BeanDefinition的class辽慕。
  • 2、處理BeanDefinition里面的 override 屬性赦肃。
  • 3溅蛉、實例化的前置處理BeanPostProcessor接口。
  • 4他宛、執(zhí)行根據BeanDefinition創(chuàng)建bean過程船侧。


執(zhí)行Bean創(chuàng)建過程

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {

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

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }

        // 使用合適的實例化策略來創(chuàng)建新的實例:工廠方法、構造函數自動注入堕汞、簡單初始化
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // 檢測是否有后置處理
        // 如果有后置處理勺爱,則允許后置處理修改 BeanDefinition
        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)依賴
        // 單例模式 & 運行循環(huán)依賴&當前單例 bean 是否正在被創(chuàng)建
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // 開始初始化 bean 實例對象
        Object exposedObject = bean;
        try {
            // 對 bean 進行填充,將各個屬性值注入讯检,其中琐鲁,可能存在依賴于其他 bean 的屬性
            // 則會遞歸初始依賴 bean
            populateBean(beanName, mbd, instanceWrapper);
            // 調用初始化方法
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
        }

        /**
         * 循環(huán)依賴處理
         */
        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);
                        }
                    }
                }
            }
        }

        // 注冊 bean
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
        }

        return exposedObject;
    }
}

說明:

  • 5、MergedBeanDefinitionPostProcessor 的應用人灼。
  • 6围段、單例模式的循環(huán)依賴處理。
  • 7投放、調用 populateBean() 進行屬性填充奈泪。將所有屬性填充至 bean 的實例中。
  • 8、 調用 initializeBean() 初始化 bean涝桅。
  • 9拜姿、依賴檢查。
  • 10冯遂、通過registerDisposableBeanIfNecessary注冊 DisposableBean蕊肥。


public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {

    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 {
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        // 初始化前置回調方法
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            // 初始化方法
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
        }
        if (mbd == null || !mbd.isSynthetic()) {
            // 初始化后置回調方法
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
        // 批量初始化的后置方法
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }
}

說明:

  • 11、初始化前置回調方法蛤肌。
  • 12壁却、初始化方法。
  • 13裸准、初始化后置回調方法展东。


public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {

    protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
            throws Throwable {

        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {

            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }, getAccessControlContext());
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }

        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) &&
                    !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                    !mbd.isExternallyManagedInitMethod(initMethodName)) {
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }
}

說明:

  • 14、執(zhí)行afterPropertiesSet()方法炒俱。
  • 15盐肃、執(zhí)行invokeCustomInitMethod的init-method方法。


public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {

    protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)
            throws Throwable {

        String initMethodName = mbd.getInitMethodName();
        Method initMethod = (mbd.isNonPublicAccessAllowed() ?
                BeanUtils.findMethod(bean.getClass(), initMethodName) :
                ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));


        Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod);

        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                ReflectionUtils.makeAccessible(methodToInvoke);
                return null;
            });
            try {
                AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
                        methodToInvoke.invoke(bean), getAccessControlContext());
            }
            catch (PrivilegedActionException pae) {
            }
        }
        else {
            try {
                ReflectionUtils.makeAccessible(initMethod);
                initMethod.invoke(bean);
            }
            catch (InvocationTargetException ex) {
                throw ex.getTargetException();
            }
        }
    }
}

說明:

  • 16向胡、通過反射調用init-method方法恼蓬。


參考文章

Spring源碼-IOC容器(三)-GetBean
【死磕 Spring】—– IOC 之開啟 bean 的實例化進程

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市僵芹,隨后出現的幾起案子处硬,更是在濱河造成了極大的恐慌,老刑警劉巖拇派,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荷辕,死亡現場離奇詭異,居然都是意外死亡件豌,警方通過查閱死者的電腦和手機疮方,發(fā)現死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茧彤,“玉大人骡显,你說我怎么就攤上這事≡啵” “怎么了惫谤?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長珠洗。 經常有香客問我溜歪,道長,這世上最難降的妖魔是什么许蓖? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任蝴猪,我火速辦了婚禮调衰,結果婚禮上,老公的妹妹穿的比我還像新娘自阱。我一直安慰自己嚎莉,他們只是感情好,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布动壤。 她就那樣靜靜地躺著萝喘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪琼懊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天爬早,我揣著相機與錄音哼丈,去河邊找鬼。 笑死筛严,一個胖子當著我的面吹牛醉旦,可吹牛的內容都是我干的。 我是一名探鬼主播桨啃,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼车胡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了照瘾?” 一聲冷哼從身側響起匈棘,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎析命,沒想到半個月后主卫,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡鹃愤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年簇搅,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片软吐。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡瘩将,死狀恐怖,靈堂內的尸體忽然破棺而出凹耙,到底是詐尸還是另有隱情姿现,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布使兔,位于F島的核電站建钥,受9級特大地震影響,放射性物質發(fā)生泄漏虐沥。R本人自食惡果不足惜熊经,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一泽艘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧镐依,春花似錦匹涮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至务唐,卻和暖如春雳攘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背枫笛。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工吨灭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人刑巧。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓喧兄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親啊楚。 傳聞我的和親對象是個殘疾皇子吠冤,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內容

  • 本來是準備看一看Spring源碼的。然后在知乎上看到來一個帖子恭理,說有一群**自己連Spring官方文檔都沒有完全讀...
    此魚不得水閱讀 6,934評論 4 21
  • IOC和DI是什么拯辙? Spring IOC 的理解,其初始化過程蚯斯? BeanFactory 和 FactoryBe...
    justlpf閱讀 3,474評論 1 21
  • 2.1 我們的理念是:讓別人為你服務 IoC是隨著近年來輕量級容器(Lightweight Container)的...
    好好學習Sun閱讀 2,712評論 0 11
  • 前面寫過一篇Spring擴展的文章 Spring擴展點1-NameSpaceHandler,本來想寫系列文章薄风,可是...
    一帥閱讀 11,010評論 6 19
  • 寫日記最大的好處是對思維的訓練,當 你嘗試著去說清楚一件事拍嵌,表達明白自 己的想法和觀念遭赂,這個過程...
    3c7d685e55bf閱讀 201評論 0 2