場景:類 A 通過反射 `Class.forName(...).newInstance()` 建立類 B 實例,類 B 標註 `@Autowired` 注入 Service/DAO,結果注入失敗(字段為 null)。原因:**反射建立的對象不在 Spring 容器管理範圍內,生命週期回調(`@PostConstruct`、`AutowiredAnnotationBeanPostProcessor`)不會觸發**。以下提供三種標準解決方案。
// ❌ 反射直接 newInstance,Spring 完全不知情
Object obj = Class.forName("com.example.ServiceB").newInstance();
// obj 內部 @Autowired 欄位永遠為 null
Spring 只負責管理「容器建立」的 Bean。反射繞過容器,自然無法享受依賴注入。
public class ReflectiveCaller {
@Autowired private ApplicationContext applicationContext; // 注入容器上下文
public void callServiceB() {
try {
Class> clazz = Class.forName("com.example.ServiceB");
Object instance = clazz.getDeclaredConstructor().newInstance();
// ✅ 關鍵:手動觸發依賴注入
AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
factory.autowireBean(instance); // 注入 @Autowired/@Inject/@Resource
factory.initializeBean(instance, "serviceB"); // 觸發 @PostConstruct、InitializingBean
// 現在可以安全調用
Method method = clazz.getMethod("doBusiness");
method.invoke(instance);
} catch (Exception e) {
throw new RuntimeException("反射調用失敗", e);
}
}
}
T getBean(Class clazz) {
return context.getBean(clazz);
}
public static Object getBean(String name) {
return context.getBean(name);
}
}
// 反射邏輯中改為:
Object serviceB = SpringContextHolder.getBean(ServiceB.class); // 直接從容器獲取已注入好的 Bean
// 或
ServiceB serviceB = (ServiceB) Class.forName("...").newInstance();
SpringContextHolder.getAutowireCapableBeanFactory().autowireBean(serviceB);
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // 每次注入/獲取都是新實例
public class ServiceB {
@Autowired private UserDao userDao; // 正常注入
@Autowired private OrderService orderService;
public void doBusiness() { ... }
}
// 使用端:注入 ObjectProvider 或 Provider
@Service
public class ServiceA {
@Autowired private ObjectProvider serviceBProvider; // Spring 4.3+
public void call() {
ServiceB b = serviceBProvider.getObject(); // 容器建立,完整注入
b.doBusiness();
}
}
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 手動 autowireBean | 改動最小、不改變調用結構 | 需持有 ApplicationContext、略顯「破壞框架」 | 舊代碼整合、第三方庫實例化 |
| SpringContextHolder 靜態獲取 | 隨處可用、無需傳遞上下文 | 靜態強耦合、難測試、違反 IoC 原則 | 舊專案大量反射、工具類、定時任務 |
| Prototype Bean + ObjectProvider | 完全受容器管理、支援 AOP、事務、生命週期 | 需重構反射為依賴注入、JavaConfig 配置 | 新代碼、核心業務邏輯、長期維護 |
總結:能重構就重構為 Prototype Bean + ObjectProvider;不得不反射時,用 `AutowireCapableBeanFactory.autowireBean()` 手動注入並初始化,切勿讓 `@Autowired` 字段處於 null 狀態運行業務邏輯。