java 在多线程 Web 应用程序中访问请求范围的 bean

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7638003/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 20:47:25  来源:igfitidea点击:

Accessing request scoped beans in a multi-threaded web application

javamultithreadingspring

提问by r4j1v

Scenario: We have a Spring managed web application that runs inside Websphere. (Spring 3.0.x, WAS 7) The webapp leverages Websphere's work manager via Spring's WorkManagerTaskExecutor(configured with a thread pool size of 10) to execute computational intensive db read operations. So basically, a request comes in to generate, lets say, 10 different documents. To generate the documents only db reads are needed to gather/process the data. So we basically spawn 10 threads to process the 10 documents and at the end gather the 10 documents returned from the 10 workers and merge them and write back one big response to the client. What we identified is that while the 10 threads are gathering/processing the data there are bunch of similar db calls made. So what we came up with is to create an Aspect around the most-executed db methods to cache the response. The aspect is configured as a singleton, and the cache the aspect uses is autowired into the aspect with a scope set to request-scope so that each request has its own cache.

场景:我们有一个在 Websphere 中运行的 Spring 管理的 Web 应用程序。(Spring 3.0.x, WAS 7) webapp 通过 Spring 的WorkManagerTaskExecutor(配置线程池大小为 10)来执行计算密集型数据库读取操作。所以基本上,一个请求进来生成,比如说,10 个不同的文档。要生成文档,只需要 db 读取来收集/处理数据。所以我们基本上产生了 10 个线程来处理 10 个文档,最后收集从 10 个工人返回的 10 个文档并将它们合并并写回一个大的响应给客户端。我们发现,当 10 个线程正在收集/处理数据时,会进行大量类似的 db 调用。所以我们想出的是围绕执行最多的 db 方法创建一个 Aspect 来缓存响应。方面被配置为单例,方面使用的缓存自动连接到方面,其范围设置为请求范围,以便每个请求都有自己的缓存。

Problem: Now the problem with this approach is that when the threads are doing their db calls and the Aspect is interjects we are getting java.lang.IllegalStateException: No thread-bound request foundexception. Which I understand is totally valid as the threads are being executed outside the request context.

问题:现在这种方法的问题是,当线程在执行它们的 db 调用并且 Aspect 插入时,我们会遇到java.lang.IllegalStateException: No thread-bound request found异常。我的理解是完全有效的,因为线程是在请求上下文之外执行的。

Is there a way to circum-navigate this issue? Is it possible to apply the aspect with a request scoped cache to the methods invoked by these threads?

有没有办法绕过这个问题?是否可以将具有请求范围缓存的方面应用于这些线程调用的方法?

采纳答案by Bozho

I don't think you can do this directly. Even if you could, it would be a bit ugly. However, you can generate a unique request identifier (or even - use the session id, but careful with multiple tabs), and pass that to each processing thread. Then the aspect can use that id as the key to the cache. The cache itself will also be singleton, but there will be Map<String, X>, where Stringis the ID and X is your cached result.

我不认为你可以直接做到这一点。就算可以,也会有点难看。但是,您可以生成唯一的请求标识符(甚至 - 使用会话 ID,但要小心使用多个选项卡),并将其传递给每个处理线程。然后方面可以使用该 id 作为缓存的键。缓存本身也将是单例的,但会有Map<String, X>, 其中StringID 和 X 是您的缓存结果。

To make things easier to handle, you can have @Asyncmethods (rather than manually spawning threads), and each @Asyncmethod can have the cache id passed as its first parameter.

为了使事情更容易处理,您可以使用@Async方法(而不是手动生成线程),并且每个@Async方法都可以将缓存 ID 作为其第一个参数传递。

(Of course, your asynchronous methods should return Future<Result>so that you can collect their results in the request thread)

(当然,您的异步方法应该返回,Future<Result>以便您可以在请求线程中收集它们的结果)