我想從Spring上下文的用戶在應用程序春天如下:獲得用戶
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
的問題是,這些方法是異步的,與註解@Async:
@Service
@Transactional
public class FooServiceImpl implements FooService {
@Async("asyncExecutor")
public void fooMethod(String bar) {
System.out.println("Foo: " + bar);
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
}
}
問題是異步方法在另一個上下文中的另一個線程中運行。 我嘗試過使用SecurityContextDelegationAsyncTaskExecutor。用戶傳播到異步方法,但如果我註銷,異步方法中的用戶爲空。這是我的代碼:
@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {
@Override
@Bean(name = "asyncExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(1);
executor.setThreadGroupName("MyCustomExecutor");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setBeanName("asyncExecutor");
executor.initialize();
return new DelegatingSecurityContextAsyncTaskExecutor(executor);
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new CustomAsyncExceptionHandler();
}
}
我也用一個ThreadPoolTaskExecutor類和設置安全春用「MODE_INHERITABLETHREADLOCAL」的背景。但結果是一樣的。如果我登錄到應用程序,用戶不爲空。如果我沒有記錄該用戶爲空。我真的希望運行該方法的用戶,而不是當前用戶登錄。我的代碼:
@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {
@Override
@Bean(name = "asyncExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(1);
executor.setThreadGroupName("MyCustomExecutor");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setBeanName("asyncExecutor");
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new CustomAsyncExceptionHandler();
}
}
@Configuration
@ComponentScan(basePackageClasses = Application.class, includeFilters = @Filter({Controller.class}), useDefaultFilters = true)
public class MvcConfiguration extends WebMvcConfigurationSupport {
//others beans
@Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class);
methodInvokingFactoryBean.setTargetMethod("setStrategyName");
methodInvokingFactoryBean.setArguments(new String[]{SecurityContextHolder.MODE_INHERITABLETHREADLOCAL});
return methodInvokingFactoryBean;
}
}
最後,我發現這個職位Spring Security and @Async。我嘗試使用CustomThreadPoolTaskExecutor重寫execute方法。但是這個方法永遠不會運行運行ThreadPoolTaskExecutor類的方法是:
<T> Future<T> submit(Callable<T> task)
我的代碼:
@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {
@Override
@Bean(name = "asyncExecutor")
public Executor getAsyncExecutor() {
CustomThreadPoolTaskExecutor executor = new CustomThreadPoolTaskExecutor();
executor.setMaxPoolSize(1);
executor.setThreadGroupName("MyCustomExecutor");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setBeanName("asyncExecutor");
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new CustomAsyncExceptionHandler();
}
}
public class CustomThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
private static final long serialVersionUID = 1L;
@Override
public void execute(final Runnable r) {
final Authentication a = SecurityContextHolder.getContext().getAuthentication();
super.execute(new Runnable() {
@Override
public void run() {
try {
SecurityContext ctx = SecurityContextHolder.createEmptyContext();
ctx.setAuthentication(a);
SecurityContextHolder.setContext(ctx);
r.run();
} finally {
SecurityContextHolder.clearContext();
}
}
});
}
}
我定製的執行方法永遠不會運行。 我在自定義ThreadPoolTaskExecutor中做錯了什麼?獲取運行異步方法的用戶的其他方法。沒有上下文的當前用戶。
在我的問題我用DelegatingSecurityContextAsyncTaskExecutor了。謝謝你的回答。我的最終解決方案是將用戶作爲參數傳遞。 – oscar