开发者

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

开发者 https://www.devze.com 2022-12-19 05:33 出处:网络
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.

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.

In my spring DI tomcat web-app, it seems to counter this problem if I j开发者_StackOverflow社区ust 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.

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.

What are the advantages and disadvantages of this approach?


As @axtavt mentioned, request-scoped beans are 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.

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.

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.

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.


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

public interface UserName {
    ...
}

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


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

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


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.

One important thing to remember when using threadLocals is that threads will be re-used by 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 .

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号