自定义/扩展Spring对shiro的@Async支持 [英] Customize/Extend Spring's @Async support for shiro
问题描述
我正在使用Spring的 @EnableAsync
功能异步执行方法.为了安全起见,我使用的是Apache Shiro.在异步执行的代码中,我需要访问附加到触发异步调用的线程的Shiro主题.
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通过将主题与要在不同线程上执行的 Callable
关联起来,支持在不同线程中使用现有主题(请参阅
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)
不幸的是,我没有直接访问 Callable
的权限,因为这些东西是由Spring封装的.我发现我需要扩展Spring的 AnnotationAsyncExecutionInterceptor
,以将我的主题与创建的 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).
现在的问题是如何使Spring使用我的自定义 AnnotationAsyncExecutionInterceptor
而不是默认的.默认代码是在 AsyncAnnotationAdvisor
和 AsyncAnnotationBeanPostProcessor
中创建的.我当然也可以扩展这些类,但这只会引起问题,因为我需要让Spring再次使用扩展类.
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.
更新:实际上,我发现需要自定义 AnnotationAsyncExecutionInterceptor
是错误的.偶然地,我偶然发现了 org.apache.shiro.concurrent.SubjectAwareExecutorService
,它完全符合我的要求,并让我认为我可以简单地提供一个自定义执行器,而不是自定义拦截器.有关详细信息,请参见我的答案.
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.
推荐答案
我设法实现了我想要的-通过提供扩展版本的 ThreadPoolTaskExecutor
:
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
:
public class SubjectAwareTaskExecutor extends ThreadPoolTaskExecutor {
@Override
public void execute(final Runnable aTask) {
final Subject currentSubject = ThreadContext.getSubject();
if (currentSubject != null) {
super.execute(currentSubject.associateWith(aTask));
} else {
super.execute(aTask);
}
}
... // override the submit and submitListenable method accordingly
}
要使spring使用此执行器,我必须实现一个 AsyncConfigurer
,该返回器将返回我的自定义执行器:
To make spring use this executor I had to implement an AsyncConfigurer
that returns my custom executor:
@EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
final SubjectAwareTaskExecutor executor = new SubjectAwareTaskExecutor();
executor.setBeanName("async-executor");
executor.setCorePoolSize(10);
executor.setMaxPoolSize(10);
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
通过此更改,父线程的主题将自动在以 @Async
注释的方法中可用,并且-可能甚至更重要的是-执行该主题后,该主题将与线程分离.异步方法.
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.
这篇关于自定义/扩展Spring对shiro的@Async支持的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!