在程式中用new ClassPathXmlApplicationContext()獲取Spring的上下文環境注意事項
問題背景:在我們的web程式中,用spring來管理各個例項(bean), 有時在程式中為了使用已被例項化的bean, 通常會用到這樣的程式碼:
- ApplicationContext appContext =
- new ClassPathXmlApplicationContext("classpath:META-INF/spring/applicationContext-common.xml");
- ApplicationContext appContext=appContextUtil.getContext();
-
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
-
/**
* 實現了ApplicationContextAware 介面,必須實現該方法;
*通過傳遞applicationContext引數初始化成員變數applicationContext
*/
-
@Component
- publicclass ApplicationContextUtil implements ApplicationContextAware {
- private ApplicationContext context;//宣告一個靜態變數儲存
- @Override
- publicvoid setApplicationContext(ApplicationContext applicationContext)
- throws BeansException {
- this.context=applicationContext;
- }
- public ApplicationContext getContext(){
- return context;
- }
- }
2) 對ApplicationContextUtil類增加 Spring配置,讓Spring完成此工具類的裝載並且完成applicationcontext上下文的注入;applicationContext-common.xml配置如下:
- //初始化appliationUtil類,並完成ApplicationContext的注入
- <bean id="applicationContextUtil"class="com.service.utils.ApplicationContextUtil"></bean>
- //對業務類注入ApplicationContextUtil例項
- <bean id="workSignCheckJob"class="com.service.tools.quartz.WorkSignCheckJob" >
- <property name="appContextUtil" ref="applicationContextUtil" />
- </bean>
3)業務類呼叫程式碼如下:
- ApplicationContext appContext=appContextUtil.getContext();
- ProjectServiceFacade projectServiceFacade=(ProjectServiceFacade)appContext.getBean("biz.projectServiceFacade");
- WorkSignService workSignService=(WorkSignService)appContext.getBean("biz.workSignService");