环境:SpringBoot 2.7.x/ 3.x,Java17;使用
application.yml+ JavaConfig; 包含:自定义业务线程池、HikariCP、Redis、Sentinel 熔断限流; 配套依赖 maven,代码可直接复制使用,注意根据业务调整参数。
一、Maven 依赖 pom.xml
<!-- SpringBoot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- HikariCP 数据库连接池(spring-boot-starter-jdbc自带) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- Sentinel 限流熔断 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2022.0.0.0</version>
</dependency>
<!-- 注解异步 @Async -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
二、application.yml 配置
spring:
# ========== HikariCP 数据库连接池 ==========
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/db_test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
hikari:
# 最小空闲连接
minimum-idle: 5
# 最大连接数,根据数据库能力设置,不要过大
maximum-pool-size: 15
# 空闲连接超时时间,毫秒
idle-timeout: 300000
# 连接最大生命周期,小于mysql wait_timeout
max-lifetime: 1800000
# 获取连接超时
connection-timeout: 3000
# 测试连接有效性sql
connection-test-query: SELECT 1
# ========== Redis 连接池配置 ==========
redis:
host: 127.0.0.1
port: 6379
password:
database: 0
timeout: 3000ms
lettuce:
pool:
max-active: 16
max-idle: 8
min-idle: 4
max-wait: 2000ms
# ========== Sentinel 限流熔断配置 ==========
spring.cloud.sentinel:
# sentinel控制台地址
transport:
dashboard: 127.0.0.1:8080
# 客户端端口,默认8719,占用则自动+1
port: 8719
# 开启Sentinel注解支持
web-context-unify: false
# 规则持久化到nacos,这里先注释;测试可内存模式
# datasource:
# flow:
# nacos:
# server-addr: 127.0.0.1:8848
# dataId: sentinel-flow-rules
# groupId: DEFAULT_GROUP
# rule-type: flow
# 自定义业务线程池配置(放到yml,方便外部调整参数)
biz:
thread-pool:
core-size: 8
max-size: 20
queue-capacity: 200
keep-alive-seconds: 60
thread-name-prefix: biz-async-
三、Java Config 配置类
1. 自定义业务线程池 ThreadPoolConfig.java
推荐业务单独线程池,和 Tomcat 线程隔离,禁止使用 Executors 创建; 用于
@Async("bizThreadPool")异步执行非主链路任务。
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@EnableAsync
public class ThreadPoolConfig {
@Value("${biz.thread-pool.core-size}")
private Integer coreSize;
@Value("${biz.thread-pool.max-size}")
private Integer maxSize;
@Value("${biz.thread-pool.queue-capacity}")
private Integer queueCapacity;
@Value("${biz.thread-pool.keep-alive-seconds}")
private Integer keepAliveSeconds;
@Value("${biz.thread-pool.thread-name-prefix}")
private String threadNamePrefix;
@Bean("bizThreadPool")
public Executor bizThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(coreSize);
// 最大线程数
executor.setMaxPoolSize(maxSize);
// 队列容量
executor.setQueueCapacity(queueCapacity);
// 线程空闲时间
executor.setKeepAliveSeconds(keepAliveSeconds);
// 线程名称前缀,方便日志排查
executor.setThreadNamePrefix(threadNamePrefix);
// 拒绝策略:调用者执行,不丢弃任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务完成再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
// 等待关闭超时时间
executor.setAwaitTerminationSeconds(30);
executor.initialize();
return executor;
}
}
使用示例:
@Async("bizThreadPool")
public void asyncSendLog(String content) {
// 非核心链路,异步执行
}
2. RedisTemplate 配置 RedisConfig.java
使用 String 序列化,避免默认 JDK 序列化带来的二进制乱码,减少存储空间; 可按需替换为 Protobuf 序列化。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
StringRedisSerializer stringSerializer = new StringRedisSerializer();
// key 序列化
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
// value 序列化
redisTemplate.setValueSerializer(stringSerializer);
redisTemplate.setHashValueSerializer(stringSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
3. Sentinel 全局异常处理器 SentinelExceptionHandler.java
捕获 Sentinel 限流、熔断异常,返回统一 JSON 响应; 配合注解
@SentinelResource使用。
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
response.setContentType("application/json;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
Map<String, Object> result = new HashMap<>();
if (e instanceof FlowException) {
result.put("code", 429);
result.put("msg", "请求过于频繁,请稍后重试");
} else if (e instanceof DegradeException) {
result.put("code", 503);
result.put("msg", "服务暂时不可用,已熔断");
} else {
result.put("code", 500);
result.put("msg", "服务访问受限");
}
PrintWriter writer = response.getWriter();
writer.write(objectMapper.writeValueAsString(result));
writer.flush();
writer.close();
}
}
Sentinel 注解使用示例
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@GetMapping("/api/test")
@SentinelResource(value = "api_test", blockHandler = "blockHandler", fallback = "fallback")
public String test() {
return "success";
}
// 限流/熔断触发
public String blockHandler(BlockException e) {
return "block";
}
// 业务异常降级
public String fallback() {
return "fallback";
}
}
四、参数调优建议(重点)
✅ HikariCP
maximum-pool-size:不要超过数据库实例最大连接数,单库一般 10~30;connection-timeout:3000ms,超过直接放弃获取连接,防止大量线程卡在获取连接;max-lifetime必须小于 mysqlwait_timeout(默认 28800 秒)。
✅ Redis Lettuce
lettuce 是线程安全,不需要像 jedis 每个线程拿连接;max-active 不要设置过大。
✅ 业务线程池
IO 密集场景:核心线程数 ≈ CPU 核心数 * 2 拒绝策略:
CallerRunsPolicy适合允许延迟;高吞吐可考虑DiscardPolicy(丢弃),业务自己评估。 不要把 Tomcat 线程池和业务线程池混在一起!
✅ Sentinel 规则建议(控制台配置)
流控:QPS 限流,单机阈值;
熔断:慢调用比例 / 异常比例,熔断时长 5~10s;
热点参数限流:针对高热度 id(商品 id、用户 id);
规则生产环境建议持久化到 Nacos/Apollo,重启不丢失。
五、补充:可选增强
Caffeine 本地缓存配置类(多级缓存)
Feign 连接池 + 超时配置
线程池监控(Micrometer/Prometheus 暴露线程池指标)
Arthas 监控埋点
本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。
原文链接
欢迎访问