盡管希臘哲學(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的思考。