为何不使用ContextLoaderPlugIn也可以正常使用DelegatingRequestProcessor和DelegatingActionProxy整...

本文详细介绍了如何在Struts框架中整合Spring框架,探讨了ContextLoaderPlugIn与ContextLoaderListener/ContextLoaderServlet的区别,以及DelegatingRequestProcessor和DelegatingActionProxy如何在没有ContextLoaderPlugIn的情况下工作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在整合Spring和Struts 1.x时候,网上面的教程都是教大家在struts配置里面增加一个叫org.springframework.web.struts.ContextLoaderPlugIn的插件,增加以下的配置:

[b]struts-config.xml:[/b]


<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/config.xml" />
</plug-in>


[b]config.xml:[/b]


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="helloWorldService" class="com.strutstest.service.impl.HelloWorldServiceImpl">
</bean>
<!--注意此处的映射必须与Struts中的动作对应 -->
<bean name="/helloWorld" class="com.strutstest.action.HelloWorldAction">
<property name="helloWorldService">
<ref bean="helloWorldService" />
</property>
</bean>
</beans>


一般都是这样的方式的;这里ContextLoaderPlugin 的作用是通过contextConfigLocation配置的位置加载Spring的配置文件,生成WebApplicationContext对象,并将该对象放入ServletContext中,
对应的Key为:

ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX + "配置文件前缀"
//或者单纯的
ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX

因此在struts运行时候就已经生成了对应的Spring环境了。Action可以被注册成Spring Bean,纳入Spring管理。

但是有些时候,可以直接使用DelegatingRequestProcessor和DelegatingActionProxy而不需要使用ContextLoaderPlugIn来实现Action的Bean化。其实是因为我们已经使用了ContextLoaderListener/ContextLoaderServlet初始化了Spring的环境,使用时候我们只需要将Action的Bean加入到对应的Spring配置文件即可。

对于[color=red]ContextLoaderPlugIn[/color]和[color=red]ContextLoaderListener/ContextLoaderServlet[/color]的区别主要在于两种方式生成的WebApplicationContext,以不同的Key存放在ServletContext中,ContextLoaderPlugIn是以

ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX + "配置文件前缀"
//或者单纯的
ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX

而ContextLoaderListener/ContextLoaderServlet则是

WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE


既然两个Key不同,那么[color=red]DelegatingRequestProcessor[/color]和[color=red]DelegatingActionProxy[/color]能识别到吗!

DelegatingRequestProcessor是Spring提供的一个继承了struts的RequestProcessor类,使用时候直接在struts-config加入下面代码即可:

<!--告诉Struts用DelegatingRequestProcessor来代替原来的RequestProcessor -->
<controller processorClass="org.springframework.web.struts.DelegatingRequestProcessor" />


由于DelegatingRequestProcessor继承于RequestProcessor,RequestProcessor是struts的核心控制器,通过其来控制Action的创建以及调用,Spring就是在这里做了手脚,Spring重写了RequestProcessor的processActionCreate方法,修改了创建Action方式,通过action 配置中path作为Bean Name,通过Spring容器获取正真的Action对象,然后执行对应的响应方法。

[b]DelegatingRequestProcessor:[/b]

private WebApplicationContext webApplicationContext;
public void init(ActionServlet actionServlet, ModuleConfig moduleConfig) throws ServletException{
super.init(actionServlet, moduleConfig);
if (actionServlet != null) {
this.webApplicationContext = initWebApplicationContext(actionServlet, moduleConfig);
}
}

protected WebApplicationContext initWebApplicationContext(ActionServlet actionServlet, ModuleConfig moduleConfig) throws IllegalStateException {
return DelegatingActionUtils.findRequiredWebApplicationContext(actionServlet, moduleConfig);
}

protected final WebApplicationContext getWebApplicationContext() {
return this.webApplicationContext;
}

protected Action processActionCreate(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws IOException {
Action action = getDelegateAction(mapping);
if (action != null) {
return action;
}
return super.processActionCreate(request, response, mapping);
}

protected Action getDelegateAction(ActionMapping mapping) throws BeansException {
String beanName = determineActionBeanName(mapping);
if (!getWebApplicationContext().containsBean(beanName)) {
return null;
}
return (Action) getWebApplicationContext().getBean(beanName, Action.class);
}

protected String determineActionBeanName(ActionMapping mapping) {
return DelegatingActionUtils.determineActionBeanName(mapping);
}

[b]DelegatingActionUtils:[/b]

public static WebApplicationContext findRequiredWebApplicationContext(ActionServlet actionServlet, ModuleConfig moduleConfig) throws IllegalStateException {
WebApplicationContext wac = getWebApplicationContext(actionServlet, moduleConfig);
// If no Struts-specific context found, fall back to root context.
if (wac == null) {
wac = WebApplicationContextUtils.getRequiredWebApplicationContext(actionServlet.getServletContext());
}
return wac;
}

public static String determineActionBeanName(ActionMapping mapping) {
String prefix = mapping.getModuleConfig().getPrefix();
String path = mapping.getPath();
String beanName = prefix + path;
if (logger.isDebugEnabled()) {
logger.debug("DelegatingActionProxy with mapping path '" + path + "' and module prefix '" + prefix + "' delegating to Spring bean with name [" + beanName + "]");
}
return beanName;
}

public static WebApplicationContext getWebApplicationContext(ActionServlet actionServlet, ModuleConfig moduleConfig) {
WebApplicationContext wac = null;
String modulePrefix = null;
// Try module-specific attribute.
if (moduleConfig != null) {
modulePrefix = moduleConfig.getPrefix();
wac = (WebApplicationContext) actionServlet.getServletContext().getAttribute(ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX + modulePrefix);
}
// If not found, try attribute for default module.
if (wac == null && !"".equals(modulePrefix)) {
wac = (WebApplicationContext) actionServlet.getServletContext().getAttribute(ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX);
}
return wac;
}

[b]WebApplicationContextUtils:[/b]

public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
Assert.notNull(sc, "ServletContext must not be null");
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;
}

public static WebApplicationContext getRequiredWebApplicationContext(ServletContext sc) throws IllegalStateException {
WebApplicationContext wac = getWebApplicationContext(sc);
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
}
return wac;
}


很明显在[color=red]DelegatingRequestProcessor[/color]的[color=red]init[/color]时候[color=red]WebApplicationContext[/color]就已经通过[color=red]DelegatingActionUtils.findRequiredWebApplicationContext[/color]方法获取到,而且很明显[color=red]findRequiredWebApplicationContext[/color]是先根据

ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX + "配置文件前缀"

获取,如果没有就根据
ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX

获取,如果再没有获取到,就根据

WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE

获取,如果还是没有获取到就直接抛出异常。

[color=red]DelegatingRequestProcessor[/color]是会在[color=red]ServletContext[/color]查找[color=red]ContextLoaderPlugIn[/color]和[color=red]ContextLoaderListener/ContextLoaderServlet[/color]的Key,获取[color=red]WebApplicationContext[/color],然后通过[color=red]WebApplicationContext[/color]获取对应的Action。因此[color=red]DelegatingRequestProcessor[/color]是可以在没有[color=red]ContextLoaderPlugIn[/color]的情况下正常运行的。

对于DelegatingActionProxy也是差不多的原理。

[b]DelegatingActionProxy:[/b]

public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
Action delegateAction = getDelegateAction(mapping);
return delegateAction.execute(mapping, form, request, response);
}

protected Action getDelegateAction(ActionMapping mapping) throws BeansException {
WebApplicationContext wac = getWebApplicationContext(getServlet(), mapping.getModuleConfig());
String beanName = determineActionBeanName(mapping);
return (Action) wac.getBean(beanName, Action.class);
}

protected WebApplicationContext getWebApplicationContext(ActionServlet actionServlet, ModuleConfig moduleConfig) throws IllegalStateException {
return DelegatingActionUtils.findRequiredWebApplicationContext(actionServlet, moduleConfig);
}

protected String determineActionBeanName(ActionMapping mapping) {
return DelegatingActionUtils.determineActionBeanName(mapping);
}


[color=red]DelegatingActionProxy[/color]在[color=red]execute[/color]时候也是通过[color=red]DelegatingActionUtils.findRequiredWebApplicationContext[/color]获取[color=red]WebApplicationContext[/color],然后获取Action,来达到目的的。

[size=medium][b]附加:[/b][/size]
配置使用Spring的[color=red]OpenSessionInView Filter[/color]时候,因为[color=red]OpenSessionInViewFilter[/color]是按照

WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE

这个key去拿spring配置的!

[b]整理一下思路:[/b]
ContextLoaderPlugIn保存spring配置的key:

ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX + "配置文件前缀"
//或者单纯的
ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX

ContextLoaderListener保存spring配置的key

WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE

而[color=red]OpenSessionInView[/color]是按照

WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE

这个名字去取得spring容器的!而你的应用程序却是按照[color=red]ContextLoaderPlugIn[/color]的key去取得spring容器的。所以,[color=red]OpenSessionInView[/color]模式失效!
如果使用了[color=red]ContextLoaderPlugIn[/color]的Spring容器,而[color=red]OpenSessionInViewFilter[/color]却获取了[color=red]ContextLoaderListener[/color]的Spring容器。这样会导致Hibernate的session异常关闭的问题。如果配置了两个Spring容器,则刪除[color=red]ContextLoaderPlugIn[/color]的加载方式。若只配置了[color=red]ContextLoaderPlugIn[/color]的加载方式,则改成[color=red]ContextLoaderListener[/color]加载方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值