Why is Spring JPA deleting the ServletRequestAttributes?
Asked Answered
I

0

0

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?

Icefall answered 11/6, 2022 at 23:24 Comment(4)
It's really weird. I can suggest to store this token in the ThreadLocal variable as a workaround.Ahem
Another answer in that thread says that the answer you linked was not working and offers an explanation why the attributes are gone. It may be working without JPA because the async task is able to finish before the original request has, but accessing the database may slow it down enough to finish after the request is done and attributes are gone. Either way, it seems like that answer isn't actually a reliable way to do this.Simmon
@Knox, if you put this comment into an answer, I will accept it.Icefall
baeldung.com/spring-security-async-principal-propagationIcefall

© 2022 - 2025 — McMap. All rights reserved.