I have a web application that has a Spring Integration logic running with it in a separated thread. The problem is that at some point my Spring Integration logic tries to us
For spring-boot 2.4 and spring framework 5, both of the RequestContextFilter
and RequestContextListener
did not work for me.
After digging into the code, I found the DispatcherServlet
will overwrite the inheritable
of RequestContextHolder
set by RequestContextFilter
or any one else, see DispatcherServlet.processRequest
and DispatcherServlet.initContextHolders
.
So the solution is quite simple, without any other components:
@Configuration
class whateverNameYouLike {
@Bean
DispatcherServlet dispatcherServlet() {
DispatcherServlet srvl = new DispatcherServlet();
srvl.setThreadContextInheritable(true);
return srvl;
}
}
But notice that the solution alone only applies to new threads created by the current request thread, not regarding to any thread pool.
For the thread pool cases, you can depend on an extra wraper class:
public class InheritableRequestContextTaskWrapper {
private Map parentMDC = MDC.getCopyOfContextMap();
private RequestAttributes parentAttrs = RequestContextHolder.currentRequestAttributes();
public Function lambda1(Function runnable) {
return t -> {
Map orinMDC = MDC.getCopyOfContextMap();
if (parentMDC == null) {
MDC.clear();
} else {
MDC.setContextMap(parentMDC);
}
RequestAttributes orinAttrs = null;
try {
orinAttrs = RequestContextHolder.currentRequestAttributes();
} catch (IllegalStateException e) {
}
RequestContextHolder.setRequestAttributes(parentAttrs, true);
try {
return runnable.apply(t);
} finally {
if (orinMDC == null) {
MDC.clear();
} else {
MDC.setContextMap(orinMDC);
}
if (orinAttrs == null) {
RequestContextHolder.resetRequestAttributes();
} else {
RequestContextHolder.setRequestAttributes(orinAttrs, true);
}
}
};
}
}
And then use it like this:
InheritableRequestContextTaskWrapper wrapper = new InheritableRequestContextTaskWrapper();
List res = pool.submit(() -> ids.parallelStream().map(
wrapper.lambda1((String id) -> {
try {
// do something and return the result string
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Error occurred in async tasks", e);
}
})).collect(Collectors.toList())).get();