在Spring項目中,有時須要新開線程完成一些複雜任務,而線程中可能須要注入一些服務。而經過Spring注入來管理和使用服務是較爲合理的方式。可是若直接在Thread子類中經過註解方式注入Bean是無效的。java
由於Spring自己默認Bean爲單例模式構建,同時是非線程安全的,所以禁止了在Thread子類中的注入行爲,所以在Thread中直接注入的bean是null的,會發生空指針錯誤。安全
如下分別列舉錯誤的注入方法和兩種解決方式。app
@Controller public class SomeController{ @ResponseBody @RequestMapping("test") String testInjection(){ // 直接建立並運行線程 new SomeThread().start(); } } // 直接編寫線程 public SomeThread extends Thread { @Autowired SomeService someService; @Override public void run(){ // do something... someService.doSomething(); // 此時 someService實例是null. } }
報NullpointException。ide
我的比較推薦這種方法,對外部代碼的影響較小。函數
@Controller public class SomeController{ // 經過註解注入封裝線程的Bean @AutoWired SomeThread someThread; @ResponseBody @RequestMapping("test") String testInjection(){ // 經過注入的Bean啓動線程 someThread.execute(); } } @Component public class SomeThread { // 封裝Bean中注入服務 @AutoWired SomeService someService public void execute() { new Worker().start(); } // 線程內部類,Thread或者Runnable都可 private class Worker extends Thread { @Override public void run() { // do something... SomeThread.this.someService.doSomething(); // 此時someService已被注入,非null. } } }
正常調用someService。this
即在能夠注入的地方先獲得可用的實例,在經過Thread子類的構造函數引入。這樣會使得在進行代碼修改時,影響到每一個使用Thread子類的代碼,修改工做量大。spa
@Controller public class SomeController{ // 經過註解注入Service @AutoWired SomeService someService; @ResponseBody @RequestMapping("test") String testInjection(){ // 經過構造函數從外部引入 new Worker(someService).start(); } } public class SomeThread { private SomeService someService; public SomeThread(SomeService someService){ // 經過構造函數從外部引入 this.someService = someService; } @Override public void run() { // do something... someService.doSomething(); // 此時someService非null. } }