Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 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.

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?

like image 288
John Avatar asked Feb 07 '10 20:02

John


1 Answers

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.

like image 76
skaffman Avatar answered Oct 13 '22 02:10

skaffman