經過此前我們設計的如:IoC、Web、數據訪問、AOP等模塊的設計,我們從設計上已經搭建好了Spring的基礎骨架了,但聰明的碼友會思考想到:作為一個基礎框架而言,目前應該是已經夠用了的,但是上進的碼友怎么會就此止步;從模塊劃分上每個模塊均有自己要關注和實現的內容,那么是否會存在一些共有的內容,比如:環境配置、事件機制、國際化等。
一、背景與設計理念
在Spring框架早期版本中,BeanFactory作為最基礎的IoC容器實現,僅提供了基礎的依賴注入功能和Bean生命周期管理。開發者需要通過顯式編碼來創建和管理對象,每個Bean的依賴關系都需要手動配置和解析,導致大量重復代碼。隨著企業應用復雜度增加,這種基礎容器的局限性日益凸顯:缺乏事件機制、國際化支持薄弱、資源抽象不足(資源配置分散在各模塊),難以滿足現代應用的需求。
Spring上下文的誕生正是為了解決這些痛點。ApplicationContext作為BeanFactory的擴展,在保留核心依賴注入功能的同時,引入了多項企業級服務支持,形成了完整的應用執行環境。與基礎BeanFactory相比,ApplicationContext提供了以下關鍵增強:
- 資源管理統一化:通過
ResourceLoader
和Resource
接口抽象不同來源的資源(類路徑、文件系統、URL等),使資源獲取與具體環境解耦; - 國際化便捷支持:基于
MessageSource
接口提供消息解析機制,支持層次化消息源和地區化處理 - 事件發布訂閱模型:通過
ApplicationEventPublisher
和ApplicationListener
實現觀察者模式,增強組件間解耦 - 上下文層次化管理:支持父子容器結構,允許在不同層次共享或隔離配置
1、有無Spring上下文的對比分析
能力維度 | 無上下文(BeanFactory) | 有上下文(ApplicationContext) |
---|---|---|
依賴注入 | 基礎Bean管理支持 | 完整Bean生命周期管理 |
資源配置 | 需手動處理資源路徑 | 統一資源抽象(ResourceLoader) |
國際化 | 無內置支持 | 多語言消息源(MessageSource) |
事件機制 | 需自定義實現 | 內置發布-訂閱模型 |
容器結構 | 單一容器 | 支持父子容器層次 |
AOP集成 | 手動代理創建 | 聲明式切面支持 |
與框架集成 | 困難 | Spring MVC/Spring Boot無縫集成 |
在Spring Boot和Spring Cloud等現代框架中,上下文設計進一步演進出層次化容器結構。當使用SpringApplicationBuilder
構建應用時,會自動創建父子上下文層次:Bootstrap上下文作為父容器,主應用上下文作為子容器。這種設計使得:
- 配置繼承:子容器可以訪問父容器的屬性源,實現配置共享
- 隔離與覆蓋:子容器可定義同名屬性覆蓋父容器配置
- 多級擴展:通過
parent()
,child()
,sibling()
方法構建復雜容器關系 - 模塊化部署:不同模塊可使用獨立上下文,通過父子關系共享基礎服務
這種層次化設計在微服務架構中尤為重要。例如在Spring Cloud應用中,Bootstrap上下文負責加載外部配置中心參數,主應用上下文則處理業務Bean初始化,二者分離既保證配置優先加載,又避免環境污染。
2、解耦悖論
Spring模塊化設計的初衷是解耦,但上下文模塊的出現,似乎讓上下文模塊成了核心依賴,那么豈不是違背了解耦的初衷。
確實,Spring各模塊(如AOP、事務、數據訪問)都需要訪問ApplicationContext
獲取Bean或環境信息,形成了事實上的中心依賴點。但這并不違背解耦原則,原因在于:
- 依賴抽象而非實現
所有模塊依賴的是ApplicationContext
接口(定義在spring-context
模塊),而非具體實現類。這種接口隔離確保了模塊間通過契約交互:
- 上下文本質是“集成中樞”
上下文不是業務組件,而是基礎設施層。就像操作系統為應用提供統一API,Spring上下文為模塊提供:- 環境配置(
Environment
) - 依賴查找(
getBean()
) - 資源抽象(
ResourceLoader
) - 事件機制(
ApplicationEventPublisher
)
- 環境配置(
這種中心化服務提供是框架的必然設計。
二、核心組件與職能劃分
通過以上了解,所以在Spring上下文模塊的設計上,要注重設計接口分層和類繼承體系,且要實現功能的高內聚和低耦合。以下從核心接口、實現類和支撐技術三個維度進行分析設計
組件類型 | 關鍵類/接口 | 主要職責 | 實現技術 |
---|---|---|---|
核心接口 | ApplicationContext | 容器基本功能定義 | 接口聚合 |
ConfigurableApplicationContext | 生命周期和配置擴展 | 生命周期方法 | |
WebApplicationContext | Web環境擴展 | ServletContext集成 | |
實現類 | AbstractApplicationContext | 容器刷新模板實現 | 模板方法模式 |
GenericApplicationContext | 輕量級通用容器 | 組合BeanFactory | |
AnnotationConfigApplicationContext | 注解配置支持 | 注解掃描解析 | |
EmbeddedWebApplicationContext | 內嵌Web容器支持 | Servlet3.0+API | |
支撐組件 | Environment | 環境配置抽象 | PropertySource體系 |
BeanDefinitionRegistry | Bean定義動態注冊 | Bean元數據操作 | |
ApplicationEventMulticaster | 事件廣播機制 | 觀察者模式 | |
ResourcePatternResolver | 資源加載策略 | 路徑匹配解析 |
1. 核心接口體系
- ApplicationContext (核心容器接口):設計一個上下文模塊的根基接口,集成多個基礎接口能力,定義容器的基本行為。它繼承
BeanFactory
提供Bean管理能力,ResourcePatternResolver
支持資源加載,ApplicationEventPublisher
實現事件推送,MessageSource
處理國際化消息。這種接口聚合設計避免了繼承爆炸問題。 - ConfigurableApplicationContext (可配置上下文):擴展
ApplicationContext
,增加生命周期控制(start()
,stop()
,close()
)和配置能力(設置父容器、注冊關閉鉤子等)。它是所有可寫上下文的契約接口,為子類提供可定制入口點。 - WebApplicationContext (Web環境擴展):專為Web應用設計,增加
getServletContext()
方法獲取Servlet上下文,提供Web作用域Bean支持(request/session/application)。
2. 關鍵實現類
- AbstractApplicationContext (抽象模板實現):可作為所有具體上下文的骨架實現,采用模板方法模式定義上下文初始化的標準流程,尤其是
refresh()
方法的實現是整個Spring容器啟動的核心。其關鍵方法包括:
// 模板方法定義容器刷新流程
@Override
public void refresh() throws BeansException, IllegalStateException {this.startupShutdownLock.lock();try {this.startupShutdownThread = Thread.currentThread();StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// Prepare this context for refreshing.// 準備此上下文以刷新。prepareRefresh();// Tell the subclass to refresh the internal bean factory.// 告訴子類刷新內部bean工廠ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.// 準備好bean工廠以便在上下文中使用prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.// 子類可以對bean工廠進行后處理,比如注冊一些bean處理器、注冊一些監聽器、注冊一些事件處理器等。postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// Invoke factory processors registered as beans in the context.// 調用工廠處理器,這些處理器是作為bean在context中注冊的。invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.// 注冊Bean后置處理器registerBeanPostProcessors(beanFactory);beanPostProcess.end();// 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 (RuntimeException | Error 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 {contextRefresh.end();}}finally {this.startupShutdownThread = null;this.startupShutdownLock.unlock();}
}
- GenericApplicationContext (通用配置上下文):基于組合優于繼承原則設計的輕量級實現,內部持有
DefaultListableBeanFactory
實例,避免了復雜的繼承層次。適合基于Java配置的應用場景,是AnnotationConfigApplicationContext
的基類。
- AnnotationConfigWebApplicationContext (注解驅動Web上下文):專為Servlet環境設計的注解配置上下文,支持通過
@Configuration
類定義Bean,自動掃描@Component
組件。內部使用AnnotatedBeanDefinitionReader
解析注解配置。
3. 支撐性技術組件
- Environment抽象 (環境配置):通過
Environment
接口和PropertySource
抽象,統一管理配置屬性源(系統變量、環境變量、配置文件等),支持Profile條件裝配。在上下文層次結構中,子容器通過Environment.merge()
合并父容器環境。 - BeanDefinitionRegistry (Bean定義注冊):提供動態注冊Bean定義的能力,允許在運行時修改容器元數據。
GenericApplicationContext
直接實現此接口,支持編程式Bean注冊。 - ApplicationEventMulticaster (事件廣播器):作為觀察者模式的核心實現,管理事件監聽器列表,支持同步/異步事件分發。默認使用
SimpleApplicationEventMulticaster
實現,可通過TaskExecutor擴展為異步模式。
三、核心設計模式應用
1. 代理模式:功能委托與擴展
代理模式在上下文設計中應用廣泛,主要體現在功能解耦和職責分離兩方面。AbstractApplicationContext
內部通過多個代理組件實現功能委托。
這種設計帶來兩大優勢:
- 靈活性:可動態替換代理實現(如將
SimpleApplicationEventMulticaster
替換為異步廣播器) - 可擴展性:子類只需覆蓋
initApplicationEventMulticaster()
等初始化方法即可定制組件
public abstract class AbstractApplicationContext {// 消息代理@Nullableprivate MessageSource messageSource;// 事件廣播器代理@Nullableprivate ApplicationEventMulticaster applicationEventMulticaster;// 資源解析器代理private ResourcePatternResolver resourcePatternResolver;@Overridepublic String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {// 委托給messageSource處理return getMessageSource().getMessage(code, args, defaultMessage, locale);}@Overridepublic void publishEvent(ApplicationEvent event) {// 委托給applicationEventMulticaster廣播事件getApplicationEventMulticaster().multicastEvent(event);}
}
2. 模板方法模式:容器生命周期標準化
AbstractApplicationContext.refresh()
方法是模板方法模式的典范,定義了容器初始化的12步標準流程,但將關鍵步驟設計為可擴展點:
- 可覆蓋方法:如
postProcessBeanFactory()
、onRefresh()
等protected方法允許子類擴展 - 抽象方法:如
obtainFreshBeanFactory()
強制子類提供具體實現 - 鉤子方法:如
registerBeanPostProcessors()
提供默認實現,子類可選擇覆蓋
這種設計使Spring能夠支持多樣化的配置方式(XML、注解、Groovy等),同時保持核心初始化流程的統一性。例如ClassPathXmlApplicationContext
通過覆蓋loadBeanDefinitions()
方法實現XML解析:
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {@Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {// 創建XML解析器XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);// 加載XML配置reader.loadBeanDefinitions(getConfigLocations());}
}
3. 組合模式:容器層次結構構建
Spring通過組合模式實現容器層次結構,ApplicationContext
接口提供getParent()
方法獲取父容器引用。這種設計在Web應用中尤為重要:
public class CustomWebApplicationInitializer implements WebApplicationInitializer {public void onStartup(ServletContext servletContext) {// 創建父容器(服務層Bean)AnnotationConfigApplicationContext rootContext = new AnnotationConfigApplicationContext();rootContext.register(ServiceConfig.class);rootContext.refresh();// 創建子容器(Web層Bean)AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();webContext.setParent(rootContext); // 設置父子關系webContext.register(WebConfig.class);// 將子容器關聯到DispatcherServletDispatcherServlet servlet = new DispatcherServlet(webContext);ServletRegistration.Dynamic reg = servletContext.addServlet("app", servlet);}
}
在此結構中:
- Web層容器可訪問父容器的Bean(如Service組件)
- 父容器無法訪問子容器Bean,實現關注點分離
- 配置隔離:各層容器可獨立配置自己的Bean作用域
4. 觀察者模式:事件驅動機制
Spring的事件模型是觀察者模式的典型應用,由三個核心組件構成:
- ApplicationEvent:事件對象(如
ContextRefreshedEvent
,RequestHandledEvent
) - ApplicationListener:事件監聽器接口
- ApplicationEventMulticaster:事件廣播中心
具體應用示例:
// 1. 定義自定義事件
public class UserModifyEvent extends ApplicationEvent {public UserModifyEvent(Object source) {super(source);}
}// 2. 創建事件監聽器
@Component
public class UserModifyListener implements ApplicationListener<UserModifyEvent> {@Overridepublic void onApplicationEvent(UserModifyEvent event) {// 處理更新事件邏輯}
}// 3. 發布事件
@Service
public class UserService {@Autowiredprivate ApplicationEventPublisher publisher;public void updateUser(User user) {// 業務邏輯...publisher.publishEvent(new UserModifyEvent(this));}
}
這種松耦合通信機制使業務組件無需直接引用即可交互,增強系統可維護性。
5. 策略模式:可插拔組件實現
上下文模塊中多處應用策略模式實現算法可替換:
- 資源加載:
ResourcePatternResolver
作為策略接口,PathMatchingResourcePatternResolver
是其默認實現 - 環境管理:
Environment
接口抽象環境策略,StandardEnvironment
和StandardServletEnvironment
提供不同實現 - 屬性解析:
PropertyResolver
定義屬性解析策略,PropertySourcesPropertyResolver
基于PropertySources
實現
策略模式使Spring能夠適應不同運行環境。例如在測試環境中可替換為模擬策略:
public class TestApplicationContext extends GenericApplicationContext {@Overrideprotected ConfigurableEnvironment createEnvironment() {// 返回測試專用的環境策略return new MockEnvironment();}
}
四、高級特性與應用實踐
1. 層次化容器設計
Spring的容器層次結構不僅僅是父子關系,而是支持多級嵌套和交叉引用的復雜拓撲。在Spring Cloud環境中,這種設計發揮到極致:
Bootstrap Context (最高級)||--- Application Context (主應用)||--- Web MVC Context (Web模塊)||--- Batch Context (批處理模塊)
屬性解析規則在這種層次結構中遵循:
- 優先子級:子容器屬性覆蓋父容器同名屬性
- 源獨立性:每個容器維護獨立的屬性源(bootstrap, application等)
- 名稱空間隔離:相同屬性源名稱在不同層級互不影響
通過SpringApplicationBuilder
可編程式構建此結構:
new SpringApplicationBuilder().parent(ParentConfig.class).web(WebApplicationType.NONE) // 父容器.child(WebConfig.class).web(WebApplicationType.SERVLET) // 子容器.sibling(BatchConfig.class).web(WebApplicationType.NONE) // 兄弟容器.run(args);
2. 環境抽象與配置管理
Environment
抽象是Spring上下文的核心創新,通過PropertySource
體系統一管理配置源:
- 層次化覆蓋:子容器環境自動合并父容器環境,子級PropertySource優先
- 動態配置:通過
@PropertySource
注解動態添加配置源 - Profile激活:條件化加載Bean定義,實現環境適配
在Spring Boot中,屬性加載順序的精心設計體現了環境抽象的威力:
- 默認屬性(通過
SpringApplication.setDefaultProperties
設置) @Configuration
類上的@PropertySource
- 配置數據(application.properties/YAML)
- 操作系統環境變量
- JVM系統屬性
3. 條件化裝配機制
Spring 4.0引入的@Conditional
注解將條件判斷提升到元編程級別,成為Spring Boot自動配置的基石。其擴展應用包括:
- Profile條件:
@Profile
底層基于@Conditional
實現 - 屬性條件:
@ConditionalOnProperty
根據屬性存在性/值決定裝配 - 資源條件:
@ConditionalOnResource
檢測資源存在性 - Bean條件:
@ConditionalOnBean
/@ConditionalOnMissingBean
根據容器中Bean存在性決策
自定義條件示例:
public class ClusterModeCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {// 從環境獲取運行模式String mode = context.getEnvironment().getProperty("cluster.mode");// 僅當模式為"high-availability"時匹配return "high-availability".equalsIgnoreCase(mode);}
}// 使用自定義條件裝配
@Configuration
@Conditional(ClusterModeCondition.class)
public class ClusterConfig {@Beanpublic ClusterService clusterService() {return new HighClusterService();}
}
4. 上下文生命周期管理
上下文的生命周期由ConfigurableApplicationContext
接口嚴格定義,核心階段包括:
- 初始化:構造上下文實例,設置配置源
- 準備刷新:
prepareRefresh()
初始化環境屬性 - Bean工廠創建:
obtainFreshBeanFactory()
加載Bean定義 - 后處理:執行
BeanFactoryPostProcessor
- Bean實例化:注冊
BeanPostProcessor
,初始化單例 - 完成刷新:發布
ContextRefreshedEvent
- 運行中:處理請求/調用
- 關閉:發布
ContextClosedEvent
,銷毀Bean
生命周期事件為應用提供關鍵擴展點:
ContextStartedEvent
:上下文啟動后ContextStoppedEvent
:上下文停止后ContextRefreshedEvent
:上下文完全刷新ContextClosedEvent
:上下文關閉
五、設計總結與啟示
Spring上下文模塊經過多年演進形成的架構,體現了以下核心設計哲學:
- 可擴展性設計:通過模板方法模式定義骨架流程,預留擴展點(如
postProcessBeanFactory()
)允許子類定制特定步驟。這種設計使Spring能無縫支持XML、注解、Groovy等多種配置方式,同時保持核心流程穩定。 - 關注點分離:采用代理模式將消息、事件、資源等功能委托給專門組件,確保核心容器職責單一。例如
ApplicationEventMulticaster
專注事件廣播,MessageSource
處理國際化,各組件通過接口契約協作。 - 層次化抽象:通過組合模式構建容器父子關系,實現配置繼承與覆蓋。在微服務架構中,這種設計衍生出Bootstrap上下文、主應用上下文、Web上下文的層級結構,為Spring Cloud的配置管理、服務發現等提供基礎設施。
在現代云原生應用開發中,上下文設計啟示我們:
- 環境適配:通過
Environment
抽象統一管理配置源,使應用可無縫遷移到不同環境(本地、測試、生產) - 條件化裝配:基于
@Conditional
的自動配置機制大幅減少樣板代碼 - 事件驅動:內置事件模型支持響應式編程,增強組件解耦
- 生命周期管理:標準化的生命周期使框架擴展更可控
Spring上下文模塊的成功證明:強大的抽象能力和合理的分層設計是框架靈活性的基石。其設計思想不僅適用于Java生態系統,對任何復雜框架的開發都具有參考價值。隨著Spring 6和Spring Boot 3的演進,響應式上下文、原生鏡像支持等新特性將繼續拓展上下文設計的邊界,為開發者提供更強大的企業級支持。