Interceptor in Spring 5 WebFlux

2020-06-21 00:17发布

问题:

I am using Spring WebFlux in my project. I want to create an interceptor to calculate the time taken by each API. In Spring MVC we have HandlerInterceptor which is not present in spring-boot-starter-webflux. I tried adding spring-boot-starter-web and wrote my interceptor but it didn't work. Here is the code:

@Component
public class TimeInterceptor implements HandlerInterceptor {

public static Logger logger = Logger.getLogger(TimeInterceptor.class);

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    long startTime = System.currentTimeMillis();
    request.setAttribute("startTime", startTime);
    return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    long totaltime = System.currentTimeMillis() - (long) request.getAttribute("startTime");
    request.setAttribute("totaltime", totaltime);
    logger.info("Logging total time" + totaltime);

}
...
...

I want to add similar functionality to my application and intercept time taken by each call.

Thanks in advance.

回答1:

There is no concept of HandlerInterceptor in Spring WebFlux, but you can use your own WebFilter for that instead.

The feature you're describing sounds a lot like the metrics support provided by Actuator and Micrometer. If you'd like to try it:

  1. Add the actuator dependency to your project
  2. Expose the relevant endpoints (here, metrics)
  3. Go to "/actuator/metrics and select the metric for server HTTP requests (see the reference documentation).

Micrometer offers way more and helps you to get your metrics right, like: taking into account GC pauses when measuring time, providing histograms/percentiles/..., and more.

Note: adding spring-boot-starter-web to your application will turn it into a Spring MVC application.



回答2:

If you want to handle a request when it starts and when it completes, you can use WebFilter.

Try something like this

@Component
public class CustomWebFilter implements WebFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        long startTime = System.currentTimeMillis();
        return chain.filter(exchange).doFinally(signalType -> {
            long totalTime = System.currentTimeMillis() - startTime;
            exchange.getAttributes().put("totalTime", totalTime);
            System.out.println(totalTime);
        });
    }
}

When request processing is start all defined filters called. Mono is returned from filter. It indicates when request processing is complete.