转自(http://www.blogjava.net/jackstudio/archive/2006/11/09/80060.html)
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子类来处理相应的请求了。