gpt4 book ai didi

java - Spring Boot 为返回 CompletionStage 的请求运行过滤器两次

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:27:03 26 4
gpt4 key购买 nike

我遇到了一个问题,当方法返回 CompletionStage 时,我的过滤器运行了两次。从关于 RequestMapping ( here ) 的文档中,它是受支持的返回值。

A CompletionStage (implemented by CompletableFuture for example) which the application uses to produce a return value in a separate thread of its own choosing, as an alternative to returning a Callable.

由于项目非常复杂,并发代码很多,所以我创建了一个新的简单的 spring-boot 项目。这是其中的(唯一) Controller :

@Controller
public class BaseController {
@RequestMapping("/hello")
@ResponseBody
public CompletionStage<String> world() {
return CompletableFuture.supplyAsync(() -> "Hello World");
}
}

还有一个过滤器:

@WebFilter
@Component
public class GenericLoggingFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;

System.out.println(httpServletRequest.getMethod() + " " +
httpServletRequest.getRequestURI());

chain.doFilter(request, response);
}
}

当我调用 curl http://localhost:8080/hello 时,它会在控制台上打印两次 GET/hello。当我更改 Controller 方法以返回 String 时:

@RequestMapping("/hello")
@ResponseBody
public String world() {
return "Hello World";
}

它只打印一次。即使我将其更改为没有真正的并发意义的 Callable 也会出现此行为(当然,spring 本身现在可能将其视为 Async 请求)。

因此,如果 spring 再次运行整个 web 堆栈以获得可用的请求上下文,即使这样也没有任何意义,因为以下原因:

@RequestMapping("/hello")
@ResponseBody
public CompletionStage<String> world() {
return CompletableFuture.supplyAsync(() -> {
System.out.println(RequestContextHolder.currentRequestAttributes());
return "Hello World";
});
}

抛出异常:IllegalStateException:未找到线程绑定(bind)请求...

令人惊讶的是,下面的方法有效:

@RequestMapping("/hello")
@ResponseBody
public Callable<String> world() {
return () -> {
System.out.println(RequestContextHolder.currentRequestAttributes());
return "Hello World";
};
}

所以,我不确定很多事情。

  1. 看起来 CallableCompletionStage 在执行线程的上下文中被区别对待。
  2. 如果是这样,那为什么我的过滤器在每种情况下都运行两次?如果过滤器的工作是设置某个特定于请求的上下文,那么在 CompletionStage 无论如何都不可访问的情况下再次运行它是没有意义的。
  3. 过滤器究竟以哪种方式运行两次?

最佳答案

请将 GenericFilterBean 替换为 OncePerRequestFilter

关于java - Spring Boot 为返回 CompletionStage 的请求运行过滤器两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42528473/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com