問題原因
關(guān)于這個(gè)問題烈菌,其實(shí)答案相對(duì)統(tǒng)一阵幸,實(shí)際上用大白話說起來也容易理解。
1.初始化問題
先看一下Java初始化類的順序:
父類的靜態(tài)字段 > 父類靜態(tài)代碼塊 > 子類靜態(tài)字段 > 子類靜態(tài)代碼塊 > 父類成員變量 > 父類構(gòu)造代碼塊 > 父類構(gòu)造器 > 子類成員變量 > 子類構(gòu)造代碼塊 > 子類構(gòu)造器
而Autowired注入芽世,則要排隊(duì)到子類構(gòu)造器以后了挚赊,SpringIOC并不會(huì)對(duì)依賴的bean是否為null做判斷,JVM編譯時(shí)同樣也不會(huì)有問題济瓢,但如果使用不當(dāng)荠割,運(yùn)行起來時(shí)或許會(huì)因?yàn)槌霈F(xiàn)空指針異常。
2.對(duì)IOC容易依賴過強(qiáng)
@Autowired
由Spring提供,而@Resource
是JSR-250提供的蔑鹦,它是Java標(biāo)準(zhǔn)夺克。前者會(huì)警告,而后者不警告嚎朽,就是因?yàn)榍罢邔?dǎo)致了應(yīng)用與框架的強(qiáng)綁定铺纽,若是換成其他IOC框架,則不能夠成功注入了哟忍。其實(shí)對(duì)于這方面狡门,我認(rèn)為在大多數(shù)情況時(shí)是不會(huì)有什么問題的。
3.其他方面
我看到網(wǎng)絡(luò)上有一些其他方面的總結(jié)锅很,比如:依賴過多卻不夠明顯其馏,違反了單一職責(zé)原則;不能像構(gòu)造器那樣注入不可變的對(duì)象等爆安,這類問題需要結(jié)合個(gè)人實(shí)際開發(fā)進(jìn)行判斷叛复。
對(duì)于@Autowired
使用方面,它雖然是將業(yè)務(wù)代碼和框架進(jìn)行了強(qiáng)綁定扔仓,但字段注入確實(shí)大幅簡(jiǎn)化了代碼褐奥。追求完完全全的松耦合其實(shí)也過于理想化,應(yīng)該在實(shí)際使用中追求平衡当辐,否則將為了過度追求松耦合而得不償失抖僵。
其他使用方式
除了使用@Autowired
以外,我們其實(shí)也有幾種好用的方式缘揪。使用@Resource
替代@Autowired
方法是其中一種,只需要改變一個(gè)注解义桂,這里就不展示了找筝。
1.set方法
@RestController
public class TestController2 {
ITestService testService;
/*
* 基于set注入
* */
@Autowired
public void setTestService(ITestService iTestService) {
this.testService = iTestService;
}
@GetMapping("/status2")
public Result<?> status() {
return testService.status();
}
}
這種方法也使用了@Autowired
注解,但是它是作用于成員變量的Setter函數(shù)上慷吊,而不是像Fied注入一樣作用于成員變量上袖裕。
2.構(gòu)造器
@RestController
public class TestController1 {
ITestService testService;
/*
* 基于構(gòu)造方法的注入
* */
public TestController1(ITestService iTestService) {
this.testService = iTestService;
}
@GetMapping("/status1")
public Result<?> status() {
return testService.status();
}
}
它的好處在于,采用了構(gòu)造方法注入溉瓶,這種方式對(duì)對(duì)象創(chuàng)建的順序會(huì)有要求急鳄,它將避免循環(huán)依賴問題。是最可靠的方法堰酿。
3.構(gòu)造器的簡(jiǎn)化版(推薦)
首先疾宏,需要引入lombok依賴。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
</dependency>
隨后触创,我們?cè)趧?chuàng)建時(shí)就可以使用@RequiredArgsConstructor
注解坎藐,它將幫我們創(chuàng)建構(gòu)造器,final關(guān)鍵字必不可少。
@RestController
@RequiredArgsConstructor
public class TestController3 {
/*
* 用@RequiredArgsConstructor注解岩馍,這個(gè)使用方式也可以應(yīng)用于service層
* */
private final ITestService testService;
@GetMapping("/status3")
public Result<?> status() {
return testService.status();
}
}
我們?cè)谑褂眠@些創(chuàng)建方法時(shí)碉咆,都可以調(diào)出IDEA的結(jié)構(gòu)(Structure)面板進(jìn)行查看,如下圖所示蛀恩。
可以看到疫铜,在這個(gè)類中,已經(jīng)存在我們所需要注入的內(nèi)容双谆。
在網(wǎng)上有博主總結(jié)了一張表壳咕,但因?yàn)榈教幠芸吹剑恢瓉沓鎏幨悄睦铩?/p>
總結(jié)
在使用中佃乘,使用構(gòu)造方法是比較可行的囱井,加上lombok,其實(shí)也可以到達(dá)非常簡(jiǎn)便趣避。