服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

hibernate/spring/struts使用opensessioninview

    今天有一个朋友问了我一个问题,他使用的是hibernate/spring/struts架构,配置使用spring的opensessioninview filter,但是发现不生效,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。

    实际上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配置。

扫描关注微信公众号