2011-08-19 217 views
2

我在尝试将spring服务调用的一系列顺序转换为异步。SecurityContextHolder.getContext()使用@Async时的NPE

我已经用@Async注释了该方法,并添加了taskExecutor configuratinos。

我可以看到,该方法目前正在异步调用,但我有与SecurityContextHolder.getContext()引发此错误的问题:

java.util.concurrent.ExecutionException: java.lang.NullPointerException

会很感激任何见解。谢谢!

+0

请参阅http://stackoverflow.com/questions/3467918/how-to-set-up-spring-security-securitycontextholder-strategy – Ritesh

回答

6

SecurityContext存储在ThreadLocal中。所以如果你从一个没有设置它的新线程访问它,那么SecurityContext就是null。

更新:新增ThreadLocal的javadoc的链接

2

我找到了解决办法,切换到 “MODE_INHERITABLETHREADLOCA” 解决了我的问题startegy。

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> 
<property name="targetClass" value="org.springframework.security.core.context.SecurityContextHolder"/> 
<property name="targetMethod" value="setStrategyName"/> 
<property name="arguments"> 
    <list> 
     <value>MODE_INHERITABLETHREADLOCAL</value> 
    </list> 
</property> 
</bean> 
0

由于弹簧安全3.2有这个答案的末尾描述的一个很好的注解@AuthenticationPrincipal。当你使用Spring-Security> = 3.2时,这是最好的方法。你可以用各种方式注入它。欲了解更多信息look at this answer

0

如果您想要访问异步调用中的安全上下文,您可以实现上下文感知线程池执行器来存储安全上下文时创建像下面的线程。

public class CustomExecutor extends ThreadPoolTaskExecutor { @Override public <T> Future<T> submit(Callable<T> task) { return super.submit(new ScopeAwareCallable<T>(task, SecurityContextHolder.getContext())); } }

public class ScopeAwareCallable<T> implements Callable<T> { 

private Callable<T> callableTask; 
private SecurityContext securityContext; 

public ScopeAwareCallable(Callable<T> task, SecurityContext secContex) { 
    this.callableTask = task; 
    this.securityContext = secContex; 
} 

@Override 
public T call() throws Exception { 
    if(securityContext != null){ 
     SecurityContextHolder.setContext(securityContext); 
    } 
    try { 
     return callableTask.call(); 
    } 
    finally { 
     SecurityContextHolder.clearContext(); 
    } 
} 

}

配置这是在Spring配置你的任务执行。如果您使用Runnable而不是Callable,则可以重写支持Runnable执行的ThreadPoolTask​​Executor中的其他方法。