2011-10-03 84 views
8

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

问题: 现在这种方法的问题是,当线程正在做他们的数据库调用和方面是interjects我们得到java.lang.IllegalStateException: No thread-bound request found异常。我的理解是完全有效的,因为线程在请求​​上下文之外执行。

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

回答

5

我不认为你可以直接做到这一点。即使你可以,它会有点难看。但是,您可以生成唯一的请求标识符(甚至可以使用会话标识符,但要注意多个标签),并将其传递给每个处理线程。然后该方面可以使用该ID作为缓存的关键。缓存本身也是单身人士,但会有Map<String, X>,其中String是ID,X是您的缓存结果。为了使事情更容易处理,可以使用@Async方法(而不是手动产生线程),并且每个方法都可以将缓存ID作为其第一个参数传递。

(当然,你的异步方法应该返回Future<Result>这样就可以收集他们的请求线程结果)

+0

我想到的办法,但有一个缺点,我觉得是,它会迫使我传球在我想要缓存的所有方法调用的下游(在线程执行期间)的唯一请求标识符。另外,一段时间后缓存会不会很大?这会迫使我定期进行管理。也许我在这里错过了一些东西。 – r4j1v

+0

也许有一个“线程执行上下文”,我可以使用它来存储我的唯一请求标识符并在方面检索它,而不必自己传递它? – r4j1v

+5

我设法解决了这个问题。我开始使用'SimpleAsyncTaskExecutor'而不是'WorkManagerTaskExecutor'。好处是'SimpleAsyncTaskExecutor'永远不会重用线程。这只是解决方案的一半。解决方案的另一半是使用'RequestContextFilter'而不是'RequestContextListener'。 'RequestContextFilter'有一个'setThreadContextInheritable()'方法,它基本上允许子线程继承父上下文。 – r4j1v

相关问题