Spring 框架核心原理

盡管希臘哲學(xué)家赫拉克利特(Heraclitus)并不作為一名軟件開發(fā)人員而聞名,但他似乎深諳此道。他的一句話經(jīng)常被引用:“唯一不變的就是變化”,這句話抓住了軟件開發(fā)的真諦。

我們現(xiàn)在開發(fā)應(yīng)用的方式和1年前、5年前、10年前都是不同的,更別提15年前了,當(dāng)時(shí)RodJohnson的圖書 Expert One-on-One J2EE Design and Development 介紹了Spring框架的初始形態(tài)。當(dāng)時(shí),最常見的應(yīng)用形式是基于瀏覽器的Web應(yīng)用,后端由關(guān)系型數(shù)據(jù)庫(kù)作為支撐。盡管這種形式的開發(fā)依然有它的價(jià)值,Spring也為這種應(yīng)用提供了良好的支持,但是我們現(xiàn)在感興趣的還包括如何開發(fā)面向云的由微服務(wù)組成的應(yīng)用,這些應(yīng)用會(huì)將數(shù)據(jù)保存到各種類型的數(shù)據(jù)庫(kù)中。

另外一個(gè)嶄新的關(guān)注點(diǎn)是反應(yīng)式編程,它致力于通過非阻塞操作提供更好的擴(kuò)展性并提升性能。隨著軟件開發(fā)的發(fā)展,Spring框架也在不斷變化,以解決現(xiàn)代應(yīng)用開發(fā)中的問題,其中就包括微服務(wù)和反應(yīng)式編程。Spring還通過引入Spring Boot簡(jiǎn)化自己的開發(fā)模型。

Spring 的核心

任何實(shí)際的應(yīng)用程序都是由很多組件組成的,每個(gè)組件負(fù)責(zé)整個(gè)應(yīng)用功能的一部分,這些組件需要與其他的應(yīng)用元素進(jìn)行協(xié)調(diào)以完成自己的任務(wù)。當(dāng)應(yīng)用程序運(yùn)行時(shí),需要以某種方式創(chuàng)建并引入這些組件。

Application Context

Spring的核心是提供了一個(gè)容器(container),通常稱為Spring應(yīng)用上下文(Spring Application Context),它們會(huì)創(chuàng)建和管理應(yīng)用組件。

這些組件也可以稱為bean,會(huì)在Spring應(yīng)用上下文中裝配在一起,從而形成一個(gè)完整的應(yīng)用程序。這就像磚塊、砂漿、木材、管道和電線組合在一起,形成一棟房子似的。將bean裝配在一起的行為是通過一種基于依賴注入(dependency injection,DI)的模式實(shí)現(xiàn)的。此時(shí),組件不會(huì)再去創(chuàng)建它所依賴的組件并管理它們的生命周期,使用依賴注入的應(yīng)用依賴于單獨(dú)的實(shí)體(容器)來創(chuàng)建和維護(hù)所有的組件,并將其注入到需要它們的bean中。通常,這是通過構(gòu)造器參數(shù)和屬性訪問方法來實(shí)現(xiàn)的。

Spring 容器的刷新 refresh() 過程

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

流程說明:

1、prepareRefresh();
容器刷新前的準(zhǔn)備,設(shè)置上下文狀態(tài),獲取屬性,驗(yàn)證必要的屬性等

2、obtainFreshBeanFactory();
獲取新的beanFactory,銷毀原有beanFactory、為每個(gè)bean生成BeanDefinition等

3、prepareBeanFactory(beanFactory);
配置標(biāo)準(zhǔn)的beanFactory,設(shè)置ClassLoader,設(shè)置SpEL表達(dá)式解析器,添加忽略注入的接口,添加bean,添加bean后置處理器等

4、postProcessBeanFactory(beanFactory);
模板方法,此時(shí),所有的beanDefinition已經(jīng)加載,但是還沒有實(shí)例化。
允許在子類中對(duì)beanFactory進(jìn)行擴(kuò)展處理。比如添加ware相關(guān)接口自動(dòng)裝配設(shè)置,添加后置處理器等,是子類擴(kuò)展prepareBeanFactory(beanFactory)的方法

5、invokeBeanFactoryPostProcessors(beanFactory);
實(shí)例化并調(diào)用所有注冊(cè)的beanFactory后置處理器(實(shí)現(xiàn)接口BeanFactoryPostProcessor的bean,在beanFactory標(biāo)準(zhǔn)初始化之后執(zhí)行)。
例如:
PropertyPlaceholderConfigurer(處理占位符)

6、registerBeanPostProcessors(beanFactory);
實(shí)例化和注冊(cè)beanFactory中擴(kuò)展了BeanPostProcessor的bean。
例如:
AutowiredAnnotationBeanPostProcessor(處理被@Autowired注解修飾的bean并注入)
RequiredAnnotationBeanPostProcessor(處理被@Required注解修飾的方法)
CommonAnnotationBeanPostProcessor(處理@PreDestroy、@PostConstruct、@Resource等多個(gè)注解的作用)等。

7、initMessageSource();
初始化國(guó)際化工具類MessageSource

8、initApplicationEventMulticaster();
初始化事件廣播器

9、onRefresh();
模板方法,在容器刷新的時(shí)候可以自定義邏輯,不同的Spring容器做不同的事情。

10、registerListeners();
注冊(cè)監(jiān)聽器,廣播early application events

11、finishBeanFactoryInitialization(beanFactory);
實(shí)例化所有剩余的(非懶加載)單例
比如invokeBeanFactoryPostProcessors方法中根據(jù)各種注解解析出來的類,在這個(gè)時(shí)候都會(huì)被初始化。
實(shí)例化的過程各種BeanPostProcessor開始起作用。

12、finishRefresh();
refresh做完之后需要做的其他事情。
清除上下文資源緩存(如掃描中的ASM元數(shù)據(jù))
初始化上下文的生命周期處理器,并刷新(找出Spring容器中實(shí)現(xiàn)了Lifecycle接口的bean并執(zhí)行start()方法)。
發(fā)布 ContextRefreshedEvent 事件告知對(duì)應(yīng)的 ApplicationListener 進(jìn)行相應(yīng)的操作

Spring的環(huán)境抽象

Spring的環(huán)境抽象是各種配置屬性的一站式服務(wù)。它抽取了原始的屬性,這樣需要這些屬性的bean就可以從Spring本身中獲取了。Spring環(huán)境會(huì)拉取多個(gè)屬性源,包括:

?JVM系統(tǒng)屬性;
?操作系統(tǒng)環(huán)境變量;
?命令行參數(shù);
?應(yīng)用屬性配置文件。

它會(huì)將這些屬性聚合到一個(gè)源中,通過這個(gè)源可以注入到Spring的bean中。圖5.1闡述了來自各個(gè)屬性源的屬性是如何流經(jīng)Spring的環(huán)境抽象進(jìn)入Spring bean的。

Spring 為什么能夠長(zhǎng)盛不衰?

Spring 之所以能夠在技術(shù)不斷更新?lián)Q代的IT領(lǐng)域長(zhǎng)盛不衰,并且引領(lǐng)技術(shù)架構(gòu)發(fā)展的潮流,是因?yàn)?Spring 不斷適應(yīng)新技術(shù)的發(fā)展,不斷優(yōu)化和革新,讓Java應(yīng)用的開發(fā)更加便利和高效。從XML配置、注解配置,再到Spring Boot的自動(dòng)化配置,Spring在不斷簡(jiǎn)化,開發(fā)人員需要做的額外工作越來越少。

有時(shí)候,我也會(huì)思考,真正的技術(shù)到底是什么,是某一項(xiàng)生僻的 geek 技巧, 還是某個(gè)新的API?這都不是最關(guān)鍵的, 因?yàn)檫@些東西都是不穩(wěn)定的、易變的,想要在新知識(shí)層出不窮的領(lǐng)域中不被淘汰,我們更應(yīng)該去追求一些內(nèi)在穩(wěn)定不變的知識(shí),比如技術(shù)的基礎(chǔ)規(guī)范、設(shè)計(jì)原理等。


Kotlin 開發(fā)者社區(qū)

國(guó)內(nèi)第一Kotlin 開發(fā)者社區(qū)公眾號(hào),主要分享、交流 Kotlin 編程語(yǔ)言、Spring Boot、Android、React.js/Node.js、函數(shù)式編程、編程思想等相關(guān)主題。

越是喧囂的世界,越需要寧?kù)o的思考。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容