在 Spring 體系中,ApplicationContext 是 Bean 容器的核心介面。根據應用類型(獨立程序、Web 應用、單元測試)與代碼所在位置(普通類、Controller、Filter、Listener),獲取 Bean 的最佳路徑各不相同。本文系統梳理五種主流方式,附適用場景與代碼範例。
適用於 main 方法、批處理任務、JUnit 測試 等非 Web 環境,或需加載多個配置文件時。
// 經典 XML 配置
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 或註解配置
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService bean = ctx.getBean(MyService.class);
// 使用完畢關閉容器(釋放資源、調用 destroy-method)
((ConfigurableApplicationContext) ctx).close();
優點: 完全可控;缺點: 每次調用都會重新啟動容器,生產環境嚴禁在請求鏈路中使用。
在 ServletContext 可獲取的場景下(如 Filter.doFilter、ServletContextListener、Struts2 Action),通過工具類從 ServletContext 屬性中取出容器。
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.context.WebApplicationContext;
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
WebApplicationContext ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext((ServletContext) req.getServletContext());
MyService service = ctx.getBean(MyService.class);
// ...
}
}
getRequiredWebApplicationContext() 找不到時拋異常,getWebApplicationContext() 返回 null,按需選擇。
最推薦的「非侵入式」方式:讓任意 Spring Bean 實現該接口,容器啟動時自動回調注入 ApplicationContext。
T getBean(Class clazz) {
return context.getBean(clazz);
}
public static Object getBean(String name) {
return context.getBean(name);
}
}
隨後在任意處(包括非 Spring 管理的工具類)調用 SpringContextHolder.getBean(MyService.class)。注意: 僅在容器完全啟動後可用,構造器/字段注入階段不可用。
在 Spring 管理的 Bean 中直接注入容器引用,類型安全、IDE 友好。
ApplicationObjectSupport:提供 getApplicationContext()WebApplicationObjectSupport:提供 getWebApplicationContext()早期 Spring MVC Controller、HibernateDAOSupport 等均繼承此類。新項目不建議使用,耦合度高、難測試。
| 方式 | 適用場景 | 耦合度 | 推薦指數 |
|---|---|---|---|
| 手動構建 | main、批處理、測試 | 低 | ⭐⭐⭐(特定場景) |
| WebApplicationContextUtils | Filter、Listener、非 Spring Bean | 中 | ⭐⭐ |
| ApplicationContextAware | 工具類、靜態方法、跨層調用 | 低(靜態持有) | ⭐⭐⭐⭐ |
| @Autowired 注入 | Service、Component、Controller 內部 | 零(框架原生) | ⭐⭐⭐⭐⭐ |
| 繼承基類 | 舊項目維護 | 高 | ⭐ |
ApplicationContextAware + 靜態字段模式,並提供 clear() 方法供測試清理。getBean(),改為啟動時緩存 Bean 引用。spring.main.allow-bean-definition-overriding=false 防止 Bean 覆蓋導致運行時不一致。核心原則: 「依賴查找」應作為「依賴注入」的補充,而非替代。90% 以上場景下,直接
@Autowired目標 Bean 而非容器本身。