编写线程池的配置文件:
@Configuration
public class AsyncConfig {
@Bean(value = "otherThreadPool")
public AsyncTaskExecutor otherThreadPool() {
ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor();
//异步任务装饰器 异步线程池传递traceId
poolTaskExecutor.setTaskDecorator(new MdcTaskDecorator());
//核心线程数
poolTaskExecutor.setCorePoolSize(4);
//最大线程数
poolTaskExecutor.setMaxPoolSize(8);
//工作队列
poolTaskExecutor.setQueueCapacity(0);
poolTaskExecutor.setAwaitTerminationSeconds(10);
//拒绝策略
poolTaskExecutor.setRejectedExecutionHandler(RejectPolicy.ABORT.getValue());
//线程名称前缀
poolTaskExecutor.setThreadNamePrefix("just-test");
poolTaskExecutor.initialize();
return poolTaskExecutor;
}
}
异步任务装饰器:
/**
* 异步线程池传递traceId
*/
public class MdcTaskDecorator implements TaskDecorator {
private final static String TRACE_ID = "traceId";
/**
* 使异步线程池获得主线程的上下文
*
* @param runnable
* @return
*/
@Override
public Runnable decorate(Runnable runnable) {
Map<String, String> map = MDC.getCopyOfContextMap();
return () -> {
try {
if (CollectionUtil.isEmpty(map) || StringUtil.isBlank(map.get(TRACE_ID))) {
MDC.put(TRACE_ID, UUID.randomUUID().toString());
} else {
MDC.put(TRACE_ID, map.get(TRACE_ID));
}
runnable.run();
} finally {
MDC.clear();
}
};
}
}
编写全局拦截器:(为每一个请求都传递进去一个TraceId)
@Slf4j
public class TraceIdInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String traceId = UUID.randomUUID().toString().replaceAll("-", "");
log.info(traceId);
MDC.put("traceId", traceId);
response.setHeader("X-Trace-Id", traceId);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
MDC.clear();
}
}
将拦截器加入到容器中:
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TraceIdInterceptor())
.addPathPatterns("/**");
super.addInterceptors(registry);
}
}
logback-spring.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--定义日志的根路径 项目中value=Maven-SpringBoot/logs-->
<property name="LOGS" value="./logs"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%X{traceId}] - %d{HH:mm:ss.SSS} - [%thread] - %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOGS}/spring-boot.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天滚动生成一个日志文件 -->
<fileNamePattern>${LOGS}/spring-boot-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 日志文件保留天数 -->
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>[%X{traceId}] - %d{HH:mm:ss.SSS} - [%thread] - %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 日志级别 -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
测试类:
@RestController
@Slf4j
public class HelloController {
@Resource(name = "myThreadPool")
private AsyncTaskExecutor executor;
@GetMapping("/hi")
public String say() {
executor.execute(() -> {
for (int i = 0; i < 10; i++) {
log.info("当前打印的数字是:" + i);
}
});
return "hello,spring boot 3.1.1 and jdk17";
}
}
控制台的输出:
[2234e82e41514e84aa9f1de75bd64629] - 01:06:47.582 - [pool-2-thread-1] - INFO c.e.demo.controller.HelloController - 当前打印的数字是:0
[2234e82e41514e84aa9f1de75bd64629] - 01:06:47.582 - [pool-2-thread-1] - INFO c.e.demo.controller.HelloController - 当前打印的数字是:1
[2234e82e41514e84aa9f1de75bd64629] - 01:06:47.582 - [pool-2-thread-1] - INFO c.e.demo.controller.HelloController - 当前打印的数字是:2
[2234e82e41514e84aa9f1de75bd64629] - 01:06:47.582 - [pool-2-thread-1] - INFO c.e.demo.controller.HelloController - 当前打印的数字是:3
[2234e82e41514e84aa9f1de75bd64629] - 01:06:47.582 - [pool-2-thread-1] - INFO c.e.demo.controller.HelloController - 当前打印的数字是:4
[2234e82e41514e84aa9f1de75bd64629] - 01:06:47.582 - [pool-2-thread-1] - INFO c.e.demo.controller.HelloController - 当前打印的数字是:5
[2234e82e41514e84aa9f1de75bd64629] - 01:06:47.582 - [pool-2-thread-1] - INFO c.e.demo.controller.HelloController - 当前打印的数字是:6
[2234e82e41514e84aa9f1de75bd64629] - 01:06:47.582 - [pool-2-thread-1] - INFO c.e.demo.controller.HelloController - 当前打印的数字是:7
[2234e82e41514e84aa9f1de75bd64629] - 01:06:47.582 - [pool-2-thread-1] - INFO c.e.demo.controller.HelloController - 当前打印的数字是:8
[2234e82e41514e84aa9f1de75bd64629] - 01:06:47.582 - [pool-2-thread-1] - INFO c.e.demo.controller.HelloController - 当前打印的数字是:9