将Spring EntityManager放入异步Servlet 3.0的线程中? [英] Put Spring EntityManager in thread for async Servlet 3.0?

查看:110
本文介绍了将Spring EntityManager放入异步Servlet 3.0的线程中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在尝试在Spring应用程序中启用Servlet的3.0异步支持:


  • 在web中添加。 xml (支持异步)true(支持/ async),用于所有servlet和过滤器。 重新编写请求处理代码



**

  @Override 
public void run(){
handleRequest(servlet,request,response);
}
});

**



这会导致两个问题:
$ b


  1. 在运行异步代码时,Spring Security认证会丢失。


  2. 没有EntityManager / session / ...也没有。

  3. 是由于处理程序代码不是在创建Runnable的线程所在的同一线程中执行的。理想情况下,工作线程应该从调用线程继承Spring上下文。



    我可以通过在构建时保存身份验证并将其设置为执行时间处理时间。

      private final Authentication authentication = SecurityContextHolder.getContext()。getAuthentication(); 

    尝试{
    SecurityContextHolder.clearContext();
    SecurityContextHolder.getContext()。setAuthentication(authentication);

    ..在这里运行代码..

    } finally {
    SecurityContextHolder.clearContext();
    }

    然而,对于第二个问题,我不知道如何转移会话到执行线程。对于servlet 2.x,我们使用 OpenEntityManagerInViewFilter 将会话加入到线程中。

     <滤光器> 
    < 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>

    但是现在当然这没有任何意义,因为它粘贴的线程不是和执行请求的一样。

    我试过了Spring 3.1和3.2的各种版本。但没有效果。

    任何知道如何解决此问题的人?最好用黑客。 : - )



    我的 web.xml

     <?xml version =1.0encoding =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>


    解决方案

    您需要为此打开一个新的会话/实体管理器异步线程(会话不能在线程之间共享)。为此,您可能需要使用 OpenSessionInViewInterceptor (或者我猜JPA称为 OpenEntityManagerInViewInterceptor ),但您会需要手动调用其方法或为此编写自己的方面并使用代理。


    We're trying to enable Servlet's 3.0 "async-supported" in our Spring application:

    • Added in web.xml (async-supported)true(/async-supported) for all servlets and filters.

    • Rewrote the request handling code as

    **

    request.getAsyncContext().start(new Runnable() {
      @Override
      public void run() {
        handleRequest(servlet, request, response);
      }
    });
    

    **

    This causes two problems:

    1. Spring Security authentication is lost when running the asynchronous code.

    2. There is no EntityManager/session/... any more either.

    Of course both problems are due to the fact the handler code is not executed in the same thread as the thread that created the Runnable. Ideally the worker thread should "inherit" the Spring contexts from the invoking thread.

    I could get around the Spring Security problem by saving the authentication at construction time and setting it at execution time.

    private final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    
    try {
      SecurityContextHolder.clearContext();
      SecurityContextHolder.getContext().setAuthentication(authentication);
    
      ..run code here..
    
    } finally {
      SecurityContextHolder.clearContext();
    } 
    

    However, for the second problem I have no clue how to "transfer" the session to the executing thread. For servlet 2.x we were using OpenEntityManagerInViewFilter to stick a session to the thread.

    <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>
    

    But now of course this does not make sense any more because the thread it sticks it to is not the same as the one which executed the request.

    I've tried various versions of Spring 3.1 and 3.2. But to no effect.

    Anybody who knows how to get around this ? Preferably with hacking. :-)

    My web.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>
    

    解决方案

    You need to open a new session/entitymanager for that async thread (sessions can't be shared between threads). For this purpose you might want to use OpenSessionInViewInterceptor (or I guess for JPA it's called OpenEntityManagerInViewInterceptor), but you'll need to manually invoke its methods or write your own aspect for this purpose and use proxies.

    这篇关于将Spring EntityManager放入异步Servlet 3.0的线程中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆