1. 程式人生 > >在程式中用new ClassPathXmlApplicationContext()獲取Spring的上下文環境注意事項

在程式中用new ClassPathXmlApplicationContext()獲取Spring的上下文環境注意事項

問題背景:在我們的web程式中,用spring來管理各個例項(bean), 有時在程式中為了使用已被例項化的bean, 通常會用到這樣的程式碼:

  1. ApplicationContext appContext =   
  2.           new ClassPathXmlApplicationContext("classpath:META-INF/spring/applicationContext-common.xml");  
  3.     ApplicationContext appContext=appContextUtil.getContext();  
  4.     ProjectServiceFacade projectServiceFacade=(ProjectServiceFacade)appContext.getBean("biz.projectServiceFacade"
    );  

存在的問題:因為它會重新裝載applicationContext-common.xml並例項化上下文bean, 如果有些執行緒配置類也是在這個配置檔案中,那麼會造成做相同工作的的執行緒會被啟兩次。一次是web容器初始化時啟動,另一次是上述程式碼顯示的例項化了一次。這在業務上是要避免的。

自己的理解:

首先,主要意圖就是獲得Spring上下文;
其次,有了Spring上下文,希望通過getBean()方法獲得Spring管理的Bean的物件;
最後,為了方便呼叫,把上下文定義為static變數或者getBean方法定義為static方法;
但是,在web專案中,系統一旦啟動,web伺服器會初始化Spring的上下文的,我們可以很優雅的獲得Spring的ApplicationContext物件。
如果使用new ClassPathXmlApplicationContext("applicationContext.xml");
相當於重新初始化一遍!!!!
也就是說,重複做啟動時候的初始化工作,第一次執行該類的時候會非常耗時!!!!!

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
這種方式獲取Sping上下文環境,最主要是在測試環境中使用,比如寫一個測試類,系統不啟動的情況下手動初始化Spring上下文再獲取物件!

解決方法:不用類似new ClassPathXmlApplicationContext()的方式,從已有的spring上下文取得已例項化的bean。

具體步驟:1)增加一個ApplicationContextUtil類,用來取得上下文ApplicationContext

  1. /**

      * 實現了ApplicationContextAware 介面,必須實現該方法;

      *通過傳遞applicationContext引數初始化成員變數applicationContext

      */

  2. @Component

  3. publicclass ApplicationContextUtil implements ApplicationContextAware {  
  4.     private  ApplicationContext context;//宣告一個靜態變數儲存
  5.     @Override
  6.     publicvoid setApplicationContext(ApplicationContext applicationContext)  
  7.             throws BeansException {  
  8.         this.context=applicationContext;  
  9.     }  
  10.     public  ApplicationContext getContext(){  
  11.           return context;  
  12.     }  
  13. }  


2) 對ApplicationContextUtil類增加 Spring配置,讓Spring完成此工具類的裝載並且完成applicationcontext上下文的注入;applicationContext-common.xml配置如下:

  1. //初始化appliationUtil類,並完成ApplicationContext的注入
  1. <bean id="applicationContextUtil"class="com.service.utils.ApplicationContextUtil"></bean>  
  1. //對業務類注入ApplicationContextUtil例項
  1. <bean id="workSignCheckJob"class="com.service.tools.quartz.WorkSignCheckJob" >  
  2.   <property name="appContextUtil" ref="applicationContextUtil" />   
  3.  </bean>  

3)業務類呼叫程式碼如下:

  1. ApplicationContext appContext=appContextUtil.getContext();  
  2.  ProjectServiceFacade projectServiceFacade=(ProjectServiceFacade)appContext.getBean("biz.projectServiceFacade");  
  3.     WorkSignService workSignService=(WorkSignService)appContext.getBean("biz.workSignService");