1、作用
- 是为了接口返回异步对象,然后执行异步任务也能通过SecurityContextHolder获取SecurityContext
- 比如说返回值是WebAsyncTask的时候
2、WebAsyncManagerIntegrationFilter
- 源码很短就是在WebAsyncManager中注册了SecurityContextCallableProcessingInterceptor
public final class WebAsyncManagerIntegrationFilter extends OncePerRequestFilter {
private static final Object CALLABLE_INTERCEPTOR_KEY = new Object();
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
SecurityContextCallableProcessingInterceptor securityProcessingInterceptor = (SecurityContextCallableProcessingInterceptor) asyncManager
.getCallableInterceptor(CALLABLE_INTERCEPTOR_KEY);
if (securityProcessingInterceptor == null) {
asyncManager.registerCallableInterceptor(CALLABLE_INTERCEPTOR_KEY,
new SecurityContextCallableProcessingInterceptor());
}
filterChain.doFilter(request, response);
}
}
- WebAsyncManagerIntegrationFilter没有对应的配置类,是在获取HttpSecurity的时候,默认注册的拦截器
3、AsyncTaskMethodReturnValueHandler
- 当接口返回值是WebAsyncTask的时候,SpringMVC会适配AsyncTaskMethodReturnValueHandler作为返回值处理器
- 可以看出就是调用了WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer);来处理
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue == null) {
mavContainer.setRequestHandled(true);
return;
}
WebAsyncTask<?> webAsyncTask = (WebAsyncTask<?>) returnValue;
if (this.beanFactory != null) {
webAsyncTask.setBeanFactory(this.beanFactory);
}
WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer);
}
- 而startCallableProcessing方法中就会提取在WebAsyncManager中注册的拦截器,组成拦截器链然后在异步任务的前后执行对应的回调方法
- 而在WebAsyncManagerIntegrationFilter中注册的SecurityContextCallableProcessingInterceptor就会在这里面执行
4、SecurityContextCallableProcessingInterceptor
public final class SecurityContextCallableProcessingInterceptor extends CallableProcessingInterceptorAdapter {
private volatile SecurityContext securityContext;
public SecurityContextCallableProcessingInterceptor() {
}
public SecurityContextCallableProcessingInterceptor(SecurityContext securityContext) {
Assert.notNull(securityContext, "securityContext cannot be null");
setSecurityContext(securityContext);
}
@Override
public <T> void beforeConcurrentHandling(NativeWebRequest request, Callable<T> task) {
if (this.securityContext == null) {
setSecurityContext(SecurityContextHolder.getContext());
}
}
@Override
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
SecurityContextHolder.setContext(this.securityContext);
}
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
SecurityContextHolder.clearContext();
}
private void setSecurityContext(SecurityContext securityContext) {
this.securityContext = securityContext;
}
}
- 其原理很简单,当还在Tomcat线程的时候,将SecurityContext保存起来,然后进入异步线程后又取出来就行了
- 而SecurityContext的存储策略有四种

- 默认是ThreadLocalSecurityContextHolderStrategy,也就是将SecurityContext保存在Thread的threadLocals中