若是咱們的類有以下成員變量:html
@Component public class A { @Autowired public B b; // B is a bean public static C c; // C is also a bean public static int count; public float version; public A() { System.out.println("This is A constructor."); } @Autowired public A(C c) { A.c = c; System.out.println("This is A constructor with c argument."); } @PostConstruct public void init() { count = 5; System.out.println("This is A post construct."); } }
下面的結論能夠經過在構造函數裏打斷點Debug來觀察。java
count
採用默認值0。version
採用默認值0.0。而後Spring在實例化A時選擇的構造函數的原則是:若是有構造函數被@Autowired
所修飾,則採用該構造函數(注意,@Autowired(required = true)
只能修飾一個構造函數),不然採用默認的無參構造函數。此處採用的構造函數爲spring
@Autowired public A(C c) { this.c = c; System.out.println("This is A constructor with c argument."); }
注意執行完該構造函數後,此時的成員變量B並無被注入,值仍是null。api
@PostConstruct
修飾的init()
函數。總之,在上面這個例子中,各成員變量的執行順序爲:「static 成員變量 」--> 「非static成員變量」 --> 「被@Autowired
修飾的構造函數」 --> 「被@Autowired
修飾的成員變量b」 --> 「被@PostConstruct
修飾的init()
函數」。函數
@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、@Component、@Service、@Configuration
等註解上時,這些註解所修飾的Bean將在第一次引用時才實例化;若是在@Autowired
上也同時加上這個註解,則該Bean將在第一次使用時實例化。咱們再舉個簡單的例子:在 @Component
等註解上加@Lazy
post
@Lazy @Component public class LazyBean { public LazyBean() { System.out.println("This is LazyBean constructor."); } }
* 在UseBean裏經過```@Autowired```注入LazyBean,不加```@Lazy```: ```java @Component public class UseBean { @Autowired private 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``` ```java @Getter @Component public class UseBean { @Lazy @Autowired private LazyBean lazyBean; public UseBean () {} @PostConstruct public void init() { System.out.println(this.getLazyBean()); } } ``` 這種狀況下即便執行到```@Autowired private LazyBean lazyBean;```時也沒有真正實例化LazyBean ,只有在真正使用lazyBean時,即上述代碼中的```this.getLazyBean()```時纔開始調用LazyBean 的構造函數來實例化。