我应该将我的ThreadLocals放入弹簧注入的单例中吗?

Joh*_*ohn 14 java concurrency spring dependency-injection

有些人(例如在服务器端http://www.theserverside.com/news/thread.tss?thread_id=41473)建议使用ThreadLocal对象与使用全局变量一样糟糕.我想如果你把它们变成公共静态变量就行了.那么问题是很难分辨它的使用位置,改变的地方等等.

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

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

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

可能需要它的类看起来像这样:

@Service
public class addEntryTransaction {

    @Autowired
    Username username;

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

}
Run Code Online (Sandbox Code Playgroud)

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

这种方法有哪些优缺点?

ska*_*man 19

正如@axtavt所提到的,当你谈论Web应用程序时,请求范围的bean通常是ThreadLocals的一个更干净,更优雅的替代品.事实上,在封面下,Spring使用自己的ThreadLocal变量实现请求范围的bean(请参阅参考资料RequestContextHolder).ThreadLocal和scoped bean都提供了相同的基本优势 - 访问对象的能力,而无需通过调用堆栈手动传递它.

但是,有一种情况是ThreadLocal变量赢得了作用域bean,这是在你想要从Spring的bean生命周期之外访问对象的情况下.一个很好的例子是JSP taglib.Taglib实例由servlet容器控制,而不是Spring,因此不能参与Spring的IoC框架,因此不能与请求范围的bean(或任何其他bean)连接起来.但是,它们可以访问ThreadLocal变量.有很多方法,但有时ThreadLocals是最简单的方法.

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

因此,为了建议一种方法,如果你有一个Spring webapp,Spring bean需要访问特定于当前请求线程的对象,那么我建议使用请求范围的bean.如果你需要访问那些超出Spring bean控制范围的对象,那么ThreadLocal可能会更容易,尽管我会尝试尽可能地使用scoped bean.


axt*_*avt 11

如果使用Spring,则只需使用请求范围的bean而不是显式的ThreadLocals:

public interface UserName {
    ...
}

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


Boz*_*zho 6

Spring ThreadLocal在内部使用s,将它们作为基础结构没有任何问题.但是,您应该避免它们用于业务逻辑.

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