Customize/Extend Spring 对 shiro 的 @Async 支持
Customize/Extend Spring's @Async support for shiro
我正在使用 Spring 的 @EnableAsync
功能来异步执行方法。为了安全起见,我使用的是 Apache Shiro。在异步执行的代码中,我需要访问附加到触发异步调用的线程的 Shiro 主题。
Shiro 支持在不同线程中使用现有主题,方法是将主题与要在不同线程上执行的 Callable
关联(参见 here):
Subject.associateWith(Callable)
不幸的是,我无法直接访问 Callable
,因为这些东西被 Spring 封装了。我发现我需要扩展 Spring 的 AnnotationAsyncExecutionInterceptor
以将我的主题与创建的 Callable
相关联(这是简单的部分)。
现在的问题是如何让 Spring 使用我的自定义 AnnotationAsyncExecutionInterceptor
而不是默认的。默认的是在 AsyncAnnotationAdvisor
和 AsyncAnnotationBeanPostProcessor
中创建的。我当然也可以扩展这些 类,但这只会转移到问题,因为我需要 make Spring 再次使用我的扩展 类。
有什么方法可以达到我想要的效果吗?
我也愿意添加新的自定义异步注释。但我认为这不会有太大帮助。
更新:
实际上我发现 AnnotationAsyncExecutionInterceptor
需要定制是错误的。一次偶然的机会,我偶然发现了 org.apache.shiro.concurrent.SubjectAwareExecutorService
,它完全符合我的要求,这让我觉得我可以简单地提供一个自定义执行器而不是自定义拦截器。详情见我的回答。
我设法实现了我想要的 - shiro 主题自动绑定和解除绑定到由 spring 的异步支持执行的任务 - 通过提供 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
,returns 我的自定义执行器:
@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
注释的方法中可用,并且 - 可能更重要 - 主题将在执行异步方法后从线程中解除附加.
我正在使用 Spring 的 @EnableAsync
功能来异步执行方法。为了安全起见,我使用的是 Apache Shiro。在异步执行的代码中,我需要访问附加到触发异步调用的线程的 Shiro 主题。
Shiro 支持在不同线程中使用现有主题,方法是将主题与要在不同线程上执行的 Callable
关联(参见 here):
Subject.associateWith(Callable)
不幸的是,我无法直接访问 Callable
,因为这些东西被 Spring 封装了。我发现我需要扩展 Spring 的 AnnotationAsyncExecutionInterceptor
以将我的主题与创建的 Callable
相关联(这是简单的部分)。
现在的问题是如何让 Spring 使用我的自定义 AnnotationAsyncExecutionInterceptor
而不是默认的。默认的是在 AsyncAnnotationAdvisor
和 AsyncAnnotationBeanPostProcessor
中创建的。我当然也可以扩展这些 类,但这只会转移到问题,因为我需要 make Spring 再次使用我的扩展 类。
有什么方法可以达到我想要的效果吗?
我也愿意添加新的自定义异步注释。但我认为这不会有太大帮助。
更新:
实际上我发现 AnnotationAsyncExecutionInterceptor
需要定制是错误的。一次偶然的机会,我偶然发现了 org.apache.shiro.concurrent.SubjectAwareExecutorService
,它完全符合我的要求,这让我觉得我可以简单地提供一个自定义执行器而不是自定义拦截器。详情见我的回答。
我设法实现了我想要的 - shiro 主题自动绑定和解除绑定到由 spring 的异步支持执行的任务 - 通过提供 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
,returns 我的自定义执行器:
@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
注释的方法中可用,并且 - 可能更重要 - 主题将在执行异步方法后从线程中解除附加.