@Autowired註解在抽象類中失效的原因及解決
@Autowired註解在抽象類中失效
最近在工作中遇到這個問題,在抽象類中使用Autowired這個註解,註入mybatis的dao時,總是出現空指針異常,通過日志的打印,發現是這個dao註入失敗為空。然後通過new出spring上下文對象,再去調用getBean()方法,獲取到這個註入的dao,這樣是可行的,但是總是覺得這不是最佳實踐,一定有比這個更加優雅的方式能解決這個問題。
我們來還原一下這個問題:
1.定義一個抽象類
聲明為spring組件,在其中自動裝配另一個bean:
@Component public abstract class BaseService { @Autowired Dao dao; }
2.然後在他的子類中使用這個自動裝配的對象
@Component public class myService extends BaseService{ public void print(){ //運行時為null System.out.print(dao.toString()); } }
在我們實例化子類對象的時候,抽象父類不能實例化,因為spring註入的是實例對象,而不是類,所以spring不會將dao自動裝配註入到一個實例中。但是我們通過在在抽象類中獲取的上下文對象中卻可以拿到dao,因為這個上下文對象
是我們自己手動new出來的,不是spring通過反射註入到對象中去的。因此這種方案是可行的。
下面介紹一種更優雅的解決方案:
1.同樣是定義一個抽象類
public class BaseService { Dao dao; }
2.在子類中使用註解
@Component public class myService extends BaseService{ //Autowired修飾方法時,根據方法參數類型判斷實例化哪個類 @Autowired public void printDao(Dao dao){ super.dao = dao;//父類屬性註入 } public void print(){ System.out.print(dao.toString()); } }
這樣寫是不是要比我們直接去new applicationContext更加優雅呢?
在抽象類中使用@Autowired
1.簡介
在本快速教程中,我們將說明如何在抽象類中使用 @Autowired 自動裝配註解。
我們將 @Autowired 應用於 abstract 抽象類,並關註此時要考慮的重點。
2.Setter 方式註入
我們可以在設置方法上使用_@Autowired_:
public abstract class BallService { private LogRepository logRepository; @Autowired public final void setLogRepository(LogRepository logRepository) { this.logRepository = logRepository; } }
當我們使用_@Autowired_上setter方法,我們應該用final 關鍵字,這樣子類便不能覆蓋setter方法。否則,註解將無法正常運行。
3.構造函數註入
我們不能在抽象類的構造函數上使用_@Autowired_。
Spring 不會在抽象類的構造函數上解析 @Autowired 註解。子類應為 super 構造函數提供必要的參數。
相反,我們應該在子類的構造函數上使用_@Autowired_:
public abstract class BallService { private RuleRepository ruleRepository; public BallService(RuleRepository ruleRepository) { this.ruleRepository = ruleRepository; } } @Component public class BasketballService extends BallService { @Autowired public BasketballService(RuleRepository ruleRepository) { super(ruleRepository); } }
4.備忘單
讓我們總結一些要記住的規則。
首先,抽象類不會進行組件掃描,因為沒有具體的子類就無法實例化。
其次,在抽象類中可以進行setter註入,但是如果不對setter方法使用_final_關鍵字,因而存在一定誤用的風險。如果子類覆蓋 setter 方法,則應用程序可能不能正常運行。
第三,由於 Spring 在抽象類中不支持構造函數註入,因此通常應該讓具體的子類提供構造函數參數。這意味著我們需要在具體子類中依賴構造函數註入。
最後,將構造函數註入用於必需的依賴項,並將setter註入用於可選的依賴項是一個很好的經驗法則。但是,正如我們可以從抽象類的一些細微差別中看到的那樣,通常在這裡構造函數註入更為有利。
因此,實際上我們可以說具體的子類控制著它的抽象父類如何獲得其依賴項。 Spring 在裝配子類時, 會對其依賴進行註入。
5.結論
在本文中,我們練習瞭在抽象類中使用_@Autowired_,並解釋瞭一些關鍵點。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Spring使用@Autowired註解靜態實例對象方式
- Spring中的註解之@Override和@Autowired
- 聊聊spring繼承的問題
- Spring 父類變量註入失敗的解決
- 詳解Spring 中 Bean 對象的存儲和取出