我正在开发一个分为几个模块的j2ee webapp。我有一些元数据,如用户名和首选项,我想从应用程序的任何地方访问,也可能收集类似于日志信息但特定于请求的数据,并将其存储在这些元数据中,以便我可以选择将其发回作为用户的调试信息。
除了从上层表示类到使用AOP的每个方法中传递通用上下文对象之外,唯一的解决方案是使用与会话BTW非常类似的线程局部“上下文”对象,并添加一个过滤器,用于在正在进行的请求中绑定它,并在响应时解除绑定。
但是这样的事情感觉有点hacky,因为这会破坏几种模式,并且在测试和调试时可能会使事情变得复杂,所以我想问一下,根据你的经验,这样做是否可行?
答案 0 :(得分:2)
在测试方面,最好的工具是依赖注入。它允许将伪依赖注入到被测对象中。
所有依赖注入框架(Spring,CDI,Guice)都有范围的概念(其中request是其中一个范围)。在引擎盖下,存储在请求作用域中的bean确实与ThreadLocal变量相关联,但这都是由依赖注入框架完成的。
我要做的就是使用一个DI框架,它可以使请求范围对象在任何地方都可用,但不必查找它们,这会破坏可测试性。只需要在其中使用请求范围的对象,DI框架就会为您检索它。
答案 1 :(得分:2)
ThreadLocal是弥补糟糕设计和/或架构的黑客。这是一个可怕的做法:a)它是一个或多个全局变量的池,任何语言中的全局变量都是不好的做法(有一整套与全局变量相关的问题 - 在网上搜索它)b)它可能导致内存在任何j2ee容器中泄漏,而不是管理它的线程,如果你不能很好地处理它。
更糟糕的做法是在各个层中使用ThreadLocal。 从一层传递到另一层的数据应使用传输对象(标准模式)传递。
很难想到使用ThreadLocal的合理理由。也许如果你需要在它们之间有第三层/中间层的2层之间传递一些值,而你没有办法对那个中间层进行更改......但是如果是这样的话,我会寻找一个更好的中间层 在任何情况下,如果您将值存储在代码中的一个特定点并在另一个单点中检索它,那么它可能是可以原谅的,否则您永远不会知道任何执行方法可能对ThreadLocal中的值产生什么影响。
答案 2 :(得分:1)
我个人更喜欢传递一个上下文对象,因为同一个线程用于处理的事实是实现的工件,你不应该依赖这样的工件。你想要使用其他线程的那一刻,你就会碰壁。
如果这些状态封装在Context对象中,我认为它足够干净。
答案 3 :(得分:1)
你必须知道一个servlet容器可以/将会重复使用线程来处理请求,所以如果你使用ThreadLocals,你需要在请求完成后自己清理(可能使用过滤器)
答案 4 :(得分:1)
如果您是该项目中唯一的开发人员,并且您认为自己获得了一些成就:就这样做吧!因为这是你的时间。但是,请准备好在以后重新制定决策并重新组织代码库,但总是如此。
假设该项目有十位开发人员。每个人都可能想让它的线程局部变量传递货币,语言环境,角色等参数,甚至可能变成HashMap ....
我认为最终,并非所有可行的事情都应该完成。复杂性会反击你......