1、 配置在web.xml中 a) 定義成listene <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> b) 定義成servlet <servlet> <servlet-name>SpringContextServlet</servlet-name> <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> c) Web 容器會自動加載 /WEB-INF/applicationContext.xml 初始化 ApplicationContex t實例; 也可以通過 <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext-*.xml</param-value> </context-param> contextConfigLocation是Spring好像是默認加載的名稱(下次讀讀Spring的源代碼看看) 使 Web 容器加載指定名稱路徑的 Spring 配置文件。 這里涉及一個選擇的問題,參考文獻1中認為Listerner要比Servlet更好一些,因為Listerner監(jiān)聽應(yīng)用的啟動和結(jié)束,而Servlet得啟動要稍微延遲一些,如果在這時要做一些業(yè)務(wù)的操作,啟動的前后順序是有影響的。 關(guān)于Listerner和Servlet的區(qū)別我還不了解,還要去找找看到底區(qū)別在哪里。在我們項目中是放在Servlet里面設(shè)置的。 2、 配置為Struts的plungin <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"> <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml, /WEB-INF/action-servlet.xml"/> </plug-in> 不過這類的用法比較不常見,而且他和Struts結(jié)合太緊,如果要做單元測試起來有點困難。 兩者方式都是把Spring的WebApplicationContext放入到web的ServeletContext中,在web項目里面只要能拿到ServeletContext的地方都能使用。這里需要注意的是兩者放入web ServeletContext時候的key是不一樣的。前者是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,后者是ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX+ModuleConfig.getPrefix()。不過前者可以用WebApplicationContextUtils在ServeletContext把WebApplicationContext取出來,后者沒有使用過,不是很了解。
上面說道要做單元測試,所以把Spring設(shè)置成Struts的plugin有點不方便,這個可以看看我們項目里面的使用。
在項目啟動的時候我們做了Struts的plugin:ApplicationInitializer,在這里初始化一些全局變量,這個有點類似程序的main函數(shù)。在這里面: ApplicationContext context = WebApplicationContextUtils. getRequiredWebApplicationContext(this.actionServlet.getServletContext()); // init ServiceLocator ServiceLocator.init(new SpringBeanHolder(context)); 這里可以看到我們?nèi)〕隽薃pplicationContext初始化一個ServiceLocator,以后我們的web都只是和ServiceLocator打交道,這里設(shè)置ApplicationContext只是在一個地方,如果以后要換IOC容器也比較方便,這里是不是一個代理模式呢? 不過這里很奇怪的有可以看見一個SpringBeanHolder,為什么會是這個樣子呢?我們來看看ServiceLocator.init()的定義
public synchronized static void init(BeanHolder beanHolder){ singleton = new ServiceLocator(beanHolder); } 可以看到參數(shù)是BeanHolder,這個是一個接口: public interface BeanHolder { public Object getBean(String beanId); } Look,這里就是把接口和實現(xiàn)分離了,以后如果不使用Spring了,好,那我們換一個實現(xiàn),比如叫CrabBeanHolder :) 不過SpringBeanHolder也很簡單: public class SpringBeanHolder implements BeanHolder { private ApplicationContext context; public SpringBeanHolder(){}
public SpringBeanHolder(ApplicationContext context){
this.context = context; } public Object getBean(String beanId){
return context.getBean(beanId); } } 我們再去look一下ServiceLocator:
public class ServiceLocator { private static Log log = LogFactory.getLog(ServiceLocator.class); private BeanHolder beanHolder; private static ServiceLocator singleton = null; private ServiceLocator(){
}
private ServiceLocator(BeanHolder sh){
this.setServiceHolder(sh); } public synchronized static void init(BeanHolder beanHolder){
singleton = new ServiceLocator(beanHolder); } public static ServiceLocator getInstance(){
return singleton; } private void setServiceHolder(BeanHolder beanHolder){
this.beanHolder = beanHolder; } public Object getBean(String beanId){ return this.beanHolder.getBean(beanId); } public MasterFacade getMasterFacade(){
return (MasterFacade)getBean("masterFacade"); 可以看到他本來是想寫一個單例模式,但是最后沒有做限制,只要你做init方法,都會new一個,雖然我們只是使用一個,但是這里不作一個正規(guī)的if (singleton== null)的判斷總是不太好,起碼new也是一個開銷啊。而且垃圾回收也是一個開銷。記下來,下次改正。
不過在我們的web應(yīng)用中也只是在ApplicationInitializer中做一下init,所以也算是單例啦:) 我們項目中還有一個ComponentManager:
public class ComponentManager { private ComponentManager() {
} public static DataAccessStrategy getDataAccessStrategy(){ return (DataAccessStrategy)ServiceLocator.getInstance().getBean("dataAccessStrategy"); } public static DataSource getDataSource(){ return (DataSource)ServiceLocator.getInstance().getBean("SPSDataSource"); } public static MetadataManager getMetadataManager(){ return (MetadataManager)ServiceLocator.getInstance().getBean("metadataManager"); } public static Object getBean(String beanId){ return ServiceLocator.getInstance().getBean(beanId); } } 這里他也是調(diào)用了ServiceLocator。其實兩者的功能是一樣的,上次我們的開發(fā)經(jīng)理提過讓我們注意兩者的區(qū)別,我想這里的區(qū)別主要是語義上面的,ServiceLocator主要是直接定位各種業(yè)務(wù)Façade他們都用直接的函數(shù)取得。而ComponentManager主要是去一些細顆粒度的bean把。
另外,在單元測試代碼中,我們是這么使用ServiceLocator的: String[] configLocations = {"/WEB-INF/spring-context-common.xml", "/WEB-INF/spring-context-master.xml", "/WEB-INF/spring-context-inventory.xml", "/WEB-INF/spring-context-product.xml", "/WEB-INF/spring-context-open.xml","/WEB-INF/spring-context-order.xml","/WEB-INF/spring-context-group.xml"}; ServiceLocator.init(new SpringBeanHolder (new FileSystemXmlApplicationContext(configLocations))); openProductFacade = (OpenProductFacade) ServiceLocator.getInstance().getOpenProductFacade();
看看這樣是不是很方便,如果配置成為Struts的plungin的話測試的代碼還要重新寫,這樣就不符合DRY(Don’t Repeat Yourself)的原則了。 今天總算是把項目中Struts和Spring結(jié)合的這個部分搞清楚了*^_^*,以前不清不楚的也可以做開發(fā),而且也完成了兩個項目了,但是這樣總是不可以的,到時候碰到問題的時候都不知道怎么去解決呢。而且某某人說過一句:只是用一件東西,不徹底把他搞清楚怎么可以呢。 參考文獻: 1、spring階段性的一點感受 <http://shoufuban.net/showWeb.aspx?ArticleID=5484> |
|