将Spring EntityManager放入异步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上下

我们试图在Spring应用程序中启用Servlet的3.0“异步支持”:

  • 在web.xml(支持异步)中为所有servlet和筛选器添加了true(/async-supported)

  • 根据需要重写请求处理代码

**

**

这导致两个问题:

  • 运行异步代码时,Spring安全身份验证丢失

  • 没有EntityManager/session/。。。再也没有了

  • 当然,这两个问题都是由于处理程序代码没有在创建Runnable的线程所在的线程中执行。理想情况下,工作线程应该从调用线程“继承”Spring上下文

    我可以通过在构建时保存身份验证并在执行时设置来绕过Spring安全问题

    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>