SpringBoot性能优化的12个小技巧(springboot自动装配原理简述)
myzbx 2025-06-30 18:49 5 浏览
前言
不知道你在SpringBoot项目中,有没有遇到过下面这样的代码:
@GetMapping("/orders")
public List<Order> listOrders() {
return orderDao.findAll();
}
一次性查询了所有的订单,全表扫描50万数据,导致接口查询性能很差,严重的时候可能会导致OOM问题。
问题定位:
- 未分页查询
- 无缓存机制
- 未启用批量处理
这次事故让我明白:性能优化必须贯穿开发全流程。
今天这篇文章,跟大家一起聊聊SpringBoot优化的12招,希望对你会有所帮助。
第1招:连接池参数调优
问题场景:默认配置导致连接池资源浪费,高并发时出现连接等待
错误配置:
spring:
datasource:
hikari:
maximum-pool-size: 1000
connection-timeout: 30000
数据库连接池的最大连接数,盲目设置过大,连接超时时间设置过长。
优化方案:
spring:
datasource:
hikari:
maximum-pool-size: ${CPU核心数*2} # 动态调整
minimum-idle: 5
connection-timeout: 3000 # 3秒超时
max-lifetime: 1800000 # 30分钟
idle-timeout: 600000 # 10分钟空闲释放
数据库连接池的最大连接数,改成根据CPU核心数动态调整。
将连接超时时间由30000,改成3000。
第2招:JVM内存优化
问题场景:频繁Full GC导致服务卡顿
我们需要优化JVM参数。
启动参数优化:
java -jar -Xms4g -Xmx4g
-XX:NewRatio=1
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=35
-XX:+AlwaysPreTouch
最大堆内存和初始堆内存都设置成了4G。
-XX:NewRatio=1,设置新生代和老年代各占一半。
垃圾收集器配置的是G1。
垃圾回收的最大停顿时间为200毫秒。
第3招:关闭无用组件
问题场景:自动装配加载不需要的Bean
优化方案:
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
SecurityAutoConfiguration.class
})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
如果有些功能暂时用不到,可以先排除一下。
在SpringBoot项目启动的时候,排除了
DataSourceAutoConfiguration和SecurityAutoConfiguration配置类的自动装载。
第4招:响应压缩配置
问题场景:接口返回JSON数据体积过大
优化方案:
server:
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/json
min-response-size: 1024
配置开启响应的压缩。
第5招:请求参数校验
问题场景:恶意请求导致资源耗尽
防御代码:
@GetMapping("/products")
public PageResult<Product> list(
@RequestParam @Max(value=100, message="页大小不能超过100") int pageSize,
@RequestParam @Min(1) int pageNum) {
//...
}
在接口中做好参数校验,可以拦截很多恶意请求。
第6招:异步处理机制
问题场景:同步处理导致线程阻塞
优化方案:
@Async("taskExecutor")
public CompletableFuture<List<Order>> asyncProcess() {
return CompletableFuture.completedFuture(heavyProcess());
}
@Bean("taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(500);
return executor;
}
在有些业务逻辑中,使用异步处理性能可能会更好。
第7招:使用缓存
使用缓存可以提升效率。
缓存架构:
代码实现:
@Cacheable(cacheNames = "products", key = "#id",
cacheManager = "caffeineCacheManager")
public Product getDetail(Long id) {
return productDao.getById(id);
}
这里使用了内存缓存。
第8招:批量操作优化
问题场景:逐条插入导致性能低下
优化方案:
@Transactional
public void batchInsert(List<Product> products) {
jdbcTemplate.batchUpdate(
"INSERT INTO product(name,price) VALUES(?,?)",
products,
500, // 每批数量
(ps, product) -> {
ps.setString(1, product.getName());
ps.setBigDecimal(2, product.getPrice());
});
}
每500条数据插入一次数据库。
第9招:索引深度优化
问题场景:慢查询日志频繁出现全表扫描,SQL执行时间波动大
错误案例:
-- 商品表结构
CREATE TABLE products (
id BIGINT PRIMARY KEY,
name VARCHAR(200),
category VARCHAR(50),
price DECIMAL(10,2),
create_time DATETIME
);
-- 低效查询
SELECT * FROM products
WHERE category = '手机'
AND price > 5000
ORDER BY create_time DESC;
问题分析:
优化方案一:联合索引设计
索引创建:
下面创建了一个分类ID,单价和时间的联合索引:
ALTER TABLE products
ADD INDEX idx_category_price_create
(category, price, create_time);
优化方案二:覆盖索引优化
查询改造:
只查询索引包含字段:
SELECT id, category, price, create_time
FROM products
WHERE category = '手机'
AND price > 5000
ORDER BY create_time DESC;
这里使用了覆盖索引。
优化方案三:索引失效预防
常见失效场景:
案例修复:
错误写法:
SELECT * FROM products
WHERE DATE(create_time) = '2023-01-01';
正确写法:
SELECT * FROM products
WHERE create_time BETWEEN '2023-01-01 00:00:00'
AND '2023-01-01 23:59:59';
查询时间范围,这里使用了BETWEEN AND关键字,代替了等于号。
优化方案四:索引监控分析
诊断命令:
查看索引使用情况:
SELECT
index_name,
rows_read,
rows_selected
FROM
sys.schema_index_statistics
WHERE
table_name = 'products';
分析索引效率:
EXPLAIN FORMAT=JSON
SELECT ...;
索引优化黄金三原则
- 最左前缀原则:联合索引的第一个字段必须出现在查询条件中
- 短索引原则:整型字段优先,字符串字段使用前缀索引
- 适度索引原则:单个表索引数量不超过5个,总索引长度不超过表数据量30%
DBA工具箱
- 索引分析脚本
- 执行计划可视化工具
- 索引碎片检测工具
第10招:自定义线程池
问题场景:默认线程池导致资源竞争
优化方案:
@Bean("customPool")
public Executor customThreadPool() {
return new ThreadPoolExecutor(
10, // 核心线程
50, // 最大线程
60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000),
new CustomThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
}
在高并发业务场景中,使用Executors类创建默认的线程池,可能会导致OOM问题。
因此,我们需要自定义线程池。
第11招:熔断限流策略
问题场景:突发流量导致服务雪崩
解决方案:
// 使用Sentinel实现接口限流
@SentinelResource(value = "orderQuery",
blockHandler = "handleBlock",
fallback = "handleFallback")
@GetMapping("/orders/{id}")
public Order getOrder(@PathVariable Long id) {
return orderService.getById(id);
}
// 限流处理
public Order handleBlock(Long id, BlockException ex) {
throw new RuntimeException("服务繁忙,请稍后重试");
}
// 降级处理
public Order handleFallback(Long id, Throwable t) {
return Order.getDefaultOrder();
}
为了解决重复流量导致服务雪崩的问题,我们需要增加接口熔断、限流和降级处理。
第12招:全链路监控体系
问题场景:线上问题定位困难,缺乏数据支撑
我们需要增加项目全链路的监控。
监控方案:
# SpringBoot配置
management:
endpoints:
web:
exposure:
include: "*"
metrics:
export:
prometheus:
enabled: true
这里使用了prometheus监控。
监控架构:
核心监控指标:
总结
SpringBoot性能优化检查清单
- 连接池参数按业务调整
- JVM参数经过压测验证
- 所有查询走缓存机制
- 批量操作替代逐条处理
- 线程池按场景定制
- 全链路监控覆盖
三条黄金法则:
- 预防性优化:编码时考虑性能影响
- 数据驱动:用监控指标指导优化方向
- 持续迭代:性能优化是持续过程
性能工具包
- Arthas在线诊断
- JProfiler性能分析
- Prometheus监控体系
相关推荐
- 使用 Siemens Teamcenter Digital Reality Viewer 打造逼真的数字孪生
-
现代产品通常由数百万个部件组成,需要复杂的设计和协作。工业世界在管理复杂性方面面临重大挑战,传统的可视化工具无法渲染这些大型的多CAD组件,从而无法充分利用数字孪生的优势。为了解决这些难题,西门子...
- 如何在JavaScript中实现数字输入框的范围限制?
-
在JavaScript语言中,实现数字输入框的范围限制可以通过多种方式实现,最常见的方式是利用JavaScript的事件监听机制,和通过JavaScript的条件判断语句来实现范围限制。以...
- 2.3.8.J速算24点终极挑战(速算24点题目及答案)
-
各位数学高手、脑力达人,今天给大家带来一道超烧脑的**24点挑战**!**数字:2、3、8、J(J=11规则很简单:**用加减乘除和括号,把四个数字组合成24!每个数字只能用一次!****看起...
- 分布式系统进阶二十一之短链接生成原理
-
前言短链接(ShortURL)是一种通过缩短网页链接长度来方便分享的技术。相比于传统的长链接,短链接更简洁明了,更易于在社交媒体等平台上分享和传播。在本文中,我们将会详细解释短链接的定义、作用及其构...
- 一、SpringBoo中Mybatis多数据源动态切换
-
我们以一个实例来详细说明一下如何在SpringBoot中动态切换MyBatis的数据源。一、需求1、用户可以界面新增数据源相关信息,提交后,保存到数据库2、保存后的数据源需要动态生效,并且可以由用户动...
- 「JS 逆向百例」层层嵌套!某加速商城 RSA 加密
-
声明本文章中所有内容仅供学习交流,敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!逆向目标目标:某加速商城登录接口主页:a...
- Spring Data Jpa 介绍和详细入门案例搭建
-
1.SpringDataJPA的概念在介绍SpringDataJPA的时候,我们首先认识下Hibernate。Hibernate是数据访问解决技术的绝对霸主,使用O/R映射(Object-Re...
- SpringBoot 开发 Web 系统,快速入门指南!
-
01、背景介绍在之前的文章中,我们简单的介绍了SpringBoot项目的创建过程,了解了SpringBoot开箱即用的特性,本篇文章接着上篇的内容继续介绍SpringBoot用于we...
- Nacos3.0重磅来袭!全面拥抱AI,单机及集群模式安装详细教程!
-
之前和大家分享过JDK17的多版本管理及详细安装过程,然后在项目升级完jdk17后又发现之前的注册和配置中心nacos又用不了,原因是之前的nacos1.3版本的,版本太老了,已经无法适配当前新的JD...
- golang语言的魅力精华之玩转通道channel 值得你反复阅读100遍
-
通道用例大全在阅读本文之前,请先阅读通道一文。那篇文章详细地解释了通道类型和通道值,以及各种通道操作的规则细节。一个Go新手程序员可能需要反复多次阅读那篇文章和当前这篇文章来精通Go通道编程。本文...
- 2小时快速搭建一个高可用的IM系统
-
“笔者2019年参加了一次Gopher大会,有幸听探探的架构师分享了他们2019年微服务化的过程。图片来自Pexels本文快速搭建的IM系统也是使用Go语言来快速实现的,这里先和...
- 分库分表以后,如何管理几万张分片表?
-
大家好,我是小富~ShardingSphere实现分库分表,如何管理分布在不同数据库实例中的成千上万张分片表?上边的问题是之前有个小伙伴看了我的分库分表的文章,私下咨询我的,看到他的提问我第一感觉就是...
- Spring Boot JDBC 与 JdbcTemplate 全面指南(万字保姆级教程)
-
一、SpringBootJDBC基础1.1JDBC简介与演进JDBC(JavaDatabaseConnectivity)是Java语言中用来规范客户端程序如何访问数据库的应用程序...
- Flink SQL 知其所以然(六)| 维表 join 的性能优化之路(上)
-
废话不多说,咱们先直接上本文的目录和结论,小伙伴可以先看结论快速了解博主期望本文能给小伙伴们带来什么帮助:背景及应用场景介绍:博主期望你能了解到,flinksql提供了轻松访问外部存储的loo...
- 大数据Hadoop之——Flink Table API 和 SQL(单机Kafka)
-
一、TableAPI和FlinkSQL是什么TableAPI和SQL集成在同一套API中。这套API的核心概念是Table,用作查询的输入和输出,这套API都是批处理和...
- 一周热门
- 最近发表
-
- 使用 Siemens Teamcenter Digital Reality Viewer 打造逼真的数字孪生
- 如何在JavaScript中实现数字输入框的范围限制?
- 2.3.8.J速算24点终极挑战(速算24点题目及答案)
- 分布式系统进阶二十一之短链接生成原理
- 一、SpringBoo中Mybatis多数据源动态切换
- 「JS 逆向百例」层层嵌套!某加速商城 RSA 加密
- Spring Data Jpa 介绍和详细入门案例搭建
- SpringBoot 开发 Web 系统,快速入门指南!
- Nacos3.0重磅来袭!全面拥抱AI,单机及集群模式安装详细教程!
- golang语言的魅力精华之玩转通道channel 值得你反复阅读100遍
- 标签列表
-
- HTML 简介 (30)
- HTML 响应式设计 (31)
- HTML URL 编码 (32)
- HTML Web 服务器 (31)
- HTML 表单属性 (32)
- HTML 音频 (31)
- HTML5 支持 (33)
- HTML API (36)
- HTML 总结 (32)
- HTML 全局属性 (32)
- HTML 事件 (31)
- HTML 画布 (32)
- HTTP 方法 (30)
- 键盘快捷键 (30)
- CSS 语法 (35)
- CSS 选择器 (30)
- CSS 轮廓宽度 (31)
- CSS 谷歌字体 (33)
- CSS 链接 (31)
- CSS 定位 (31)
- CSS 图片库 (32)
- CSS 图像精灵 (31)
- SVG 文本 (32)
- 时钟启动 (33)
- HTML 游戏 (34)