java 我应该把我的 ThreadLocals 放在一个弹簧注入的单例中吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2218282/
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-29 20:07:15  来源:igfitidea点击:

Should I put my ThreadLocals in a spring-injected singleton?

javaspringconcurrencydependency-injection

提问by John

Several people (eg at serverside http://www.theserverside.com/news/thread.tss?thread_id=41473) suggest that using ThreadLocal objects is as bad as using global variables. I imagine this is true if you make them public static variables. The problem then is that it can be hard to tell where it is used, where it's changed, etc.

一些人(例如在服务器端http://www.theserverside.com/news/thread.tss?thread_id=41473)建议使用 ThreadLocal 对象与使用全局变量一样糟糕。我想这是真的,如果你让它们成为公共静态变量。那么问题是,很难分辨它在哪里使用,在哪里更改,等等。

In my spring DI tomcat web-app, it seems to counter this problem if I just get spring to create a singleton object that has my ThreadLocal(s) in it, and then inject that singleton into any class that needs it.

在我的 spring DI tomcat web-app 中,如果我只是让 spring 创建一个包含我的 ThreadLocal(s) 的单例对象,然后将该单例注入任何需要它的类,它似乎可以解决这个问题。

So my singleton looks like this:

所以我的单身看起来像这样:

@Component
public class Username {
    private ThreadLocal<String> username;

    public Username() {
        username = new ThreadLocal<String>();
    }

    public String getUsername()
        return username.get();
    }

    public void setUsername(String name) {
        username.set(name);
    }
}

And classes that might need it look like this:

可能需要它的类如下所示:

@Service
public class addEntryTransaction {

    @Autowired
    Username username;

    public void method() {
        ...
        log("Method called by "+username.getUsername());
        ...
     }

}

This still has the benefits of not having to pass a username through many layers that don't care, and therefore keeping the method parameters simpler. The @Autowired is a declaration that this class uses that variable.

这仍然具有不必通过许多不关心的层传递用户名的好处,因此使方法参数更简单。@Autowired 是该类使用该变量的声明。

What are the advantages and disadvantages of this approach?

这种方法的优点和缺点是什么?

采纳答案by axtavt

If you use Spring, you can simply use a request-scoped bean instead of explicit ThreadLocals:

如果您使用 Spring,您可以简单地使用请求范围的 bean 而不是显式ThreadLocals:

public interface UserName {
    ...
}

@Component 
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
public class UsernameImpl implements UserName { 
    private String username; 
    ...
}

回答by skaffman

As @axtavt mentioned, request-scoped beansare usually a cleaner and more elegant alternative to ThreadLocals when you're talking about web applications. In fact, under the covers, Spring implements request-scoped beans using its own ThreadLocal variables (see RequestContextHolder). Both ThreadLocal and scoped beans give you the same basic advantage - the ability to access the object without having to pass it down manually through the call stack.

正如@axtavt 所提到的,当您谈论 Web 应用程序时,请求范围的 bean通常是 ThreadLocals 的更清晰、更优雅的替代方案。事实上,在幕后,Spring 使用自己的 ThreadLocal 变量实现请求范围的 bean(请参阅 参考资料RequestContextHolder)。ThreadLocal 和作用域 bean 都为您提供了相同的基本优势 - 无需通过调用堆栈手动向下传递即可访问对象的能力。

There is one scenario where ThreadLocal variales win over scoped beans, though, which is in cases where you want to access the object from outside of Spring's bean lifecycle. A good example of this is inside a JSP taglib. Taglib instances are controlled by the servlet container, not Spring, and so cannot participate in Spring's IoC framework, and so cannot be wired up with a request-scoped bean (or any other bean, for that matter). They can, however, access ThreadLocal variables. There are ways around this, but sometimes ThreadLocals are the easiest approach.

但是,有一种情况 ThreadLocal 变量胜过作用域 bean,这是在您想要从 Spring bean 生命周期之外访问对象的情况下。一个很好的例子是在 JSP 标签库中。Taglib 实例由 servlet 容器而不是 Spring 控制,因此不能参与 Spring 的 IoC 框架,因此不能与请求范围的 bean(或任何其他 bean,就此而言)连接。但是,它们可以访问 ThreadLocal 变量。有很多方法可以解决这个问题,但有时 ThreadLocals 是最简单的方法。

One of the functional disadvantages of ThreadLocal is that they're not very useful in applications where data is passed from thread to thread (InheritableThreadLocal helps here sometimes, but not always). In such situations, Spring's scoped beans also fail, since they are implemented using ThreadLocal.

ThreadLocal 的功能缺点之一是它们在数据从一个线程传递到另一个线程的应用程序中不是很有用(InheritableThreadLocal 有时会有所帮助,但并非总是如此)。在这种情况下,Spring 的作用域 bean 也会失败,因为它们是使用 ThreadLocal 实现的。

So to advise on an approach, if you have a Spring webapp, with Spring beans that want access to objects that are specific to the current request thread, then I'd advise using request-scoped beans. If you need to access those objects beyond the control of Spring's beans, then ThreadLocal may be easier, although I'd try to make things work with scoped beans as much as possible.

因此,为了建议一种方法,如果您有一个 Spring webapp,并且 Spring bean 想要访问特定于当前请求线程的对象,那么我建议使用请求范围的 bean。如果您需要访问超出 Spring bean 控制范围的那些对象,那么 ThreadLocal 可能会更容易,尽管我会尽量使事情与作用域 bean 一起工作。

回答by Bozho

Spring uses ThreadLocals internally, and there is nothing wrong with having them as infrastructure. However, you should avoid them for business logic.

SpringThreadLocal在内部使用s ,将它们作为基础设施并没有错。但是,对于业务逻辑,您应该避免使用它们。

If you really need them, and the requestscope doesn't suit you (for some unforeseeable reason), then I'd advice defining a custom Scope, using ThreadLocalinternally, thus hiding it from your business-logic.

如果您真的需要它们,并且request范围不适合您(出于某些不可预见的原因),那么我建议定义一个 custom Scope,在ThreadLocal内部使用,从而将其隐藏在您的业务逻辑中。

回答by Zeus

ThreadLocals work great when you have common code that is handled by JMS, Queues and http requests. Request scoped values do not work in all the scenarios.

当您拥有由 JMS、队列和 http 请求处理的公共代码时,ThreadLocals 工作得很好。请求范围值并不适用于所有场景。

One important thing to remember when using threadLocals is that threads will be re-usedby the server container, so are the local variable values if something is set on it, if you have values that needs to be reset, use servlet filters/AOP proxy objects on the controllers/jms listeners to clear the values just before it invokes the business logic, or else you could end up debugging very hard to reproduce type of issues .

使用 threadLocals 时要记住的一件重要事情是服务器容器将重新使用线程,因此如果在其上设置了某些内容,则本地变量值也是如此,如果您有需要重置的值,请​​使用 servlet 过滤器/AOP 代理控制器/jms 侦听器上的对象在它调用业务逻辑之前清除值,否则您最终可能会很难调试以重现类型的问题。