Tech and Media Labs
This site uses cookies to improve the user experience.




Injecting ThreadLocal Objects

Jakob Jenkov
Last update: 2016-05-20

It is possible to inject ThreadLocal objects from within Butterfly Container. This text describes how, and a few common use cases for injecting ThreadLocal objects.


ThreadLocal Revisited

First let's refresh what a ThreadLocal object is, and what it looks like. A ThreadLocal looks like this:

ThreadLocal threadLocal = new ThreadLocal();

When a thread wants to associate an object to itself, it can set that object into the ThreadLocal like this:

threadLocal.set(theObject);

The object can be obtained again like this:

Object theObject = threadLocal.get();

Different threads may set different objects on the same ThreadLocal instance, but they will not get mixed up. A thread calling get() will only get the object it had set itself by calling set().

Here is an example of a ThreadLocal object referenced from witin a container script:

//the ThreadLocal inside a class:

public class MyClass{
   public static final ThreadLocal threadLocal = new ThreadLocal();
}
/* the script referencing the ThreadLocal

myThreadLocal = * com.myapp.MyClass.threadLocal.get();

Now, whenever the factory myThreadLocal is referenced it will return whatever value is associated to the calling thread, inside the ThreadLocal inside MyClass. For instance, if a thread does this:

MyClass.threadLocal.set("A ThreadLocal String");

String string = (String) container.instance("myThreadLocal");

Then the value obtained from the container.instance("myThreadLocal") call will be the value the calling thread associated with itself, by calling MyClass.threadLocal.set(). In this case it will be the value "A ThreadLocal String".

You can also reference the myThreadLocal factory within the container script, like this:

myThreadLocal = * com.myapp.MyClass.threadLocal.get();
bean          = * com.myapp.MyBean(myThreadLocal);

Injecting ThreadLocal Locale's

ThreadLocal's can be used to associate a java.util.Locale with the calling thread. That is useful if you need to localize the dependencies for a component at instantiation time. You can read more about localization in the text Using BCS for Internationalization

Basically what you will do is call a ThreadLocal.set() method with the Locale to associate with the calling thread, before calling container.instance(). Then, by referencing that ThreadLocal from inside a container script you can inject that Locale into objects or use it as parameter to method calls. Here is how it looks:

public class MyClass{
 public static final ThreadLocal threadLocale = new ThreadLocal();

 public static Locale getLocale() {
  return (Locale) threadLocale.get();
 }
}
threadLocale = * com.myapp.MyClass.getLocale();
mybean       = * com.myapp.MyBean(threadLocale);
Locale locale = ... //obtain Locale for user.
MyClass.threadLocal.set(locale);

MyBean localizedBean = (MyBean) container.instance("mybean");

Notice how the Locale is not obtained by the ThreadLocal.get() method, but via the static method getLocale(). The reason for this is, that the ThreadLocal.get() returns Object. If you need to call Locale methods on the Locale you cannot do so unless Butterfly Container can determine that the returned object is a Locale. The getLocale() method functions as a cast from Object to its return value Locale, enabling the container to determine the type of the returned object (Locale).


Injecting ThreadLocal Request, Session etc. in Web Apps

It is also possible to associate an HTTP request object with the executing thread, thus making it possible for the container to inject the request object into instantiated beans. It is also possible to inject objects obtained from the request, like request parameters, the session object or the servlet context. Butterfly Web UI uses this method to make these objects available for injection.

Here is how that looks:

public class ControlServlet{
 public static final ThreadLocal threadRequest  = new ThreadLocal();
 public static final ThreadLocal threadResponse = new ThreadLocal();

 public static HttpServletRequest getRequest() {
  return (HttpServletRequest) threadRequest.get();
 }

 public static HttpServletResponse getResponse() {
  return (HttpServletResponse) threadResponse.get();
 }
}
request  = * com.jenkov.webui.ControlServlet.getRequest();
response = * com.jenkov.webui.ControlServlet.getResponse();
session  = * request.getSession();
servletContext = session.getServletContext();

mybean   = com.myapp.MyBean(session.getAttribute("someAttribute"));

Notice how the HttpServletRequest and HttpServletResponse are not obtained by the ThreadLocal.get() method, but via the static methods getRequest() and getResponse(). The reason for this is, that the ThreadLocal.get() returns Object. If you need to call HttpServletRequest methods on the request you cannot do so unless Butterfly Container can determine that the returned object is a HttpServletRequest. The getRequest() method functions as a cast from Object to its return value HttpServletRequest, enabling the container to determine the type of the returned object (HttpServletRequest). The same is true for the method getResponse().

Jakob Jenkov




Copyright  Jenkov Aps
Close TOC