Spring的實例化
使用@Autowired可以注入一個bean進來
@Autowired
private Diana diana;
那麼如果在容器中沒有Diana
的對象被實例化的時候應用程序會報錯嗎?我們可以通過把Diana
上面的@Component註釋掉來看一下結果如何
//@Component
public class Diana {
public void r(){
System.out.println("Diana R");
}
}
@RestController
@RequestMapping("/v1/banner")
public class BannerController {
@Autowired
private Diana diana;
}
啓動SpringBoot會出現以下結果:
由此可見,如果spring無法在容器中找到Diana
的對象,在默認的機制下啓動時就會直接報錯。
當在@Autowired後面加上 (required = false),變成
@RestController
@RequestMapping("/v1/banner")
public class BannerController {
@Autowired(required = false)
private Diana diana;
@GetMapping("/test")
public String test1() {
diana.r();
return "Hello test1";
}
}
SpringBoot可以 正常啓動,但是當訪問diana下面的方法時會出現下面這樣的結果
出現這樣的情況注入是沒有問題的,而是由於容器中沒有diana這個對象卻又調用diana下面的方法
結論:
_如果spring無法在容器中找到Diana的對象,在默認的機制下啓動時就會直接報錯。我們可以通過@Autowired(required = false)的方式令應用程序可以正常啓動。 _
依賴注入時機
IOC容器究竟是在什麼時候實例化對象並把對象注入到代碼片段裏的呢?是當請求訪問Controller的時候才進行實例化並注入,還是在SpringBoot應用啓動時就開始實例化並把對象注入到代碼片段的呢?
由之前的代碼可以看出,當把Diana上面的@Component註釋掉時,SpringBoot應用啓動時應用程序會立即報錯,我們也可以通過在Diana這個類中加一個無參的構造方法來驗證以下
@Component
public class Diana {
public Diana() {
System.out.println("Hello Diana");
}
public void r(){
System.out.println("Diana R");
}
}
應用程序啓動時控制檯打印出了"Hello Diana"
結論:
默認機制下,在SpringBoot應用啓動時,IOC容器就開始實例化對象並把對象注入到代碼片段裏
延遲實例化
SpringBoot默認是立即實例化的機制,我們可以通過 @Lazy讓它變成延遲實例化。
@Component
@Lazy
public class Diana {
當只在Diana上加上 @Lazy,啓動應用卻發現Diana仍然是立即實例化,@Lazy並沒有起作用。這是因爲BannerController是立即實例化的,那它下面的屬性如果是@Autowired的就也需要立即實例化,只加在Diana上的 @Lazy是會被忽略掉的。如果真的需要延遲實例化就需要在BannerController也加上@Lazy或者是BannerController注入Diana的地方加上@Lazy,示例代碼如下:
@RestController
@RequestMapping("/v1/banner")
@Lazy
public class BannerController {
或者
@Autowired
@Lazy
private Diana diana;
當訪問當前的Controller控制檯打印出了下面的結果:
由此可見,此時是當請求訪問Controller的時候才進行實例化並注入
如果沒有特殊理由最好不要開啓延遲實例化。使用默認機制提前實例化纔是一個比較好的做法,因爲可以儘早發現問題,避免很多問題在運行時才被發現。