spring有三種啟動方式,使用ContextLoaderServlet,ContextLoaderListener和ContextLoaderPlugIn.
看一下ContextLoaderListener的源碼,這是一個ServletContextListener
/**
? * Initialize the root web application context.
? */
?public void contextInitialized(ServletContextEvent event) {
? this.contextLoader = createContextLoader();
? this.contextLoader.initWebApplicationContext(event.getServletContext());
?}
?
? /**
? * Create the ContextLoader to use. Can be overridden in subclasses.
? * @return the new ContextLoader
? */
?protected ContextLoader createContextLoader() {
? return new ContextLoader();
?}
?contextLoader的源碼
?public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
?? throws BeansException {
? long startTime = System.currentTimeMillis();
? if (logger.isInfoEnabled()) {
?? logger.info("Root WebApplicationContext: initialization started");
? }
? servletContext.log("Loading Spring root WebApplicationContext");
? try {
?? // Determine parent for root web application context, if any.
?? ApplicationContext parent = loadParentContext(servletContext);
?? WebApplicationContext wac = createWebApplicationContext(servletContext, parent);
?? servletContext.setAttribute(
???? WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
?? if (logger.isInfoEnabled()) {
??? logger.info("Using context class [" + wac.getClass().getName() +
????? "] for root WebApplicationContext");
?? }
?? if (logger.isDebugEnabled()) {
??? logger.debug("Published root WebApplicationContext [" + wac +
????? "] as ServletContext attribute with name [" +
????? WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
?? }
?? if (logger.isInfoEnabled()) {
??? long elapsedTime = System.currentTimeMillis() - startTime;
??? logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
?? }
?? return wac;
? }
? catch (RuntimeException ex) {
?? logger.error("Context initialization failed", ex);
?? servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
?? throw ex;
? }
? catch (Error err) {
?? logger.error("Context initialization failed", err);
?? servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
?? throw err;
? }
?}
?注意WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,這里面放了WebApplicationContext,需要使用時從ServletContext取出
?可以使用WebApplicationContextUtils得到WebApplicationContext
?public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
? Object attr = sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
? if (attr == null) {
?? return null;
? }
? if (attr instanceof RuntimeException) {
?? throw (RuntimeException) attr;
? }
? if (attr instanceof Error) {
?? throw (Error) attr;
? }
? if (!(attr instanceof WebApplicationContext)) {
?? throw new IllegalStateException("Root context attribute is not of type WebApplicationContext: " + attr);
? }
? return (WebApplicationContext) attr;
?}
?關鍵的問題在于struts如何啟動的spring的,ContextLoaderPlugIn的源碼
?
?// Publish the context as a servlet context attribute.
? String attrName = getServletContextAttributeName();
? getServletContext().setAttribute(attrName, wac);
?
?public String getServletContextAttributeName() {
? return SERVLET_CONTEXT_PREFIX + getModulePrefix();
?}
?不同加載的Key竟然不同,原因就是WebApplicationContext放在那里的問題,可spring調用的時候會根據WebApplicationContext里面定義的那個名字去找的,問題出在這里
?在struts-config.xml中配置
??? <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
????? <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml" />
??? </plug-in>
??? <controller>
??????? <set-property property="processorClass" value="org.springframework.web.struts.DelegatingRequestProcessor" />
??? </controller>
?原理是這樣的,Struts雖然只能有一個ActionServlet實例,但是對于不同的子應用分別能有自己的RequestProcessor實例每個RequestProcessor實例分別對應不同的struts配置文件。
?? 子應用的ProcessorClass類必須重寫一般就是繼承RequestProcessor類,然后再其配置文件的controller元素中的<processorClass>屬性中作出修改。那么當
? getRequestProcessor(getModuleConfig(request)).process(request,response);就能根據request選擇相應的moduleconfig,再根據其<processorClass>屬性選擇相應的RequestProcessor子類來處理相應的請求了。
?