Why Ignoring SpringBoot’s Default Settings Guarantees Trouble
SpringBoot’s out‑of‑the‑box defaults—such as Tomcat’s tiny connection pool, HikariCP’s 10‑thread limit, lazy‑loaded JPA entities, system‑timezone JSON serialization, un‑rolled Logback files, unlimited in‑memory cache, exposed Actuator endpoints, tiny file‑upload limits, per‑task thread creation for @Async, and unlimited transaction timeouts—can silently cripple production systems, so each must be reviewed and tuned for real‑world workloads.
SpringBoot promotes “convention over configuration”, but many hidden defaults become performance and reliability traps in production. The article walks through each default, shows why it fails, and provides concrete configuration snippets to avoid the pitfalls.
Tomcat Connection Pool
SpringBoot uses Tomcat with a default maximum of 200 connections and 200 threads. When concurrent requests exceed this, requests are queued, leading to latency spikes.
server:
tomcat:
max-connections: 10000 # maximum connections
threads:
max: 800 # maximum worker threads
min-spare: 100 # minimum idle threads
accept-count: 100 # queue length
connection-timeout: 20000Database Connection Pool (HikariCP)
The default HikariCP pool size is only 10, which is insufficient for most applications. The article also highlights the importance of leak detection.
spring:
datasource:
hikari:
maximum-pool-size: 50
minimum-idle: 10
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
leak-detection-threshold: 60000JPA Lazy Loading
SpringBoot enables lazy loading by default, which often causes N+1 query problems. For 100 users, accessing a lazy collection triggers 101 SQL statements.
@Entity
public class User {
@Id
private Long id;
@OneToMany(fetch = FetchType.LAZY) // default is LAZY
private List<Order> orders;
}
// Fix with EntityGraph or JOIN FETCH
@Query("SELECT u FROM User u LEFT JOIN FETCH u.orders")
List<User> findAllWithOrders();Jackson Timezone Serialization
Jackson serializes dates using the system timezone, which leads to inconsistent timestamps across servers.
spring:
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
serialization:
write-dates-as-timestamps: falseLogback Logging
By default Logback writes logs to the console with level INFO and no file rotation, causing huge log files in long‑running services.
logging:
file:
name: app.log
logback:
rollingpolicy:
max-file-size: 100MB
max-history: 30
total-size-cap: 3GBCache Configuration
The default @Cacheable implementation uses a plain ConcurrentHashMap without expiration or size limits, which can cause OOM under high load. Switching to Caffeine adds eviction and size control.
spring:
cache:
type: caffeine
caffeine:
spec: maximumSize=10000,expireAfterWrite=600sActuator Endpoints
SpringBoot Actuator exposes many endpoints (health, info, metrics, env, etc.) that are useful in development but may leak sensitive data in production.
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: when-authorizedFile Upload Limits
The default file‑upload limits (1 MB per file, 10 MB per request) are too low for most business scenarios.
spring:
servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB
file-size-threshold: 2KB
location: /tmp
resolve-lazily: falseAsync Thread Pool
Using @Async without a proper executor defaults to SimpleAsyncTaskExecutor, which creates a new thread for each task, quickly exhausting resources.
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-Transaction Timeout
@Transactional has no timeout by default, so long‑running transactions hold database locks and can block other operations. The article shows a batch‑processing example and suggests a timeout and smaller transaction chunks.
@Transactional(timeout = 30, rollbackFor = Exception.class)
public void batchProcess(List<Data> dataList) {
int batchSize = 100;
for (int i = 0; i < dataList.size(); i += batchSize) {
List<Data> batch = dataList.subList(i, Math.min(i + batchSize, dataList.size()));
processBatch(batch);
}
}Static Resource Caching
SpringBoot does not set HTTP cache headers for static resources, causing browsers to re‑download unchanged CSS/JS/images on every page load.
spring:
web:
resources:
cache:
cachecontrol:
max-age: 365d
cache-public: true
chain:
strategy:
content:
enabled: true
static-locations: classpath:/static/In summary, the “convention‑over‑configuration” promise saves initial effort but can hide assumptions that don’t fit production workloads. Reviewing and adjusting these defaults early prevents costly incidents later.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer XiaoFu
xiaofucode.com – a programmer learning guide driven by the pursuit of profit
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
