在 Spring 框架開發中,大多數情況下我們通過依賴注入(DI)自動裝配 Bean。但在某些非 Spring 管理的類(如工具類、靜態方法、第三方庫回調)中,需要主動從容器獲取 Bean。本文系統總結 5 種主流獲取方式,並針對適用場景、優缺點及注意事項進行深度解析。
適用於獨立 Java 應用、單元測試或批處理程序,需手動加載配置文件啟動容器。
ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml");
MyBean bean = ac.getBean("beanId", MyBean.class);
利用 ServletContext 獲取 Web 環境下的 WebApplicationContext,是 Web 應用中最常用的非注入獲取方式。
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.context.WebApplicationContext;
import javax.servlet.ServletContext;
// 方式 1:必須存在,否則拋出異常
WebApplicationContext wac1 = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
// 方式 2:允許不存在,返回 null
WebApplicationContext wac2 = WebApplicationContextUtils.getWebApplicationContext(servletContext);
MyBean bean = wac1.getBean(MyBean.class);
ServletContext 的組件。getRequiredWebApplicationContext 找不到時拋 IllegalStateException;getWebApplicationContext 返回 null。Spring 提供的便利基類,通過模板方法模式注入 ApplicationContext。
public class MyService extends ApplicationObjectSupport {
public void doSomething() {
ApplicationContext ctx = getApplicationContext(); // 父類提供
MyBean bean = ctx.getBean(MyBean.class);
}
}
setApplicationContext 完成注入。<bean class="..."/>),否則 getApplicationContext() 返回 null。Web 環境專用基類,提供 getWebApplicationContext() 直接獲取 WebApplicationContext,功能同上但針對 Web 場景優化。
實現該接口並重寫 setApplicationContext,Spring 容器啟動時自動回調注入。配合單例模式封裝為工具類,使用極其便捷。
package com.example.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component // 自動掃描註冊為 Bean
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
applicationContext = ctx;
}
public static <T> T getBean(Class<T> clazz) {
checkContext();
return applicationContext.getBean(clazz);
}
public static Object getBean(String name) {
checkContext();
return applicationContext.getBean(name);
}
private static void checkContext() {
if (applicationContext == null) {
throw new IllegalStateException("ApplicationContext 未注入,請確認 SpringContextHolder 已被 Spring 管理!");
}
}
}
<!-- XML 方式 -->
<bean id="springContextHolder" class="com.example.util.SpringContextHolder"/>
<!-- 或掃描註解 @Component -->
MyService service = SpringContextHolder.getBean(MyService.class);
// 或
MyService service = (MyService) SpringContextHolder.getBean("myService");
null。ContextLoaderListener 初始化完成前(如構造器、@PostConstruct 早期),ContextLoader.getCurrentWebApplicationContext() 返回 null。volatile 或雙重檢查鎖(單例模式已隱含)。@Autowired/構造器注入時,絕不手動獲取,保持 IoC 原則。| 方法 | 適用環境 | 前置條件 | 推薦指數 |
|---|---|---|---|
| 手動初始化 | 獨立應用/測試 | 無 | ⭐ |
| WebApplicationContextUtils | Web 組件 | 持有 ServletContext | ⭐⭐⭐⭐ |
| ApplicationObjectSupport | 通用 Bean | 類被 Spring 管理 | ⭐⭐ |
| WebApplicationObjectSupport | Web Bean | 類被 Spring 管理 | ⭐⭐ |
| ApplicationContextAware + 工具類 | 全局任意處 | 工具類被 Spring 管理 | ⭐⭐⭐⭐⭐ |
掌握這 5 種方式,核心在於理解 Spring 容器生命周期與回調機制。實際開發中,**首選依賴注入**;不得已時,推薦「實現 ApplicationContextAware 封裝工具類」,一次配置,全局可用,且代碼乾淨解耦。