Many applications need some kind of context propagation without explicitly passing context objects down the invocation stack. Context can contain data of logged in user, request data, performance data or some other required information. In most cases we need to propagate the context within one jvm instance and one thread. Like in every task in software development we have a variety of tools at our disposal to help us with the context propagation. This article will discuss some of them and give some hints on when to use each of them.

ThreadLocals

Most basic and well know context propagation tool is ThreadLocal and InheritableThreadLocal. Both of this classes use language features to propagate context. Thread local variables accessed by different threads return a copy of the variable for each thread. Inheritable thread locals expose this copy to threads spawned from parent thread. But when using ThreadLocal variables one must be aware of pitfall associated with using them:

  • Fail to remove thread local variable – these can happen when components that set ThreadLocal variable do not clean up after them selves in reliable way. Threads are pooled in most of web and application servers so these variables will remain associated with the treads and will be made available to other threads. The Classloader the loaded this application will not be garbage collected as there is a ‘live’ thread local reference associated with it. As a consequence application can suffer from memory leaks (both heap and perm gen) and heisenbugs.
  • Increase in complexity – Thread local variables should be used to pass context data. If they are used to pass arbitrary data complexity of application will increase.

Remember to clean up you thread locals after request processing is done!

TransactionSynchronisationRegistry

Another tool at our disposal is TransactionSynchonisationRegistry. This object is associated with a JTA transaction and allows us to put and get context objects from TransactionSynchronizationRegistry instance. Passing context objects using TransactionSynchronizationRegistry will work with different threads as long as they are associated with the same transaction. But semantically using this object for context propagation is not quite right and may conceive weird ideas about spanning transaction across all layers of application starting them at web layer when it’s no really needed.

  • Do not use TransactionSynchronizationRegistry when you have short span of transactions and you would need to make it longer to use TransactionSynchronizationRegistry
  • Think twice before using it as it is no meant to be application level context carrier
  • When you use TransactionSynchronizationRegistry with distributed transaction prefix your context keys to avoid key name collision with other apps

Here’s how to use it (@Resource is a Java EE annotation – code must be run inside a Java EE Container)

Setting context:

Getting context later in request processing pipeline:

Weblogic WorkContext

If you do not have transaction associated with every request being processed or transaction is not associated with request later in request processing and if you are fortunate to use Weblogic than you can use WorkContext. This patented feature allows for context propagation like TransactionSynchronizationRegistry but it does no require transaction context and can be propagated to other Weblogic cluster servers using variety of protocols including JMS, SOAP, thread and transaction to name a few, see PropagationMode for full list. There is a caveat – you must have a context key to get your context object. So what if you don’t have such an object passed on as a parameter? A solution might be to use a framework feature like RequestContextHolder or JAAS Security Context and use data passed in this context as a key, if request is processed in one thread. Another may be to use some request-unique data as key. But what if you use thread polls (or thread managers like WorkManagers on WLS)  and do some work in different threads that the one that is processing your request? If you can use Work Managers instead of Java SE thread pools then do it. Java EE apps should use managed thread pools, and Work Managers allow you to manage threads (Work Managers are NOT thread polls strictly, they are more like rule sests for Weblogic) – if you do so then WorkContext in propagation mode Work will be available in work instances executed by Work Managers. If you can’t use Work Managers then you should consider passing context data as a parameter to slave thread then.

Usage of this neat feature is described in this Oracle WLS docs.

  • WLS is necessary to use Work Context, you bind yourself to WLS using it – but you can shield yourself partially by extracting this feature into separate infrastructure service component (maybe a custom CDI scope).
  • Propagating context other than simple ones in propagation mode like SOAP most probably will result in lower performance – but we can use thread mode.
  • Keep in mind to use application prefix for WorkContext keys to prevent name collisions, if there is a possibility that mutliple apps will use this feature.
  • It is mostly useful if you want to send context data to some other app – so for mostly technical stuff, not business related.
  • It can be propagated between work instances in WLS

CDI

Last but not least. CDI is Java EE specification for dependcy injection and contextual data (Contexts and Dependency Injection). CDI, among other neat features, specifies well defined contextual lifecycle of CDI Beans in well defined scopes and way to inject them in managed beans. Since Java EE 7 CDI support is described in other specifications such as EJB and this gives solid foundations to build our apps on. Of course CDI was supported in Java EE 6 (EJB 3.1) but it was not properly described in specification and implementations of this support sometimes where not ideal. Using CDI we can inject beans in request, conversation, session or application  scope  and dependent pseudoscope and a possibility to add you own scopes. In order to use CDI to pass context data we need to use proper scope and inject our variable to Java EE container managed bean. Session and conversation contexts are available only when injection is made to a managed bean while processing servlet request. According to CDI spec request and application scoped will be available for web service invocations or ejb remote invocations (6.7.1 Request context lifecycle or CDI API), but actually in Weblogic 12C (12.1.3) it still does not work properly.

Here’s how to use it.

Context definition:

Setting context:

Getting context later in request processing pipeline:

Conclusions

In most cases ThreadLocal are sufficient, but in my opinion CDI will be a better solution soon for Java EE apps, and in some cases (like when your context does not start at some Web Service level) it is a neat feature now. In Spring you can have similar possibilities as you can have Request and session scope beans, with Spring Web Flow you can have conversation scope and flow scope beans. You can also create a custom scopes. I do not mention it here as its well documented in Spring docs and Spring itself uses ThreadLocals to achieve context propagation in many cases (see RequestContextHolder implementation).