MDC, Thread Pools & Spring request scope beans

Bhanu Bobbali
3 min readJan 29, 2021

As developers, we tend to first get things working and then suffer the drawbacks of the approaches we have chosen. We try out multiple ways to achieve the same thing and more often than not its always the most used and the dumbest way we settle to at last. Here goes one such experience of mine

For the sake of context let's understand a bit about MDC, Thread local, ThreadPool and Spring request scoped bean and what they mean to each other

A Mapped Diagnostic Context, or MDC in short, is an instrument for distinguishing interleaved log output from different sources. Log output is typically interleaved when a server handles multiple clients near-simultaneously. A child thread automatically inherits a copy of the mapped diagnostic context of its parent.

MDC internally uses a thread-local The TheadLocal construct allows us to store data that will be accessible only by a specific thread.

A Thread pool reuses previously created threads to execute current tasks and offers a solution to the problem of thread cycle overhead and resource thrashing

Whenever a new thread is created MDC gets inherited from its parent thread but in a thread pool, the idea is to reuse already created threads. So thread pool execution triggered from any other thread can have a different MDC as the thread is actually created from a different parent thread.

Now let's see what a spring request bean scope is ….

Spring version 3.2+ registers request scope & session scope by default. So no need to enable request scope or session scope. By defining any bean as request scope the bean will be created & destroyed with-in the request context.

How is this different from using a simple thread local?

Absolutely no difference if threads are getting created & destroyed after every request but in most enterprise applications like mine we use a thread pool where we intend to reuse the threads. So its the application developer’s responsibility to clear the thread-local whereas in request scoped bean Spring essentially takes care of that for us.

So what’s the catch here? How does spring know when the request ends? what is the life cycle of request scope beans?

In the default implementation of a request scope Spring stores the requests beans in a thread-local whose data gets cleared at the end of a request. But what happens if a child thread tries to access this bean?

As long as the child thread is created from the main thread and not reused thread-local data does get copied. But in thread pools where we reuse the threads, there is a good chance that the request scoped bean will not be available.
A better way to avoid these issues with thread local across thread pools would be by writing custom implementations of thread pool executors/ Request beans
ThreadPoolExectuor provides Implementation to be passed for the Callable through which we can override the MDC data on every execution of the thread.
We can write custom implementations of spring request beans by implementing RequestAttribute interfacing and registering as a Custom Scope.

There are a lot of trade-offs in all these core spring entities. But I finally decided to go with the simplest way of passing context data in all method variables and write decent unit tests on it and just get it over with. Turns out the easiest and the simple way possible is the best of all (more often than not that is how it is)………

--

--