Spring中構造器、init-method、@PostConstruct、afterPropertiesSet孰先孰後,自動註入發生時間以及單例多例的區別
首先明白,spring的IOC功能需要是利用反射原理,反射獲取類的無參構造方法創建對象,如果一個類沒有無參的構造方法spring是不會創建對象的。在這裏需要提醒一下,如果我們在class中沒有顯示的聲明構造方法,默認會生成一個無參構造方法,但是當我們顯示的聲明一個有參構造方法的時候,JVM不會幫我們生成無參構造方法,所以我們聲明一個帶參數的構造方法也需要聲明一個無參構造方法。(題外話:如果父類聲明一個有參構造方法,子類需要在構造方法第一行顯示的調用父類構造方法,因為子類的對象也是父類的對象,所以在創建子類對象的同時也會創建父類的對象,如果父類有默認的無參構造函數,JVM會調用無參構造函數,但是有了有參的就需要我們在子類的構造函數中調用父類的有參構造函數)
1.Person類只有一個有參構造方法,報錯如下:
No default constructor found; nested exception is java.lang.NoSuchMethodException: zd.dms.job.ebuy.Person.<init>()
2.大體知道有三種生命周期回調方法去參與到spring的生命周期,查閱了一下如下:(創建和銷毀的執行順序也是下面順序)
- 在指定方法上加上@PostConstruct 或@PreDestroy註解來制定該方法是在初始化之後還是銷毀之前調用。
- 通過實現 InitializingBean/DisposableBean 接口來定制初始化之後/銷毀之前的操作方法;
- 通過 <bean> 元素的 init-method/destroy-method屬性指定初始化之後 /銷毀之前調用的操作方法;
3.測試spring的順序與註入的順序與單例多例的問題
1.Person.java
package zd.dms.job.ebuy; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean;import org.springframework.beans.factory.annotation.Autowired; import zd.dms.dao.ebuy.GroupDao; public class Person implements InitializingBean,DisposableBean{ private String name; @Autowired private GroupDao groupDao; public Person() { System.out.println("---------------實例化一個Person對象----------"); System.out.println("---------------groupDao is -----------"+groupDao); } public void init() { System.out.println("------------這是xml的init方法----------...."); System.out.println("---------------groupDao is -----------"+groupDao); } public void destory() { System.out.println("---------------這是xml的destroy方法...."); System.out.println("---------------groupDao is -----------"+groupDao); } @PostConstruct public void init2() { System.out.println("------------這是@PostConstruct的init方法----------...."); System.out.println("---------------groupDao is -----------"+groupDao); } @PreDestroy public void destory2() { System.out.println("---------------這是@PreDestroy的destroy方法...."); System.out.println("---------------groupDao is -----------"+groupDao); } @Override public void destroy() throws Exception { System.out.println("-----------這是DisposableBean的destroy方法...."); System.out.println("---------------groupDao is -----------"+groupDao); } @Override public void afterPropertiesSet() throws Exception { System.out.println("-------這是InitializingBean的afterPropertiesSet方法...."); System.out.println("---------------groupDao is -----------"+groupDao); } }
-----------------------單例模式的xml配置以及結果---------------------------------------:
配置:
<bean id="person" class="zd.dms.job.ebuy.Person" autowire="byType" destroy-method="destory" init-method="init"></bean>
測試:將Person類註入到Action我們訪問Action
@Namespace("/qlqTest") @SuppressWarnings("all") public class TestAction extends DMSActionSupport{ /** * */ private static final long serialVersionUID = -8934360924125349297L; @Autowired private GroupAndUserService groupAndUserService; @Autowired private Person person;
當我們第一次調用該實例方法的時候會創建對象,打印結果如下:
- ---------------實例化一個Person對象---------- ---------------groupDao is -----------null ------------這是@PostConstruct的init方法----------.... ---------------groupDao is -----------zd.dms.dao.ebuy.GroupDaoImpl@435598e3 -------這是InitializingBean的afterPropertiesSet方法.... ---------------groupDao is -----------zd.dms.dao.ebuy.GroupDaoImpl@435598e3 ------------這是xml的init方法----------.... ---------------groupDao is -----------zd.dms.dao.ebuy.GroupDaoImpl@435598e3
證明對象創建的順序:
構造器-->自動註入-->@PostConstrut-->InitializingBean-->xml中配置init方法
再次調用不會打印,證明默認是單例的 singleton,也就是無論我們訪問多少次Action,Spring容器中只有一個這個對象。
銷毀的時候的結果:
---------------這是@PreDestroy的destroy方法.... ---------------groupDao is -----------zd.dms.dao.ebuy.GroupDaoImpl@435598e3 -----------這是DisposableBean的destroy方法.... ---------------groupDao is -----------zd.dms.dao.ebuy.GroupDaoImpl@435598e3 ---------------這是xml的destroy方法.... ---------------groupDao is -----------zd.dms.dao.ebuy.GroupDaoImpl@435598e3
所以銷毀順序為:
@PreDestroy--DisposableBean-->xml中destroy-method方法
-----------------------多模式的xml配置以及結果---------------------------------------:
配置:
<bean id="person" class="zd.dms.job.ebuy.Person" autowire="byType" destroy-method="destory" init-method="init" scope="prototype"></bean>
我們多次訪問Action,所以Action會多次調用Person對象,發現會多次創建Person對象,也就是請求一次會創建一個對象,也就是多例:
至於到底是該使用單例還是多例,這就需要我們平時的業務需求了,springMvc就是單例的,struts2默認就是多例的。我們也可以使用註解配置單例和多例,如下:
---------------------為了理解上面的單例多例的例子,繼續測試---------------------
配置如下:
Action是struts默認多例:(註入Person類對象)
Person類模擬是service層,默認是單例(註入GroupDaoImpl對象)
GroupDaoImpl是多例
也就是我們上面的配置從Action到service到dao的作用域是多-單-多,我們多次訪問Action,結果如下:
解釋:
我們每次訪問action是多例所以每次會創建對象,而Person默認是單例,所以spring只會維護一個對象,即使GroupDaoImpl是多例模式,但是其已經註入到Person類中,而person不會創建新的對象,所以GroupDaoImpl也只會生成一個對象。只有在生成Person類的時候才會重新生成GroupDaoImpl且重新維護關系。所以上面在spring中出現對各TestAction,一個Person和一個GroupDaoImpl。
Spring中構造器、init-method、@PostConstruct、afterPropertiesSet孰先孰後,自動註入發生時間以及單例多例的區別