Java Future-Spring身份验证在AuditorAware中为空
这是我的设想: 我的应用程序已启用Mongo审核,并带有一个自定义AuditorAware,可从Java Future-Spring身份验证在AuditorAware中为空,java,spring,mongodb,spring-security,completable-future,Java,Spring,Mongodb,Spring Security,Completable Future,这是我的设想: 我的应用程序已启用Mongo审核,并带有一个自定义AuditorAware,可从SecurityContext获取当前用户。这在同步方法中效果很好,并且成功保存了当前的auditor,但是我无法使它在@Async方法中正常工作 我有一个异步方法(CompletableFuture),可以对我的Mongo数据库进行一些更新。调用AuditorAware.getCurrentAuditor()时,不存在身份验证信息,并且我无法获取当前审计员(SecurityContextHolder
SecurityContext
获取当前用户。这在同步方法中效果很好,并且成功保存了当前的auditor,但是我无法使它在@Async
方法中正常工作
我有一个异步方法(CompletableFuture
),可以对我的Mongo数据库进行一些更新。调用AuditorAware.getCurrentAuditor()
时,不存在身份验证信息,并且我无法获取当前审计员(SecurityContextHolder.getContext().getAuthentication()
返回null
)
我正在使用一个DelegatingSecurityContextAsyncTaskExecutor
:
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(100);
executor.setQueueCapacity(200);
executor.initialize();
return new DelegatingSecurityContextAsyncTaskExecutor(executor);
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new ItacaExceptionHandler();
}
}
如何使其正常工作?Spring安全上下文始终绑定到Threadlocal 您可能需要为安全上下文另外设置MODE_INHERITABLETHREADLOCAL
@Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class);
methodInvokingFactoryBean.setTargetMethod("setStrategyName");
methodInvokingFactoryBean.setArguments(new String[]{SecurityContextHolder.MODE_INHERITABLETHREADLOCAL});
return methodInvokingFactoryBean;
}
在上的评论之后,您似乎没有正确地将CompletableFuture
与Spring@Async
一起使用
如果您使用启动任务,例如,它们将由执行,而不是您为@Async
配置的任务。您可以使用将执行器
作为参数的重载,但它实际上不会受益于@Async
的优点
相反,您应该做的是让Spring处理任务执行,并简单地返回一个已完成的可完成的未来
,如下所示:
@Async
public CompletableFuture<String> someMethod() {
// do some computation, but return a completed future
return CompletableFuture.completedFuture("Hello World!");
}
@Async
公共CompletableFuture-someMethod(){
//做一些计算,但返回一个完整的未来
返回CompletableFuture.completedFuture(“你好,世界!”);
}
Spring随后将在配置的执行器中异步执行您的方法,同时立即返回一个CompletableFuture
,当您的方法返回时将完成该操作
如果您使用的是Spring 4.2或更高版本。否则需要一些实现,但这将是另一个问题。根据,在使用重复使用线程的执行器时,使用
模式\u INHERITABLETHREADLOCAL
将不起作用(仅在创建线程时才会发生继承)。但是,它应该与DelegatingSecurityContextAsyncTaskExecutor
一起使用@s1moner3d您确定您在问题中展示的遗嘱执行人确实被使用了吗CompletableFuture
默认情况下使用公共ForkJoinPool。@DiDierrl如何检查?我确信它是在启动时实例化的time@DidierL我查过了,你完全正确!它使用ForkJoinPool
。如何使用DelegatingSecurityContextAsyncTaskExecutor
?@s1moner3d我想最简单的方法是调试@Async
方法之一,查看它在哪个线程中运行,或者在该方法中打印thread.getCurrentThread().getName()
。@s1moner3d这取决于如何创建可完成的未来。大多数方法都有带有Executor
参数的重载,但是如果您依赖于Spring@Async
,我想您有一个工厂来处理它们的创建,所以应该在那里完成。
@Async
public CompletableFuture<String> someMethod() {
// do some computation, but return a completed future
return CompletableFuture.completedFuture("Hello World!");
}