14

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.

Serhii PovĂ­senko
  • 3,352
  • 1
  • 30
  • 48
Deepak Kumar
  • 1,669
  • 3
  • 16
  • 36

4 Answers4

14

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 starts all defined filters are called. Mono is returned from filter. It indicates when request processing is complete.

V. Kuznetsov
  • 609
  • 1
  • 7
  • 18
6

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.

Brian Clozel
  • 56,583
  • 15
  • 167
  • 176
1

Use the following project as dependency as jar / ant / maven / gradle

https://github.com/TurquoiseSpace/spring-webflux-http-interceptor

<dependency>
    <groupId>com.github.TurquoiseSpace</groupId>
    <artifactId>spring-webflux-http-interceptor</artifactId>
    <version>0.0.7</version>
</dependency>

It provides ReactiveApiInterceptor which is a custom implementation of WebFilter

Tyler2P
  • 2,324
  • 26
  • 22
  • 31
0

If required, you can override ReactiveApiInterceptor as well, to add your own custom logic, besides having the default logic, by calling

@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
    // Your custom implementation, when api is hit and the request lands
    super.filter(serverWebExchange, webFilterChain)
        .doFinally(signalType -> {
            // Your custom implementation, when request-response exchange gets completed
        });
}