今天有一个朋友问了我一个问题,他使用的是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配置。
闽公网安备 35060202000074号