在非 Spring 管理的類別 (工具類、舊代碼、第三方庫回調) 中需要存取 Spring Bean 時,必須獲取 `ApplicationContext`。本文介紹三種標準方式,**強烈推薦方式一 (實作 Aware 接口)**。
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
SpringContextUtil.applicationContext = context;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
@SuppressWarnings("unchecked")
public static T getBean(String name) {
return (T) applicationContext.getBean(name);
}
public static T getBean(Class clazz) {
return applicationContext.getBean(clazz);
}
public static Map getBeansOfType(Class clazz) {
return applicationContext.getBeansOfType(clazz);
}
}
public class SpringContextHolder {
private static ApplicationContext context;
public static void setContext(ApplicationContext ctx) {
if (context != null) throw new IllegalStateException("已初始化");
context = ctx;
}
public static ApplicationContext getContext() {
if (context == null) throw new IllegalStateException("未初始化,請在啟動類呼叫 setContext()");
return context;
}
// getBean 方法同上...
}
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired private ApplicationContext context;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) {
SpringContextHolder.setContext(context); // 容器就緒後初始化
}
}
// 錯誤示範
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
| 場景 | 推薦方式 | 關鍵點 |
|---|---|---|
| 工具類、靜態方法、非 Spring 代碼需取 Bean | 方式一:實作 ApplicationContextAware | 單例、線程安全、容器自動回調 |
| Spring Bean 內部需取其他 Bean | 方式三:直接 @Autowired ApplicationContext | 簡潔、型別安全 |
| 無組件掃描、手動裝配環境 | 方式二:靜態工具類 + 啟動類初始化 | 需嚴格控制初始化時機 |
| 單元測試 | @SpringBootTest 注入 ApplicationContext | 測試切片自動管理 |
public static T getBean(Class clazz) {
return applicationContext.getBean(clazz);
}
public static T getBean(String name, Class clazz) {
return applicationContext.getBean(name, clazz);
}
使用:`UserService service = SpringContextUtil.getBean(UserService.class);` 避免強轉。
**「實作 `ApplicationContextAware` + 靜態工具類」** 是獲取 Spring 上下文的**黃金標準**。切記:**絕不**在運行時手動 `new ClassPathXmlApplicationContext()`,這會破壞單例語意並導致嚴重資源洩漏與行為錯誤。