I'm using Spring's @EnableAsync
feature to execute methods asynchronously. For security I'm using Apache Shiro. In the code that is executed asynchronously I need to have access to the Shiro subject that was attached to the thread that triggered the async call.
Shiro supports using an existing subject in a different thread by associating the subject with the Callable
that is to be executed on the different thread (see here):
Subject.associateWith(Callable)
Unfortunately I don't have direct access to the Callable
as this stuff is encapsulated by Spring. I found that I would need to extend Spring's AnnotationAsyncExecutionInterceptor
to associate my subject with the created Callable
(that's the easy part).
By problem is now how to make Spring use my custom AnnotationAsyncExecutionInterceptor
instead of the default one. The default one is created in AsyncAnnotationAdvisor
and AsyncAnnotationBeanPostProcessor
. I can of course extend these classes as well, but this only shifts to problem as I need the make Spring use my extended classes again.
Is there any way to achieve what I want?
I would be fine with adding a new custom async annotation as well. But I don't think this would be much of a help.
UPDATE:
Actually my finding that AnnotationAsyncExecutionInterceptor
would need to be customized was wrong. By chance I stumbled across org.apache.shiro.concurrent.SubjectAwareExecutorService
which does pretty exactly what I want and made me think I could simply provide a custom executor instead of customizing the interceptor. See my answer for details.
I managed to achieve what I want - shiro subject is automatically bound and unbound to tasks that are executed by spring's async support - by providing an extended version of the
ThreadPoolTaskExecutor
:To make spring use this executor I had to implement an
AsyncConfigurer
that returns my custom executor:With this change the parent Thread's subject will automatically be available in methods that are annotated with
@Async
and - probably even more important - the subject will be de-attached from the thread after execution of the asynchronous method.