May 5th, 2012, 03:24 PM
Keeping threadlocal variables threw spring integration operations
In my application, i have few information in threadlocal variables of the main thread. I would like to access those variable in spring integration operations.
For example, in my context, each soap request i receive is tagged with a transaction id. I store this transaction id in ThreadLocal.
My main thread calls an interface which is a Spring integration gateway. This gateway splits the message, then aggregates it.
I would like to access my ThreadLocal variables in my spring integration beans. But the message has been splitted in many threads.
What is the best solution to store and access my main threadlocal variables in spring integration context ?
Thanks for your help,
May 7th, 2012, 12:28 PM
Are you using any Executor channels in the flow? If you are using DirectChannels, the invocations happen in the same thread and hence your thread local values will be accessible. Also i am assuming your flow where you expect the thread local values to be read is local to a VM and messages are not sent to remote systems.
If you are using executor channels in the flow, using InheritableThreadLocal instead of ThreadLocal should solve your problem. If you still face any problems please post you config if possible. That can help answer better.
Hope that helps.
May 7th, 2012, 12:36 PM
What Amol is saying is correct, however why are you using Thread local in the first place especially when utilizing messaging architecture? Why not pass the value as part of the message (e.g., some header)? Unless I am missing something it seems to be counterintuitive to the core principles of messaging where "the world is stateless since state is maintained by the message only". The messages that were created as a result of a split will retain all the headers but most importantly will allow your flow to extends beyond single thread or even singe JVM. That is what makes Messaging architecture the most flexible and extensible.
May 19th, 2012, 06:17 AM
Hi Amol and Oleg,
Thanks for your responses.
I have a monitoring component in my architecture. My architure uses Spring Integration as an option.
I use Spring Integration for specific needs such as splitting, aggregating... For basic stuffs, i keep coding with standard application layers (service, dao...) and ioc.
My monitoring component stores in ThreadLocal :
- a transaction id for the current request, opened on the first tracked layer and closed when this first tracked layer is finished
- time tracking for each layer matching patterns i defined (with aop)
The aim is to track information but also to hide this complexity to developers.
Adding transaction information in message would need the developer to add manually those information. It is the oposite of my initial goal but i'm going to consider it.
As i want to fully integrate Spring Integration in my archtecture, i would prefer to pass the ThreadLocal transaction information using InheritableThreadLocal. I'm going to try this.
Another way could be to know how Spring Integration retrieves a thread in ThreadPoolExectors and how it gives it back. I'd have a look on how to add an instruction to pass the root transaction information at thread retrieving phase and how to clear thos information at thread release.
Any idea about doing it ?
May 19th, 2012, 08:37 AM
Adding a header at the start of the flow with say the timestamp and reading it at the end of the flow would do the work too. This doesn't need the developers to be aware of anything. Its a one time activity like say adding a header enricher at the start of the flow. Can you provide more details about the level of monitoring you'll like to perform? Is it withing say the spring integration components in your flow too? There could possibly be a better mechanism too once you let us know your exact requirements.
May 19th, 2012, 12:45 PM
My component already exists. Here is a current usecase :
- in my spring configuration, i have an interceptor around different kind of layers (for example : *Server, * ServiceImpl, *Client, *Dao) using AOP around interceptors or Spring WS interceptors...
- at runtime, when a webservice server receives a request it looks at soap headers to find a transaction id. If no transaction Id exists, it generates a unique id and stores it in ThreadLocal. If transaction id header exists, it stores the transactionId in ThreadLocal. It also flags the start time of the process.
- the server calls a ServiceImpl class which is intercepted by my monitoring AOP proxy. This one retrieves the transaction ID and flag the start time of ServiceImpl process
- ServiceImpl calls a dao... It does the same as ServiceImpl
- When dao process is finished, aop interceptor flags the end time of dao process
- When ServiceImpl process is finished, aop interceptor flags the end time of ServiceImpl process
- When Server process is finished, Spring WS interceptor flags the end time of server process and as it was the first layer that created the transaction in the thread, i store times tracked on each layer in a database. I clear the ThreadLocal, removing transactionId.
==> Everything is fine while my request is kept in the same thread.
Now if i call an interface with spring integration @Gateway annotation in the previous process :
- my channel splits the message and send it to channels consumed by a service-activator.
- i put an interceptor around service-activator beans
- To manage splitted messages, it retrieves threads in Threads pool and send each message to service-activator on the associated thread
- at this phase, my interceptor doesn't know the transaction id of the main thread, so it creates a new transaction id... I would like to keep the main thread transaction id.
As you suggested, i tried to use InheritableThreadLocal instead of ThreadLocal in my component but the delegated thread didn"t get the parent threadlocal map. I guess we can explain it by the fact the delegated thread hadn't been created by the main thread but it had just been retrieved in a already created ThreadPool.