拼多多一面:Spring @Lazy 可以解決循環(huán)依賴嗎?
在實(shí)際工作中,@Lazy注解的主要用途是什么?它是如何工作的?@Lazy可以解決循環(huán)依賴嗎?我們?cè)撊绾问褂盟??這篇文章,我們來(lái)聊一聊。
1. 主要作用
首先,讓我們看看@Lazy注解的源碼,截圖如下:
通過(guò)源碼,我們可以看到:@Lazy注解是一個(gè)標(biāo)記注解,用于標(biāo)記 bean會(huì)被延遲初始化。@Lazy注解可以用于類,方法,構(gòu)造器,參數(shù),字段上。
從整體上看,@Lazy注解的作用主要有下面三點(diǎn):
(1) 延遲初始化Bean
- 默認(rèn)情況下,Spring容器在啟動(dòng)時(shí)會(huì)立即創(chuàng)建和初始化所有單例(singleton)Bean,這稱為預(yù)加載(eager initialization)。
- 使用@Lazy注解可以將Bean的初始化延遲到第一次使用時(shí)才進(jìn)行,即懶加載(lazy initialization)。
(2) 優(yōu)化資源使用和啟動(dòng)時(shí)間
- 對(duì)于一些在應(yīng)用啟動(dòng)時(shí)不一定會(huì)使用的Bean,延遲初始化可以減少啟動(dòng)時(shí)間,提高應(yīng)用的響應(yīng)速度。
- 減少不必要的資源消耗,尤其是在資源密集型的應(yīng)用中尤為重要。
(3) 解決循環(huán)依賴問(wèn)題
在某些情況下,Bean之間存在循環(huán)依賴,提前初始化可能導(dǎo)致問(wèn)題。使用@Lazy可以打破這種循環(huán)依賴。
2. 工作原理
在分析完@Lazy注解的主要作用后,接下來(lái)我們來(lái)看看@Lazy注解的工作原理,這里歸納為下面三點(diǎn):
(1) 代理機(jī)制
- Spring通過(guò)創(chuàng)建代理對(duì)象來(lái)實(shí)現(xiàn)Bean的延遲初始化。當(dāng)一個(gè)懶加載Bean被引用時(shí),Spring并不會(huì)立即創(chuàng)建其實(shí)例,而是創(chuàng)建一個(gè)代理對(duì)象。
- 當(dāng)對(duì)代理對(duì)象的方法進(jìn)行實(shí)際調(diào)用時(shí),代理會(huì)觸發(fā)Bean的真實(shí)創(chuàng)建和初始化。
(2) 延遲加載的實(shí)現(xiàn)步驟
- 容器啟動(dòng)時(shí):Spring掃描到帶有@Lazy注解的Bean,不會(huì)立即實(shí)例化,而是生成一個(gè)代理對(duì)象并注冊(cè)到容器中。
- 第一次訪問(wèn)時(shí):當(dāng)應(yīng)用代碼首次引用該Bean時(shí),代理對(duì)象會(huì)觸發(fā)實(shí)際Bean的創(chuàng)建和依賴注入過(guò)程。
(3) 與@Scope搭配使用
@Lazy通常與@Scope("singleton")或@Scope("prototype")搭配使用,以控制單例或原型Bean的懶加載行為。
3. 使用方法
根據(jù)上面我們分析@Lazy注解源碼時(shí),我們知道@Lazy注解可以用于類,方法,構(gòu)造器,參數(shù),字段上,因此,我們將分別舉例來(lái)說(shuō)明它們是如何使用的。
(1) 在Bean定義上使用@Lazy
@Component
@Lazy
public class LazyBean {
// Bean內(nèi)容
}
(2) 在配置類中使用@Lazy注解
@Configuration
public class AppConfig {
@Bean
@Lazy
public LazyBean lazyBean() {
return new LazyBean();
}
}
(3) 在依賴注入點(diǎn)使用@Lazy
對(duì)特定的依賴進(jìn)行懶加載,而不是整個(gè)Bean。
@Component
public class AnotherBean {
private final LazyBean lazyBean;
public AnotherBean(@Lazy LazyBean lazyBean) {
this.lazyBean = lazyBean;
}
}
4. 注意事項(xiàng)
在日常工作中,我們使用@Lazy 注解,需要注意以下事項(xiàng):
- 代理開(kāi)銷:使用@Lazy會(huì)引入代理對(duì)象,可能會(huì)帶來(lái)一定的性能開(kāi)銷,尤其是在高頻調(diào)用的場(chǎng)景下需要權(quán)衡利弊。
- 配置復(fù)雜性:過(guò)度使用懶加載可能導(dǎo)致配置復(fù)雜,難以跟蹤Bean的初始化時(shí)機(jī),影響調(diào)試和維護(hù)。
- 測(cè)試與調(diào)試:在測(cè)試和調(diào)試時(shí),延遲初始化可能會(huì)導(dǎo)致某些Bean未按預(yù)期初始化,需要注意測(cè)試環(huán)境的配置。
5. 總結(jié)
本文,我們分析了 @Lazy注解的工作原理,主要用途以及如何使用它。@Lazy是 Spring提供的一個(gè)強(qiáng)大工具,用于控制 Bean的初始化時(shí)機(jī),幫助開(kāi)發(fā)者優(yōu)化應(yīng)用的性能和資源使用。
回到文章的標(biāo)題:@Lazy注解能解決循環(huán)依賴嗎?
答案:可以解決基于構(gòu)造器注入產(chǎn)生的循環(huán)依賴。詳情可以參考我往期的文章:Spring循環(huán)依賴,一個(gè)注解搞定!