惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Check Point Blog
GbyAI
GbyAI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
U
Unit 42
美团技术团队
NISL@THU
NISL@THU
C
Cisco Blogs
SecWiki News
SecWiki News
N
Netflix TechBlog - Medium
Forbes - Security
Forbes - Security
Cloudbric
Cloudbric
雷峰网
雷峰网
T
Tailwind CSS Blog
博客园 - 司徒正美
The Register - Security
The Register - Security
L
LangChain Blog
S
Security Affairs
Hacker News - Newest:
Hacker News - Newest: "LLM"
B
Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
Threat Research - Cisco Blogs
I
InfoQ
S
Schneier on Security
L
Lohrmann on Cybersecurity
量子位
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Martin Fowler
Martin Fowler
Schneier on Security
Schneier on Security
F
Fortinet All Blogs
TaoSecurity Blog
TaoSecurity Blog
K
Kaspersky official blog
Google DeepMind News
Google DeepMind News
Cisco Talos Blog
Cisco Talos Blog
PCI Perspectives
PCI Perspectives
Attack and Defense Labs
Attack and Defense Labs
WordPress大学
WordPress大学
Microsoft Azure Blog
Microsoft Azure Blog
H
Help Net Security
Project Zero
Project Zero
The GitHub Blog
The GitHub Blog
D
Docker
N
News | PayPal Newsroom
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
H
Hacker News: Front Page
云风的 BLOG
云风的 BLOG
Microsoft Security Blog
Microsoft Security Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 聂微东
Webroot Blog
Webroot Blog
MongoDB | Blog
MongoDB | Blog

博客园 - KLAPT

Gateway 网关 CodeX =>Skills Redis 内存满了怎么处理 JWT 续签 Access Token + Refresh Token 双 Token claudeCode 命令 MyBatis 的 Mapper 接口 AI | CC GUI 集成 IDEA 完整教程 在IDEA中使用Claude Code IDEA中使用CodeX MyBatisPlus解决大数据量查询慢问题 idea 中的 claude code Token Dubbo 和 Spring Cloud Gateway的区别 Transactional 注解中propagation 掌握 Spring 框架这 10 个扩展点 SpringBoot 快速实现 api 加密 Spring Boot/Cloud 中 bootstrap.yml 与 application.yml SpringBoot 实现 DOCX 转 PDF 微服务Token鉴权设计的几种方案 进程、线程、协程 RSA 加密 Java二维码 ntp服务端和客户端 Chronyd与NTP chronyd 作为服务器时钟 chrony sudo命令和su 的区别 java -cp 和 java -jar Maven 项目打包:实现业务代码与第三方依赖分离 达梦数据库创建用户 梦数据库新增大字段报错问题 达梦数据库操作 MySQL UPDATE多表关联更新 达梦数据库 为HTTP POST请求设置请求体 在Java中调用第三方接口并返回第三方页面 Java调用第三方接口的方法 Nginx 之Rewrite 使用详解 linux 命令 Spring Boot项目中集成Spring Security OAuth2和Apache Shiro
SpringBoot 默认配置修改
KLAPT · 2026-07-01 · via 博客园 - KLAPT

Tomcat连接池

SpringBoot默认使用Tomcat作为Web容器,但默认的连接池配置在高并发场景下会成为瓶颈。

默认配置下,Tomcat的最大连接数只有200,最大线程数也只有200。这意味着当并发请求超过200时,后续请求就会排队等待。在生产环境中,这个配置明显不够用。

server:
  tomcat:
    max-connections:10000  # 最大连接数
    threads:
      max:800              # 最大工作线程数
      min-spare:100        # 最小空闲线程数
    accept-count:100       # 等待队列长度
    connection-timeout:20000

SpringBoot的默认超时时间是无限长。这会导致连接一直占用,直到客户端主动断开。

在网络不稳定的环境下,大量连接会一直挂着不释放,最终耗尽服务器资源。

数据库连接池

SpringBoot默认使用HikariCP作为数据库连接池,但默认的连接池配置在生产环境下会成为瓶颈。默认最大连接数只有10个,对于稍微复杂一点的应用来说根本不够用。

spring:
  datasource:
    hikari:
      maximum-pool-size:50
      minimum-idle:10
      connection-timeout:30000
      idle-timeout:600000
      max-lifetime:1800000
      leak-detection-threshold:60000

特别要注意leak-detection-threshold这个配置。默认情况下这个检测是关闭的,如果代码中存在连接泄漏问题,根本发现不了。

开启后,HikariCP会监控连接的使用时间,超过阈值就会打印警告日志。

JPA懒加载

SpringBoot集成JPA时,默认开启了懒加载。这个设计初衷是好的,但在实际使用中经常会导致N+1查询问题。

@Entity
publicclassUser {
    @Id
    private Long id;
    
    @OneToMany(fetch = FetchType.LAZY)  // 默认就是LAZY
    private List<Order> orders;
}

当查询用户列表时,每访问一次orders属性,就会触发一次数据库查询。

如果有100个用户,就会执行101次SQL。

这种情况下,要么使用@EntityGraph指定加载策略,要么在Repository中使用JOIN FETCH

@Query("SELECT u FROM User u LEFT JOIN FETCH u.orders")
List<User> findAllWithOrders();

ackson时区序列化

SpringBoot默认使用Jackson处理JSON序列化,但时区处理经常出问题。

默认情况下,Jackson会使用系统时区,这在分布式部署时会导致不一致的问题。

spring:
  jackson:
    time-zone:GMT+8
    date-format:yyyy-MM-ddHH:mm:ss
    serialization:
      write-dates-as-timestamps:false

更要命的是,如果你的应用部署在不同时区的服务器上,同样的时间可能会被序列化成不同的值。

这个问题在国际化应用中特别突出。

日志配置

SpringBoot默认使用Logback,但默认配置下没有对日志文件进行滚动和清理。

长时间运行的应用会产生巨大的日志文件,最终占满磁盘空间。

logging:
  file:
    name:app.log
  logback:
    rollingpolicy:
      max-file-size:100MB
      max-history:30
      total-size-cap:3GB

另外,默认的日志级别是INFO,在生产环境中会产生大量不必要的日志。

缓存配置

SpringBoot的@Cacheable注解默认使用ConcurrentHashMap作为缓存实现,但这个实现没有过期机制,也没有大小限制。在高并发场景下,缓存会无限增长,最终导致内存溢出。

spring:
  cache:
    type:caffeine
    caffeine:
      spec:maximumSize=10000,expireAfterWrite=600s

可以考虑使用Caffeine替代默认实现,可以提供更好的性能和内存管理能力。

监控端点

SpringBoot Actuator默认暴露了很多监控端点,包括健康检查、配置信息、环境变量等。

这些信息在开发环境中很有用,但在生产环境中可能泄漏敏感信息。

management:
  endpoints:
    web:
      exposure:
        include:health,info,metrics
  endpoint:
    health:
      show-details:when-authorized

只暴露必要的端点,并且配置适当的安全策略,避免信息泄漏

文件上传大小限制

SpringBoot默认的文件上传限制非常小,单个文件只能上传1MB,整个请求大小限制10MB。

在实际业务中,这个限制经常不够用,用户上传稍大一点的文件就会报错。

这个属于是比较常见的问题,因为开发环境测试时通常用小文件,一切正常。等到用户上传几MB的PDF文档或者高清图片时,系统就开始报 MaxUploadSizeExceededException 异常。

这个异常往往还发生在文件传输完成之后,用户等了半天上传完毕,结果被告知文件过大,体验极差。

spring:
  servlet:
    multipart:
      max-file-size:100MB
      max-request-size:100MB
      file-size-threshold:2KB
      location:/tmp
      resolve-lazily:false

file-size-threshold 这个参数也很重要,它决定了多大的文件会直接写入内存。如果设置过大,大量并发上传会占用过多内存;设置过小,小文件也要写磁盘,影响性能。一般设置为几KB比较合适。

异步线程池配置

使用@Async注解时,SpringBoot默认使用SimpleAsyncTaskExecutor,这个执行器每次都会创建新线程,没有线程池复用机制。高并发情况下会创建大量线程,最终导致系统资源耗尽。

这个问题在开发阶段很难发现,因为异步任务通常不多。但在生产环境,如果有大量异步任务执行,比如发送短信、推送、记录日志等,系统会不断创建新线程。每个线程默认占用1MB的栈空间,创建几千个线程就是几GB内存。

更严重的是线程切换的开销,CPU大部分时间都在做上下文切换,真正的业务逻辑反而执行很慢。

spring:
  task:
    execution:
      pool:
        core-size:8
        max-size:16
        queue-capacity:100
        keep-alive:60s
      thread-name-prefix:async-task-
    scheduling:
      pool:
        size:4
      thread-name-prefix:scheduling-

线程池大小的设置也有讲究。

如果是CPU密集型任务,线程数设置为CPU核心数就够了;如果是IO密集型任务,可以设置为CPU核心数的2-3倍。

queue-capacity设置了任务队列长度,当线程池满了之后,新任务会放到队列里等待执行。

静态资源缓存策略

SpringBoot默认不为静态资源设置HTTP缓存头,这意味着浏览器每次都会重新请求CSS、JS、图片等静态文件,严重影响页面加载性能。

用户每次访问页面,浏览器都要重新下载所有静态资源,即使这些文件根本没有变化。对于资源较多的单页应用来说,这个问题特别明显。用户看到的就是页面加载慢,特别是网络条件不好的时候,体验很差。

spring:
  web:
    resources:
      cache:
        cachecontrol:
          max-age:365d
          cache-public:true
      chain:
        strategy:
          content:
            enabled:true
            paths:/**
        cache:true
      static-locations:classpath:/static/

开启内容版本化策略后,SpringBoot会根据文件内容生成MD5哈希值作为版本号,文件名变成style-abc123.css这样的格式。当文件内容发生变化时,哈希值也会变化,浏览器会认为这是新文件重新下载;如果文件没变化,浏览器就直接使用缓存,有效提升页面加载速度。

数据库事务超时

@Transactional注解默认没有设置超时时间,长时间运行的事务会一直持有数据库锁,影响其他操作的执行。特别是在批量数据处理时,很容易出现锁表问题。

这个问题在并发量不高的时候不明显,但随着业务增长,长事务的危害就暴露出来了。

比如一个数据导入任务需要处理几万条记录,如果放在一个事务里,可能要运行几分钟甚至更长时间。在这期间,相关的表都被锁住,其他用户的操作只能等待,系统响应变得很慢。

@Transactional(timeout = 30, rollbackFor = Exception.class)
publicvoidbatchProcess(List<Data> dataList) {
    // 分批处理,避免长事务
    intbatchSize=100;
    for (inti=0; i < dataList.size(); i += batchSize) {
        List<Data> batch = dataList.subList(i, 
            Math.min(i + batchSize, dataList.size()));
        processBatch(batch);
    }
}

对于大批量数据处理,建议分成多个小事务,每个事务处理少量数据。这样即使某个小事务失败,也不会影响整体进度,而且可以及时释放数据库锁,提高系统并发性能。

同时再加上rollbackFor = Exception.class确保所有异常都会触发回滚,避免数据不一致。