一、输出所有Controller接口信息

有时候我们需要在容器启动时能够打印出当前项目中的所有Controller接口信息。这样可以给我们提供一个清晰的项目接口概览,从而帮助我们更快的定位和解决可能出现的问题。

1.在配置文件加上以下配置

logging.level.web=trace

2.启动程序,查看控制台日志

我们当前项目的Controller接口如图所示:

SpringBoot开发的几个小技巧_注册

SpringBoot开发的几个小技巧_容器_02

二、统计接口调用耗时

一般我们在不借助第三方工具的情况下,打印接口耗时通常会在接口处理逻辑的开始和结束位置分别记录当前时间戳,然后计算时间差来获取耗时,如下示例:

package com.example.tcpclientdemo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.Duration;
import java.time.Instant;

/**
 * @author qx
 * @date 2024/7/4
 * @des
 */
@RestController
public class IndexController {

    @GetMapping("/index")
    public String testIndex() throws InterruptedException {
        Instant start = Instant.now();
        Thread.sleep(1000L);
        System.out.printf("接口耗时:%d毫秒", (Duration.between(start, Instant.now()).toMillis()));
        return "index success";
    }

}

执行程序:

接口耗时:1003毫秒

为了更准确地反应处整个请求处理过程的耗时,包括Spring框架根据请求查找对应的Controller、拦截器执行等操作,SpringMVC在这些过程执行完成后是发布了一个事件,我们可以通过监听该事件来获取整个请求生命周期的耗时,如下示例:

package com.example.tcpclientdemo.listener;

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.ServletRequestHandledEvent;

/**
 * @author qx
 * @date 2024/7/4
 * @des 耗时监听器
 */
@Component
public class CostTimeListener implements ApplicationListener<ServletRequestHandledEvent> {
    @Override
    public void onApplicationEvent(ServletRequestHandledEvent event) {
        Throwable failureCause = event.getFailureCause();
        if (failureCause != null) {
            System.err.printf("错误原因:%s%n", failureCause.getMessage());
        }
        System.err.printf("请求客户端地址:%s,请求URL:%s,请求Method:%s,请求耗时:%d%n", event.getClientAddress(), event.getRequestUrl(), event.getMethod(), event.getProcessingTimeMillis());
    }
}

启动程序进行测试:

SpringBoot开发的几个小技巧_容器_03

我们查看控制台的日志,日志如下:

接口耗时:1007毫秒请求客户端地址:0:0:0:0:0:0:0:1,请求URL:/index,请求Method:GET,请求耗时:1077

通过监听ServletRequestHandledEvent事件,可以有效的获取客户端地址,请求的URL等完整的信息,其中ProcessingTimeMillis属性反应的就是这个请求耗时情况。

三、动态注册静态资源

一般我们都是在配置文件或者自定义WebMvcConfigurer进行静态资源的配置和注册。

spring.web.resources.static-locatinotallow=classpath:/resources/,classpath:/static/,classpath:/public/

要想实时生效可以通过如下方式动态注册。

package com.example.tcpclientdemo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * @author qx
 * @date 2024/7/4
 * @des
 */
@RestController
public class TestController {

    @Resource
    private SimpleUrlHandlerMapping urlHandlerMapping;
    @Resource
    private ApplicationContext context;


    // 如:requestURI=/s/**, path=d:/images/
    @GetMapping("/test")
    public String toTest(String requestUrl, String path) {
        ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
        List<org.springframework.core.io.Resource> resourceList = new ArrayList<>();
        resourceList.add(new FileSystemResource(path));
        handler.setLocations(resourceList);
        handler.setApplicationContext(context);
        handler.afterPropertiesSet();
        urlHandlerMapping.registerHandler(requestUrl, handler);
        return "test success";
    }
}

四、容器启动时处理操作

当我们希望在Spring容器正确初始化加载完成后执行一些初始化操作,那么我们可以监听ContextRefreshedEvent事件。

package com.example.tcpclientdemo.listener;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

/**
 * @author qx
 * @date 2024/7/4
 * @des
 */
@Slf4j
@Component
public class ContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        log.info("上下文初始化完成....");
    }
}

执行程序:

SpringBoot开发的几个小技巧_容器_04