当前位置: 首页 > 知识库问答 >
问题:

Spring提升请求范围的bean到子线程(HttpServletRequest)

谷梁德容
2023-03-14

我现在尝试了很多东西,但我似乎错过了一块拼图。故事是这样的:我有一个请求范围的bean,它从HttpServletRequest读取一些SessionContext。此属性在过滤器中设置。因此,当代码在正确的线程上运行时,这是非常好的。

@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.INTERFACES)
public class SessionContextProviderImpl implements SessionContextProvider<SessionContext> {
    private final HttpServletRequest _request;

    @Autowired
    public SessionContextProviderImpl(HttpServletRequest request) {
        _request = request;
    }

    @Override
    public SessionContext get() {
        return (SessionContext) _request.getAttribute(Constants.SESSION_CONTEXT_IDENTIFIER);
    }
}

现在我开始使用java 8s的新功能CompletableFuture,我有其中三个功能在请求线程等待结果时并行计算东西。我想做的是提升/移交/传播bean或请求,使其可以在从原始超文本传输协议线程派生的子线程上使用。特别是我想从异步提供的CompletableFuture中从HttpServletRequest获取SessionContext。

我尝试的是这个(替换了get的实现):

final HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
request.getAttribute(Constants.SESSION_CONTEXT_IDENTIFIER);

但这显然与请求范围的bean具有相同的结果。“getRequest”返回null而不是抛出的异常。

作为第三种方法,我尝试了这篇原始文章:

ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;

org.springframework.beans.factory.config.Scope simpleThreadScope = new SimpleThreadScope();

cbf.registerScope("simpleThreadScope", simpleThreadScope);

我将SessionContextProviderImpl的范围设置为“simpleThreadScope”。不幸的是,这也不起作用,并抛出了一个异常,即它在请求范围之外使用。

我使用的环境:泽西连同Spring注射。

也许有人有什么想法?

当做

共有2个答案

汤乐家
2023-03-14

在我的例子中,使用OrderedRequestContextFilter可以解决这个问题。您还必须将threadContextInheritable标志设置为true,如下所示:

@Bean
public RequestContextFilter requestContextFilter() {
    OrderedRequestContextFilter filter = new OrderedRequestContextFilter();
    filter.setThreadContextInheritable(true);
    return filter;
}
闻人嘉悦
2023-03-14

对于任何未来的冒险家:

我花了一些时间研究了Spring代码,找到了具有InheritableRequestAttributeHolder的RequestContextHolder。如果您查看关于这是什么的文档(继承自:InheritableThreadLocal),可以阅读以下内容:

当变量中维护的每个线程属性(例如,用户ID、事务ID)必须自动传输到创建的任何子线程时,可继承的线程局部变量优先于普通线程局部变量使用。

因此RequestContextHolder有一个字段,实际上setRequestAttributes支持使用InheritableRequestAttributeHolder的标志。此外,如果您查看RequestContextListener-

public class InheritableRequestContextListener extends RequestContextListener {
    private static final String REQUEST_ATTRIBUTES_ATTRIBUTE =
        InheritableRequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES";

    @Override
    public void requestInitialized(ServletRequestEvent requestEvent) {
        if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
            throw new IllegalArgumentException(
                    "Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
        }
        HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
        ServletRequestAttributes attributes = new ServletRequestAttributes(request);
        request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
        LocaleContextHolder.setLocale(request.getLocale());
        RequestContextHolder.setRequestAttributes(attributes, true);
    }
}

瞧,我可以在子线程中访问SessionContextProvider。

 类似资料:
  • 在大容量(每秒约50,000个请求)的java Web应用程序中,我使用Threadloce-app执行一个任务,该任务应按请求范围执行。 我可以使用Spring请求范围实现相同的效果,我想知道哪种性能更好? 在代码中,使用线程本地: 对于每个超文本传输协议请求设置: 使用Spring请求范围: 现在,什么成本更高: 或 不知道有没有人已经尝试过这样的标杆了呢?

  • 问题内容: 我正在尝试在Spring中建立一个请求范围的bean。 我已经成功设置好了,所以每个请求创建一次bean。现在,它需要访问HttpServletRequest对象。 由于该bean是每个请求创建一次的,所以我认为容器可以轻松地将请求对象注入到我的bean中。我怎样才能做到这一点 ? 问题答案: 可以将请求范围的Bean与请求对象自动连接。

  • 基于CGLIB的请求范围bean的堆栈跟踪() 基于JDK-Dynamic-Proxy-Interface的请求范围bean的堆栈跟踪()

  • 我得到的错误是: 我检查的内容: > 已启用批注处理,否则AnyService根本不会实例化 AnyBean不是最终的 请求作用域在AnyBean中与AspectJ代理(ScopedProxyMode.target_class)一起定义 存在EnableAspectJAutoproxy批注 类路径上有以下JAR: Web XML还包含RequestContextListener: 当我向org.s

  • 问题内容: 场景:我们有一个在Websphere中运行的Spring托管的Web应用程序。(Spring 3.0.x,WAS 7)Webapp通过Spring的Web应用程序利用Websphere的工作管理器(配置为10的线程池)以执行计算密集型db读取操作。因此,基本上,有一个请求来生成10个不同的文件。要生成文档,只需db读取即可收集/处理数据。因此,我们基本上产生了10个线程来处理10个文档

  • 问题内容: 有人可以解释一下我一直只使用“原型”的Spring bean的作用域吗,但是还有其他参数可以代替吗? 我在说什么的例子 问题答案: 从Spring规范开始,支持五种类型的bean作用域: 1.单身人士(默认*) 每个Spring IoC容器将单个bean定义的作用域限定为单个对象实例。 2.原型 将单个bean定义的作用域限定为任意数量的对象实例。 3.要求 将单个bean定义的范围限