日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

springboot---成员初始化顺序

發布時間:2023/12/10 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springboot---成员初始化顺序 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

如果我們的類有如下成員變量:

@Component public class A {@Autowiredpublic B b; // B is a beanpublic static C c; // C is also a beanpublic static int count;public float version;public A() {System.out.println("This is A constructor.");}@Autowiredpublic A(C c) {A.c = c;System.out.println("This is A constructor with c argument.");}@PostConstructpublic void init() {count = 5;System.out.println("This is A post construct.");} }

下面的結論可以通過在構造函數里打斷點Debug來觀察。

首先初始化的是static成員變量, 此處的count采用默認值0。
然后初始化的是非static成員變量,此處的version采用默認值0.0。
然后Spring在實例化A時選擇的構造函數的原則是:如果有構造函數被@Autowired所修飾,則采用該構造函數(注意,@Autowired(required = true)只能修飾一個構造函數),否則采用默認的無參構造函數。此處采用的構造函數為

@Autowired public A(C c) {this.c = c;System.out.println("This is A constructor with c argument."); }

注意執行完該構造函數后,此時的成員變量B并沒有被注入,值還是null。

Spring容器選擇合適的Bean注入b。
執行被@PostConstruct修飾的init()函數。

總之,在上面這個例子中,各成員變量的執行順序為:“static 成員變量 ”–> “非static成員變量” --> “被@Autowired修飾的構造函數” --> “被@Autowired修飾的成員變量b” --> “被@PostConstruct修飾的init()函數”。
有時我們想要對靜態成員進行依賴注入(通常是Field dependency injection,即直接在成員上加@Autowired,此種做法不推薦),直接在靜態成員上加@Autowired是無效的(其值總為null),這是因為靜態成員變量是類的屬性,不屬于任何對象,而Spring實現Field dependency injection 是要依靠基于實例的reflection(反射)進行的。在這個例子中,Spring通過反射生成bean a, 并且發現a使用了bean b(此時bean b已經生成并被注冊到Spring容器中),再次利用反射生成setter方法并將b set進a,這樣就實現了Field dependency injection。通過上述過程我們可以知道static成員由于不屬于任何實例,所以無法實現這樣的依賴注入,但是我們可以通過Constructor dependency injection(構造函數依賴注入)來實現。以上面的例子為例,Spring在生成bean a(調用A的構造函數)時,由于A的構造函數帶有參數c,Spring將在容器里尋找是否有符合c類型的bean,找到后將bean c賦值給構造函數的參數c,然后當執行到A.c = c時成員變量c就被“注入”成功了。

如果我們希望某個Bean不要在Spring容器啟動時初始化(這樣可以加快應用的啟動速度),而是在用到時才實例化,可以用@Lazy這個注解。將這個注解加在@Bean、@Component、@Service、@Configuration等注解上時,這些注解所修飾的Bean將在第一次引用時才實例化;如果在@Autowired上也同時加上這個注解,則該Bean將在第一次使用時實例化。我們再舉個簡單的例子:
在@Component等注解上加@Lazy

@Lazy @Component public class LazyBean {public LazyBean() {System.out.println("This is LazyBean constructor.");} }

在UseBean里通過@Autowired注入LazyBean,不加@Lazy:

@Component public class UseBean {@Autowiredprivate LazyBean lazyBean;public UseBean () {} }

當應用啟動時,Spring要去掃描這些被@Component等注解修飾的類,立即將他們實例化并注冊到容器中,但是由于LazyBean 類被@Lazy修飾,Spring會跳過這個Bean的實例化。當生成UseBean后(即Spring完成對UseBean的構造函數的調用后),由于UseBean引用了LazyBean,這個時候Spring才將LazyBean實例化。因此,以上Bean的初始化順序永遠是先初始化UseBean,當執行到@Autowired private LazyBean lazyBean;時才實例化lazyBean。

在@Component等注解和@Autowired上都加@Lazy

@Getter@Componentpublic class UseBean {@Lazy@Autowiredprivate LazyBean lazyBean;public UseBean () {}@PostConstructpublic void init() {System.out.println(this.getLazyBean());}}

這種情況下即使執行到@Autowired private LazyBean lazyBean;時也沒有真正實例化LazyBean ,只有在真正使用lazyBean時,即上述代碼中的this.getLazyBean()時才開始調用LazyBean 的構造函數來實例化。

總結

以上是生活随笔為你收集整理的springboot---成员初始化顺序的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。