首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Spring 多線程環境下注入 Bean 為 Null 解決方案總結

     編輯:Java 綜合教學

Spring 多線程環境下注入 Bean 為 Null 解決方案總結

現象:Web 應用啟動正常,但自定義線程中 @Resource 或 XML 注入的 Service 均為 null,拋 NPE。

原因分析

Spring 容器啟動時掃描主線程管理的 Bean,子線程由開發者手動 new Thread() 創建,不在容器管理範圍內,故無法自動注入。

四種解決方案(推薦度遞減)

方案一:構造器/Setter 手動傳遞(推薦)

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(); // 直接傳引用
    }
}

方案二:實現 ApplicationContextAware 靜態工具類(通用)

@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。

方案三:繼承 SpringBeanAutowiringSupport(舊版 Spring)

public class MyThread extends Thread {
    @Resource UserService userService; // 需在 Spring 管理的類中才生效
    @Override public void run() { userService.doSomething(); }
}
// 必須讓 Spring 管理 MyThread 實例(如 @Component + @Scope("prototype"))

方案四:手動 new ServiceImpl()(強烈不推薦)

每次調用創建新實例,破壞單例、事務管理、AOP 切面,資源浪費。

最佳實踐建議

  1. 優先用「主線程注入 → 構造器傳遞給線程」,清晰可控。
  2. 通用工具類 SpringContextUtil 適合舊代碼改造或無法傳遞引用場景。
  3. 避免在線程中直接 new 業務邏輯類。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved