将Spring EntityManager放入异步Servlet 3.0的线程中?
我们试图在Spring应用程序中启用Servlet的3.0“异步支持”:将Spring EntityManager放入异步Servlet 3.0的线程中?,spring,hibernate,jpa,spring-security,jpa-2.0,Spring,Hibernate,Jpa,Spring Security,Jpa 2.0,我们试图在Spring应用程序中启用Servlet的3.0“异步支持”: 在web.xml(支持异步)中为所有servlet和筛选器添加了true(/async-supported) 根据需要重写请求处理代码 ** ** 这导致两个问题: 运行异步代码时,Spring安全身份验证丢失 没有EntityManager/session/。。。再也没有了 当然,这两个问题都是由于处理程序代码没有在创建Runnable的线程所在的线程中执行。理想情况下,工作线程应该从调用线程“继承”Spring上下
- 在web.xml(支持异步)中为所有servlet和筛选器添加了true(/async-supported)
- 根据需要重写请求处理代码
private final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
try {
SecurityContextHolder.clearContext();
SecurityContextHolder.getContext().setAuthentication(authentication);
..run code here..
} finally {
SecurityContextHolder.clearContext();
}
但是,对于第二个问题,我不知道如何将会话“转移”到执行线程。对于Servlet2.x,我们使用OpenEntityManagerViewFilter将会话粘贴到线程
<filter>
<filter-name>openEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>entityManagerFactoryBeanName</param-name>
<param-value>entityManagerFactory</param-value>
</init-param>
</filter>
OpenEntityManager视图过滤器
org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
真的
EntityManager工厂名称
实体管理工厂
但是现在,这当然没有任何意义了,因为它粘贴到的线程与执行请求的线程不同
我尝试了Spring3.1和3.2的各种版本。但毫无效果
有谁知道怎么避开这件事吗?最好是黑客攻击。:-)
Myweb.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>Foo</servlet-name>
<servlet-class>com.foo.Main</servlet-class>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>Foo</servlet-name>
<url-pattern>/restricted/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>openEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>entityManagerFactoryBeanName</param-name>
<param-value>entityManagerFactory</param-value>
</init-param>
</filter>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.bar.ServletInit</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.foo.SpringCtxInitializer</param-value>
</context-param>
<filter-mapping>
<filter-name>openEntityManagerInViewFilter</filter-name>
<url-pattern>/restricted/*</url-pattern>
</filter-mapping>
</web-app>
福
com.foo.Main
真的
福
/受限的/*
OpenEntityManager视图过滤器
org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
真的
EntityManager工厂名称
实体管理工厂
springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy
真的
springSecurityFilterChain
/*
org.springframework.web.context.ContextLoaderListener
org.bar.ServletInit
上下文配置位置
/WEB-INF/applicationContext.xml
上下文初始化类
com.foo.SpringCtxInitializer
OpenEntityManager视图过滤器
/受限的/*
您需要为该异步线程打开一个新的会话/entitymanager(会话不能在线程之间共享)。为此,您可能希望使用OpenSessionInViewInterceptor
(或者我猜对于JPA来说,它被称为OpenEntityManagerInViewInterceptor
),但是您需要手动调用它的方法,或者为此编写自己的方面,并使用代理。通过复制/粘贴过滤器的代码,我取得了一些成功。但是我不知道实体管理器下游会发生什么情况——如果另一个异步处理也发生了。当下游发生故障时,如何保证事务完整性?事务完整性在这里不是问题,因为一切都将在spring启动的事务中完成,无论是在服务层还是在拦截器中,即使这发生在不同的线程中。当涉及到共享EntityManager
时,你无法强制在线程之间不共享它,除非你想迭代所有线程并检查它们的线程局部变量,这是纯Java,你只需要小心。我不知道我是否真的想这样做。:-)我希望Spring3.2能够提供支持。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>Foo</servlet-name>
<servlet-class>com.foo.Main</servlet-class>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>Foo</servlet-name>
<url-pattern>/restricted/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>openEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>entityManagerFactoryBeanName</param-name>
<param-value>entityManagerFactory</param-value>
</init-param>
</filter>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.bar.ServletInit</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.foo.SpringCtxInitializer</param-value>
</context-param>
<filter-mapping>
<filter-name>openEntityManagerInViewFilter</filter-name>
<url-pattern>/restricted/*</url-pattern>
</filter-mapping>
</web-app>