`

spring的2种加载方式:ContextLoaderListener和ContextLoaderPlugIn

阅读更多
今天有一个朋友问了我一个问题,他使用的是Hibernate/Spring/Struts架构,配置使用Spring的OpenSessionInViewFilter,但是发现不生效,lazy的集合属性在页面访问的时候仍然报session已经关闭的错误。我和他一起检查了所有的配置和相关的代码,但是没有发现任何问题。经过调试发现,应用程序使用的Session和OpenSessionInView Filter打开的Session不是同一个,所以OpenSessionInView模式没有生效,但是为什么他们不使用同一个Session呢?

检查了一遍Spring的相关源代码,发现了问题的根源:

通常在Web应用中初始化Spring的配置,我们会在web.xml里面配置一个Listener,即:

<listener>  
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
</listener>  


如果使用Struts,那么需要在Struts的配置文件struts-config.xml里面配置一个Spring的plugin:ContextLoaderPlugIn。像这样:
 <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
    <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml,/WEB-INF/action-servlet.xml" />
  </plug-in>


实际上ContextLoaderListener和ContextLoaderPlugIn的功能是重叠的,他们都是进行Spring配置的初始化工作的。因此,如果你不打算使用OpenSessionInView,那么你并不需要在web.xml里面配置ContextLoaderListener。

好了,但是你现在既需要Struts集成Spring,又需要OpenSessionInView模式,问题就来了!

由于ContextLoaderListener和ContextLoaderPlugIn功能重叠,都是初始化Spring,你不应该进行两次初始化,所以你不应该同时使用这两者,只能选择一个,因为你现在需要集成Struts,所以你只能使用ContextLoaderPlugIn。

但是令人困惑的是,ContextLoaderListener和ContextLoaderPlugIn有一个非常矛盾的地方!

ContextLoaderListener初始化spring配置,然后把它放在ServletContext对象里面保存:

servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);


请注意,保存的对象的key是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE!

但是ContextLoaderPlugIn初始化spring配置,然后把它放在ServletContext对象里面保存:

String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);


这个attrName和WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE名字是不一样的!

如果仅仅是名字不一样,问题还不大,你仍然可以放心使用ContextLoaderPlugIn,但是当你使用OpenSessionInView的时候,OpenSessionInViewFilter是使用哪个key取得spring配置的呢?
WebApplicationContext wac =WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext(););


显然,OpenSessionInViewFilter是按照WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE这个key去拿spring配置的!

我们整理一下思路:

ContextLoaderPlugIn保存spring配置的名字叫做attrName;
ContextLoaderListener保存spring配置的名字叫做WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
而OpenSessionInView是按照WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE这个名字去取得spring配置的!
而你的应用程序却是按照attrName去取得spring的配置的!

所以,OpenSessionInView模式失效!

解决办法:
修改ContextLoaderPlugIn代码,在getServletContext().setAttribute(attrName, wac);这个地方加上一行代码:
getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);

或者修改OpenSessionInViewFilter,让它按照attrName去取得spring配置。
分享到:
评论
1 楼 juforg 2010-11-15  
有其它解决方案吗
改源码总觉得不好

相关推荐

    java解决org.springframework.web.context.ContextLoaderListener

    java解决org.springframework.web.context.ContextLoaderListener

    Spring的监听器ContextLoaderListener的作用

    Spring的监听器ContextLoaderListener的作用

    Web项目中使用Spring, 使用 Spring 的器监听器 ContextLoaderListener.docx

    二、 使用 Spring 的器监听器 ContextLoaderListener o1. maven依赖pom.xml o2. 注册监听器 ContextLoaderListener o3. 指定 Spring 配置文件的位置 o4. 获取Spring容器对象 在 Web 项目中使用 Spring 框架,首先...

    ssh整合时遇到常见错误 ContextLoaderListener not found 解决

    ssh整合时 被虐的经验之谈。内容虽然比较少,也是前人的工作经验。

    整合struts2和spring源代码(可以直接在tomcat中运行)

    可以直接运行,并对整合spring和struts2步骤及需要注意的事项进行类总结 整合spring和struts2总结 1.将struts2和spring中的库文件复制到项目下(可以查看WEB-INF\lib目录下的文件) 注意:struts2-spring-...

    Spring-5.1.5源码

    Spring framework 5.1.5源码 Main: spring-web/org.springframework.web.context.ContextLoaderListener

    spring-simple-web:使用 Spring Framework 的简单 Web (WAR) 项目

    Web 应用程序使用 Spring Web 侦听器初始化,例如web.xml org.springframework.web.context.ContextLoaderListener 。 Spring Web 侦听器使用web.xml的contextConfigLocation上下文参数进行初始化。 此设置的...

    spring和hibernate整合

    org.springframework.web.context.ContextLoaderListener &lt;listener&gt; &lt;listener-class&gt;org.springframework.web.context.request.RequestContextListener&lt;/listener-class&gt; &lt;/listener&gt;

    struts2-spring-plugin-2.1.2.jar

    struts2与spring的整合。导入struts2-spring-... spring监听器对应的API类为:org.springframework.web.context.ContextLoaderListener。 struts2-spring-plugin包为我们将struts2的对象工厂设置为spring的IoC容器,

    spring-web-2.5.jar

    org.springframework.remoting.caucho.Hessian2SkeletonInvoker.class org.springframework.remoting.caucho.HessianClientInterceptor.class org.springframework.remoting.caucho.HessianProxyFactoryBean.class ...

    web.xml中ContextLoaderListener的运行过程解析

    web.xml中ContextLoaderListener的运行

    DispatcherServlet 和 ContextLoaderListener 区别

    NULL 博文链接:https://angie.iteye.com/blog/2334955

    springweb3.0MVC注解(附实例)

    org.springframework.web.context.ContextLoaderListener &lt;/listener&gt; &lt;!-- Spring MVC 的Servlet,它将加载WEB-INF/annomvc-servlet.xml 的 配置文件, 以启动Spring MVC模块--&gt; &lt;servlet-name&gt;annomvc ...

    Spring MVC 入门实例

    虽然《Spring in Action》选择了 .html, 但是那是一种非常糟糕的作法, 特别是你整合 Apache 和 Tomcat 的时候. 配置 CharacterEncodingFilter (filter 标签), 否则你会发现中文乱码. 因为我的 jsp 和 html 文件都...

    Spring源码学习七:web应用自动装配Spring配置文件1

    在web应用启动读取web.xml时,发现配置了ContextLoaderListener,而ContextLoaderListener实现了ServletCo

    基于java的企业级应用开发:Spring的核心容器.ppt

    Web服务器实例化ApplicationContext容器时,通常会使用ContextLoaderListener来实现,此种方式只需要在web.xml中添加如下代码: &lt;context-param&gt; &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt; &lt;param-value&gt; ...

    spring源代码解析

    下面我们使用ContextLoaderListener作为载入器作一个详细的分析,这个Servlet的监听器是根上下文被载入的地方,也是整个 Spring web应用加载上下文的第一个地方;从加载过程我们可以看到,首先从Servlet事件中得到...

    ssm

    &lt;!-- 前端控制器:DispatcherServlet --&gt; &lt;!-- 启动WEB容器时,自动装配ApplicationContext配置信息:...-- 确保web应用程序的类加载器以及加载的类正确释放资源:IntrospectorCleanupListener --&gt;

    spring_MVC源码

    本文主要介绍使用注解方式配置的spring mvc,之前写的spring3.0 mvc和rest小例子没有介绍到数据层的内容,现在这一篇补上。下面开始贴代码。 文中用的框架版本:spring 3,hibernate 3,没有的,自己上网下。 先说...

    springmybatis

    其实还有更简单的方法,而且是更好的方法,使用合理描述参数和SQL语句返回值的接口(比如IUserOperation.class),这样现在就可以至此那个更简单,更安全的代码,没有容易发生的字符串文字和转换的错误.下面是详细...

Global site tag (gtag.js) - Google Analytics