現象:Web 應用啟動正常,但自定義線程中 @Resource 或 XML 注入的 Service 均為 null,拋 NPE。
Spring 容器啟動時掃描主線程管理的 Bean,子線程由開發者手動 new Thread() 創建,不在容器管理範圍內,故無法自動注入。
public class MyTask implements Runnable {
private final UserService userService;
public MyTask(UserService userService) { this.userService = userService; }
@Override public void run() { userService.doSomething(); }
}
// 主線程(受容器管理)
@Service
public class TaskStarter {
@Resource UserService userService;
public void start() {
new Thread(new MyTask(userService)).start(); // 直接傳引用
}
}
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext ctx;
@Override public void setApplicationContext(ApplicationContext c) { ctx = c; }
public static T getBean(String name) { return (T) ctx.getBean(name); }
public static T getBean(Class clazz) { return ctx.getBean(clazz); }
}
// 線程中調用
public void run() {
UserService svc = SpringContextUtil.getBean(UserService.class);
svc.doSomething();
}
需在 XML 或掃描路徑註冊 SpringContextUtil Bean。
public class MyThread extends Thread {
@Resource UserService userService; // 需在 Spring 管理的類中才生效
@Override public void run() { userService.doSomething(); }
}
// 必須讓 Spring 管理 MyThread 實例(如 @Component + @Scope("prototype"))
每次調用創建新實例,破壞單例、事務管理、AOP 切面,資源浪費。
SpringContextUtil 適合舊代碼改造或無法傳遞引用場景。new 業務邏輯類。