Avoid Hidden SpringBoot Pitfalls: Essential Config Tweaks for Production

SpringBoot’s “convention over configuration” simplifies development, but its default settings—such as limited Tomcat connections, minimal HikariCP pool size, unchecked JPA lazy loading, unrestricted file upload limits, and inadequate logging and caching—can cause performance bottlenecks and runtime failures, so this guide details essential configuration adjustments to ensure robust, production‑ready applications.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Avoid Hidden SpringBoot Pitfalls: Essential Config Tweaks for Production

Introduction

When SpringBoot first emerged, its promise of "out‑of‑the‑box" and "convention over configuration" attracted many developers. While the defaults let you start quickly, they also hide assumptions that may not fit production environments, leading to hidden failures.

Tomcat Connection Pool

SpringBoot uses Tomcat as the default web container, but the default connection pool limits become a bottleneck under high concurrency.

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

The default maximum connections and threads are only 200 each; exceeding this causes request queuing.

Database Connection Pool

SpringBoot defaults to HikariCP, yet the default pool size (10) is insufficient for most production workloads.

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

Pay special attention to leak-detection-threshold, which is disabled by default and can hide connection leaks.

JPA Lazy Loading

SpringBoot enables lazy loading for JPA entities, which often leads to N+1 query problems.

@Entity
public class User {
    @Id
    private Long id;

    @OneToMany(fetch = FetchType.LAZY) // 默认就是LAZY
    private List<Order> orders;
}

Fetching a list of users triggers a separate query for each orders collection. To avoid this, use @EntityGraph, JOIN FETCH, or explicit queries:

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

Jackson Time‑Zone Serialization

Jackson inherits the system time‑zone, which can cause inconsistent timestamps across distributed deployments.

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

Log Configuration

SpringBoot uses Logback with no file rotation or size limits by default, leading to ever‑growing log files.

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

Adjust log levels and enable rolling to prevent disk exhaustion.

Cache Configuration

The default @Cacheable implementation uses a plain ConcurrentHashMap without expiration, which can cause unbounded memory growth.

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

Switching to Caffeine provides size limits and expiration.

Monitoring Endpoints

SpringBoot Actuator exposes many endpoints; exposing them in production can leak sensitive information.

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

Expose only necessary endpoints and secure them appropriately.

File Upload Size Limits

The default limits (1 MB per file, 10 MB total) are often too low for real‑world use, causing MaxUploadSizeExceededException.

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

Adjust thresholds to balance memory usage and performance.

Async Thread Pool Configuration

Using @Async defaults to SimpleAsyncTaskExecutor, which creates a new thread per task, exhausting resources under load.

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-

Configure core and max sizes based on CPU‑bound or I/O‑bound workloads.

Static Resource Caching Strategy

SpringBoot does not set HTTP cache headers for static assets, causing browsers to re‑download unchanged files.

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

Enabling content versioning (e.g., style-abc123.css) lets browsers cache unchanged files indefinitely.

Database Transaction Timeout

Without a timeout, long‑running transactions hold locks and can block other operations.

@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);
    }
}

Split large jobs into smaller transactions and set appropriate timeouts to release locks promptly.

Conclusion

SpringBoot’s conventions save development effort, but each default hides assumptions that may not suit production. Proactively reviewing and tuning configurations—connection pools, caching, logging, async execution, and more—prevents hidden failures and ensures a stable, high‑performance system.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

backendPerformanceconfigurationSpringBoot
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.