Log SpringBoot Controllers, Track Request Time, Dynamically Register Resources

This guide shows how to output all SpringBoot controller endpoints via logging configuration, measure complete request processing time by listening to ServletRequestHandledEvent, dynamically register and deregister static resources at runtime, and execute custom logic after the application context refreshes using ContextRefreshedEvent.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Log SpringBoot Controllers, Track Request Time, Dynamically Register Resources

Environment: SpringBoot 3.2.5

1. Output All Controller Interface Information

Sometimes you want to print all controller endpoints when the application starts to get a clear overview and speed up troubleshooting.

Method 1

logging:
  level:
    web: trace

Result:

This prints a lot of logs because it enables the entire web logging group, not just controller information.

Method 2

logging:
  level:
    '[_org.springframework.web.servlet.HandlerMapping.Mappings]': debug

Result:

Only controller mappings are logged, while other logs keep their default level.

2. Measure Interface Call Duration

Without third‑party tools, a common approach is to record timestamps at the start and end of a handler:

@GetMapping("/time")
public Object time() throws Exception {
  Instant startTime = Instant.now();
  // TODO: business logic
  System.err.printf("Interface duration: %d ms%n", Duration.between(startTime, Instant.now()).toMillis());
  return "take time";
}

For a more accurate measurement that includes the whole request lifecycle (handler mapping, interceptors, etc.), listen to ServletRequestHandledEvent:

@Component
public class TakeTimeCountListener implements ApplicationListener<ServletRequestHandledEvent> {

  @Override
  public void onApplicationEvent(ServletRequestHandledEvent event) {
    Throwable failureCause = event.getFailureCause();
    if (failureCause != null) {
      System.err.printf("Error cause: %s%n", failureCause.getMessage());
    }
    System.err.printf("Client: %s, URL: %s, Method: %s, Duration: %d ms%n",
        event.getClientAddress(),
        event.getRequestUrl(),
        event.getMethod(),
        event.getProcessingTimeMillis());
  }
}

Listening to this event provides client address, request URL, HTTP method, and the exact processing time ( ProcessingTimeMillis).

3. Dynamically Register Static Resources

Static resources are usually configured in application.yml or via a WebMvcConfigurer implementation:

spring:
  web:
    resources:
      static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/

You can add a file‑system directory:

spring:
  web:
    resources:
      static-locations: ..., file:///d:/images/

Or register them programmatically (requires a restart):

public class WebConfig implements WebMvcConfigurer {
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/images/**").addResourceLocations("file:///d:\\images\\");
  }
}

To make the registration effective at runtime without restarting, use a dynamic approach:

@RestController
public class RegController {
  @Resource
  private SimpleUrlHandlerMapping resourceHandlerMapping;
  @Resource
  private ApplicationContext context;

  // Example: requestURI=/s/**, path=d:/images/
  @GetMapping("")
  public Object reg(String requestURI, String path) throws Throwable {
    ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
    handler.setLocations(List.of(new FileSystemResource(path)));
    handler.setApplicationContext(context);
    handler.afterPropertiesSet();
    resourceHandlerMapping.registerHandler(requestURI, handler);
    return "register success";
  }
}

This method also allows you to deregister resources when needed.

4. Perform Actions After Container Startup

To run custom logic after the Spring context has fully refreshed, listen to ContextRefreshedEvent (triggered at the end of the refresh method):

@Component
public class ContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> {

  @Override
  public void onApplicationEvent(ContextRefreshedEvent event) {
    System.out.println("Context refresh completed...");
    // TODO: custom logic here
  }
}

Implement your own processing inside the listener.

End of article.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

SpringBootevent-listenerRequest TimingDynamic Resources
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.