In order to copy the Spring RequestAttributes
into an @Async
thread, I have implemented a TaskDecorator
bean, based on How to enable request scope in async task executor.
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public TaskDecorator taskDecorator() {
return runnable -> {
RequestAttributes context = RequestContextHolder.getRequestAttributes();
return () -> {
try {
RequestContextHolder.setRequestAttributes(context);
runnable.run();
} finally {
RequestContextHolder.resetRequestAttributes();
}
};
};
}
}
This approach works well, until JPA is added to the @Async
thread. I have an asynchronous service method, invoked by a controller that takes an authorization header.
@Async
public void logAuthToken() {
System.out.println(">>> authToken before Repo call: " + getAuthToken());
repo.findAll();
System.out.println(">>> authToken after Repo call: " + getAuthToken());
}
private String getAuthToken() {
return Optional.ofNullable(RequestContextHolder.getRequestAttributes())
.map(ServletRequestAttributes.class::cast)
.map(ServletRequestAttributes::getRequest)
.map(request -> request.getHeader(AUTHORIZATION))
.orElse("No Authorization Token in this Context!");
}
The TaskDecorator
successfully populates the RequestAttributes
when the thread starts; but after a JPA call, the attributes are gone.
>>> authToken before Repo call: my-auth-token
>>> authToken after Repo call: No Authorization Token in this Context!
The repo is an empty CrudRepository
interface. A full working example is in github.
Why is JPA apparently deleting the RequestAttributes
and how can I prevent it from doing that?
ThreadLocal
variable as a workaround. – Ahem