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)只能修飾一個構造函數),否則采用默認的無參構造函數。此處采用的構造函數為
注意執行完該構造函數后,此時的成員變量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
在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---成员初始化顺序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 项目建议书模板doc_重要!非洲猪瘟等动
- 下一篇: python cookies过期_Pyt