在 Spring Boot 中,继承的 ServletRquestAttributes 在子线程完成之前被标记为完成

Yon*_*qin 5 java spring-mvc spring-boot

我正在使用 SpringBoot 1.5.2 版本。我有一个异步 REST 调用,它会生成单独的 java 线程来完成长时间运行的作业。长时间运行的作业需要更新数据库表,我在其中配置了 Spring 审核 bean 以使用当前登录用户名更新表。我遇到的问题是:通过调用 setThreadContextInheritable(true) 启用可继承标志后,传递给执行长时间运行的数据库更新的子线程的 ServletRequestAttributes 对象在子线程完成其工作之前被标记为“非活动”,最终导致当审核 bean 尝试从 RequestContextHolder 中缓存的 ServletRequestAttributes 访问用户名时出错。

要打开可继承标志,请参阅Scope 'session' is not active for the current thread; IllegalStateException:未找到线程绑定请求

这是获取我到目前为止所拥有的内容的主要代码:

  1. 应用程序.java中
@Override
public Executor getAsyncExecutor() {
    SimpleAsyncTaskExecutor executor = new
        SimpleAsyncTaskExecutor(appProperties.threadNamePrefix);
    return executor;
}
@Bean
public ServletRegistrationBean registerAirportDispatchServlet() {
    DispatcherServlet dispatcherServlet = new DispatcherServlet();
    AnnotationConfigWebApplicationContext applicationContext =
        new AnnotationConfigWebApplicationContext();
    dispatcherServlet.setApplicationContext(applicationContext);
    dispatcherServlet.setThreadContextInheritable(true);
    ServletRegistrationBean servletRegistrationBean =
        new ServletRegistrationBean(dispatcherServlet, "/*");
    servletRegistrationBean.setName("AirportSCSDispacherServlet");
    return servletRegistrationBean;
}
@Bean
@Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public AccessToken getAccessToken() {
    RequestAttributes attribs =
        RequestContextHolder.getRequestAttributes();
    //do something with the attribs here...
    return token;
}
Run Code Online (Sandbox Code Playgroud)

是的,我必须注册我的 DispatcherServlet 并在那里设置标志,而不是使用 RequestContextFilter 和 RequestContextListener,因为沿着请求过滤的路径,DispatcherServlet 将可继承标志设置为 false,这将覆盖链中较早的 RequestContextFilter 和 RequestContextListener 设置的 true 标志。通过调试,我可以看出FrameworkServlet的processRequest()方法内部是DispatcherServlet的超类,它调用了requestAttributes.requestCompleted(); 在第989行,这个requestAttributes对象作为新生成的线程的继承属性保存在RequestContextHolder中,当新线程尝试获取AccessToken的这个属性时,Spring框架会抛出错误,因为它被标记为非活动状态。我已经尝试过 SESSION 范围,但它不起作用,因为我的 REST 调用不在会话中,我使用 Keycloak 进行身份验证,因此请求属性中包含字符串访问令牌。

我在这里问:有没有更好的办法让我可以保持这个继承的请求属性对象仍然处于活动状态?

小智 0

我遇到了完全相同的问题。我的应用程序正在启动一个异步线程,然后立即将 http 响应发送回客户端。由于当我尝试在异步线程中获取属性时我已经发送了响应,因此 requestActive 字段为false。这就是这个错误的原因。我们无法requestActive在外部设置该字段。Spring会根据http请求状态来处理该字段。