Spring 4.1 MVC + Hibernate 4.3 + Webflow 2.4 + OpenSessionInViewFilter = java.lang.IllegalStateException,已将值绑定到线程
Spring 4.1 MVC + Hibernate 4.3 + Webflow 2.4 + OpenSessionInViewFilter = java.lang.IllegalStateException, Already value for key bound to thread
我正在将应用程序从这些组件版本升级到它们的最新对应版本:
Spring 3.0.4 -> Spring 4.1.6
Hibernate 3.3.0 -> Hibernate 4.3.8
Spring Webflow 2.0.7 -> Spring Webflow 2.4.1
Spring Security 2.0.4 -> Spring Security 3.2.6
我目前非常纠结于与 OpenSessionInViewFilter
和 Spring Webflows 相关的问题。 None 与我的 webflow 相关的代码甚至被执行,问题发生在 webflow 和 Hibernate SessionHolder 的初始化时。在此 Spring/Hibernate 升级期间,我没有更改 webflow 配置,并且在近 6 年的时间里,一切都在生产中运行良好。我收到以下异常,网络上几乎没有帮助。堆栈跟踪有一英里长,所以我包括了我认为重要的部分。
2015/04/06 18:39:31 ERROR exception_jsp Stack Trace -
org.springframework.webflow.execution.FlowExecutionException: Exception thrown in state 'null' of flow 'process/order'
at org.springframework.webflow.engine.impl.FlowExecutionImpl.wrap(FlowExecutionImpl.java:573)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:227)
at org.springframework.webflow.executor.FlowExecutorImpl.launchExecution(FlowExecutorImpl.java:140)
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:238)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
...
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122)
at
...
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
at
...
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: Already value [org.springframework.orm.hibernate4.SessionHolder@30b921ac] for key [org.hibernate.internal.SessionFactoryImpl@486fe7cb] bound to thread [http-nio-8080-exec-8]
at org.springframework.transaction.support.TransactionSynchronizationManager.bindResource(TransactionSynchronizationManager.java:190)
at org.springframework.webflow.persistence.HibernateFlowExecutionListener.bind(HibernateFlowExecutionListener.java:250)
at org.springframework.webflow.persistence.HibernateFlowExecutionListener.sessionStarting(HibernateFlowExecutionListener.java:137)
at org.springframework.webflow.engine.impl.FlowExecutionListeners.fireSessionStarting(FlowExecutionListeners.java:117)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:367)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:223)
... 76 more
web.xml的相关部分:
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param><param-name>singleSession</param-name><param-value>false</param-value></init-param>
</filter>
<filter-mapping>
<filter-name>openSessionInViewFilter</filter-name>
<url-pattern>*.htm</url-pattern>
</filter-mapping>
应用程序上下文配置的相关部分:
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="order" value="0"/>
<property name="flowRegistry" ref="flowRegistry"/>
</bean>
<!-- Dispatches requests mapped to flows to FlowHandler implementations -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor"/>
</bean>
...
<bean id="flowExecutionListener" class="org.springframework.webflow.persistence.HibernateFlowExecutionListener">
<constructor-arg ref="sessionFactory" />
<constructor-arg ref="transactionManager" />
</bean>
...
<webflow:flow-executor id="flowExecutor">
<webflow:flow-execution-listeners>
<webflow:listener ref="flowExecutionListener" />
<webflow:listener ref="securityFlowExecutionListener" />
</webflow:flow-execution-listeners>
</webflow:flow-executor>
...
<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices" base-path="/WEB-INF">
<webflow:flow-location-pattern value="/**/*-flow.xml" />
</webflow:flow-registry>
Webflow配置文件:
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.4.xsd">
<persistence-context/>
<on-start>
<evaluate expression="orderFormFactory.createOrderForm(externalContext.sessionMap.inboxCriteria)" result="flowScope.orderForm"/>
</on-start>
...
似乎 OpenSessionInViewFilter
首先创建 Hibernate Session,然后 HibernateFlowExecutionListener
尝试创建一个而不是使用 OpenSessionInViewFilter
创建的会话,因此导致 "Already value [org.springframework.orm.hibernate4.SessionHolder@xxxxxxxx] for key [org.hibernate.internal.SessionFactoryImpl@xxxxxxxx] bound to thread [xxxxxxxxxxxxxxx]"
错误。
关于我可以调整或进一步深入研究以进行故障排除的任何想法?任何解决方案或解决方法?还有其他人看到这个吗?感谢您的帮助!
我的解决方案是将我的 Web 流从 OpenSessionInViewFilter 处理中分离出来。在我进行更改之前,应用程序中所有以 *.htm 结尾的 URL 都通过 OpenSessionInViewFilter 进行路由。这是更改前我的 web.xml:
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param><param-name>singleSession</param-name><param-value>false</param-value></init-param>
</filter>
<filter-mapping>
<filter-name>openSessionInViewFilter</filter-name>
<url-pattern>*.htm</url-pattern>
</filter-mapping>
现在我的 web.xml 有这样的配置:
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.somepackage.MyCustomOpenSessionInViewFilter</filter-class>
<init-param><param-name>singleSession</param-name><param-value>false</param-value></init-param>
</filter>
<filter-mapping>
<filter-name>openSessionInViewFilter</filter-name>
<url-pattern>*.htm</url-pattern>
<url-pattern>*.flow</url-pattern>
</filter-mapping>
请注意,我为 openSessionInViewFilter 添加了一个新的 *.flow url-pattern 到我的过滤器映射中,我现在有一个自定义 class 覆盖 Spring OpenSessionInViewFilter (更多内容见下文)。然后,我不得不更改我的视图(以及少数情况下的控制器)中调用 webflows 的地方的 URL 后缀,从使用 '.htm' 更改为使用 '.flow'。
因此,例如,如果我以前使用的 webflow url of '/customer/customer-add.htm',我将其更改为 '/customer/customer-add.flow'.
下一篇是我添加了一个从Spring的OpenSessionInViewFilter派生的class,其目的是将所有*.htm URLs传递给OpenSessionInViewFilter,同时简单地转发所有*.flow URLs 到链中的下一个过滤器(从而允许 HibernateFlowExecutionListener 最终处理 URL 并正确管理会话):
package org.somepackage;
import javax.servlet.http.HttpServletRequest;
import org.springframework.orm.hibernate4.support.OpenSessionInViewFilter;
public class MyCustomOpenSessionInViewFilter extends OpenSessionInViewFilter {
@Override
public boolean shouldNotFilter( HttpServletRequest request ) {
return request.getRequestURI().contains( ".flow" );
}
}
最后,请注意,您应该单独保留 HibernateFlowExecutionListener 的 Spring 配置 —— 无需更改:
<bean id="flowExecutionListener" class="org.springframework.webflow.persistence.HibernateFlowExecutionListener">
<constructor-arg ref="sessionFactory" />
<constructor-arg ref="transactionManager" />
</bean>
我正在将应用程序从这些组件版本升级到它们的最新对应版本:
Spring 3.0.4 -> Spring 4.1.6
Hibernate 3.3.0 -> Hibernate 4.3.8
Spring Webflow 2.0.7 -> Spring Webflow 2.4.1
Spring Security 2.0.4 -> Spring Security 3.2.6
我目前非常纠结于与 OpenSessionInViewFilter
和 Spring Webflows 相关的问题。 None 与我的 webflow 相关的代码甚至被执行,问题发生在 webflow 和 Hibernate SessionHolder 的初始化时。在此 Spring/Hibernate 升级期间,我没有更改 webflow 配置,并且在近 6 年的时间里,一切都在生产中运行良好。我收到以下异常,网络上几乎没有帮助。堆栈跟踪有一英里长,所以我包括了我认为重要的部分。
2015/04/06 18:39:31 ERROR exception_jsp Stack Trace -
org.springframework.webflow.execution.FlowExecutionException: Exception thrown in state 'null' of flow 'process/order'
at org.springframework.webflow.engine.impl.FlowExecutionImpl.wrap(FlowExecutionImpl.java:573)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:227)
at org.springframework.webflow.executor.FlowExecutorImpl.launchExecution(FlowExecutorImpl.java:140)
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:238)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
...
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122)
at
...
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
at
...
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: Already value [org.springframework.orm.hibernate4.SessionHolder@30b921ac] for key [org.hibernate.internal.SessionFactoryImpl@486fe7cb] bound to thread [http-nio-8080-exec-8]
at org.springframework.transaction.support.TransactionSynchronizationManager.bindResource(TransactionSynchronizationManager.java:190)
at org.springframework.webflow.persistence.HibernateFlowExecutionListener.bind(HibernateFlowExecutionListener.java:250)
at org.springframework.webflow.persistence.HibernateFlowExecutionListener.sessionStarting(HibernateFlowExecutionListener.java:137)
at org.springframework.webflow.engine.impl.FlowExecutionListeners.fireSessionStarting(FlowExecutionListeners.java:117)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:367)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:223)
... 76 more
web.xml的相关部分:
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param><param-name>singleSession</param-name><param-value>false</param-value></init-param>
</filter>
<filter-mapping>
<filter-name>openSessionInViewFilter</filter-name>
<url-pattern>*.htm</url-pattern>
</filter-mapping>
应用程序上下文配置的相关部分:
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="order" value="0"/>
<property name="flowRegistry" ref="flowRegistry"/>
</bean>
<!-- Dispatches requests mapped to flows to FlowHandler implementations -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor"/>
</bean>
...
<bean id="flowExecutionListener" class="org.springframework.webflow.persistence.HibernateFlowExecutionListener">
<constructor-arg ref="sessionFactory" />
<constructor-arg ref="transactionManager" />
</bean>
...
<webflow:flow-executor id="flowExecutor">
<webflow:flow-execution-listeners>
<webflow:listener ref="flowExecutionListener" />
<webflow:listener ref="securityFlowExecutionListener" />
</webflow:flow-execution-listeners>
</webflow:flow-executor>
...
<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices" base-path="/WEB-INF">
<webflow:flow-location-pattern value="/**/*-flow.xml" />
</webflow:flow-registry>
Webflow配置文件:
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.4.xsd">
<persistence-context/>
<on-start>
<evaluate expression="orderFormFactory.createOrderForm(externalContext.sessionMap.inboxCriteria)" result="flowScope.orderForm"/>
</on-start>
...
似乎 OpenSessionInViewFilter
首先创建 Hibernate Session,然后 HibernateFlowExecutionListener
尝试创建一个而不是使用 OpenSessionInViewFilter
创建的会话,因此导致 "Already value [org.springframework.orm.hibernate4.SessionHolder@xxxxxxxx] for key [org.hibernate.internal.SessionFactoryImpl@xxxxxxxx] bound to thread [xxxxxxxxxxxxxxx]"
错误。
关于我可以调整或进一步深入研究以进行故障排除的任何想法?任何解决方案或解决方法?还有其他人看到这个吗?感谢您的帮助!
我的解决方案是将我的 Web 流从 OpenSessionInViewFilter 处理中分离出来。在我进行更改之前,应用程序中所有以 *.htm 结尾的 URL 都通过 OpenSessionInViewFilter 进行路由。这是更改前我的 web.xml:
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param><param-name>singleSession</param-name><param-value>false</param-value></init-param>
</filter>
<filter-mapping>
<filter-name>openSessionInViewFilter</filter-name>
<url-pattern>*.htm</url-pattern>
</filter-mapping>
现在我的 web.xml 有这样的配置:
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.somepackage.MyCustomOpenSessionInViewFilter</filter-class>
<init-param><param-name>singleSession</param-name><param-value>false</param-value></init-param>
</filter>
<filter-mapping>
<filter-name>openSessionInViewFilter</filter-name>
<url-pattern>*.htm</url-pattern>
<url-pattern>*.flow</url-pattern>
</filter-mapping>
请注意,我为 openSessionInViewFilter 添加了一个新的 *.flow url-pattern 到我的过滤器映射中,我现在有一个自定义 class 覆盖 Spring OpenSessionInViewFilter (更多内容见下文)。然后,我不得不更改我的视图(以及少数情况下的控制器)中调用 webflows 的地方的 URL 后缀,从使用 '.htm' 更改为使用 '.flow'。
因此,例如,如果我以前使用的 webflow url of '/customer/customer-add.htm',我将其更改为 '/customer/customer-add.flow'.
下一篇是我添加了一个从Spring的OpenSessionInViewFilter派生的class,其目的是将所有*.htm URLs传递给OpenSessionInViewFilter,同时简单地转发所有*.flow URLs 到链中的下一个过滤器(从而允许 HibernateFlowExecutionListener 最终处理 URL 并正确管理会话):
package org.somepackage;
import javax.servlet.http.HttpServletRequest;
import org.springframework.orm.hibernate4.support.OpenSessionInViewFilter;
public class MyCustomOpenSessionInViewFilter extends OpenSessionInViewFilter {
@Override
public boolean shouldNotFilter( HttpServletRequest request ) {
return request.getRequestURI().contains( ".flow" );
}
}
最后,请注意,您应该单独保留 HibernateFlowExecutionListener 的 Spring 配置 —— 无需更改:
<bean id="flowExecutionListener" class="org.springframework.webflow.persistence.HibernateFlowExecutionListener">
<constructor-arg ref="sessionFactory" />
<constructor-arg ref="transactionManager" />
</bean>