Why Is Your Spring Boot App Lagging? 10 Optimization Tips to Speed It Up
This guide walks through ten practical techniques—startup lazy initialization, scoped component scanning, selective auto‑configuration, async processing, connection‑pool tuning, JPA batch settings, multi‑level caching, multi‑stage Docker builds, JVM container‑aware flags, Tomcat thread tuning, Resilience4j, observability stack, and TDD—to diagnose and eliminate performance bottlenecks in Spring Boot applications.
Startup Optimization
Goal: Reduce the time from Spring Boot start to ready, crucial for CI/CD and cloud‑native environments.
Lazy Initialization : Enable globally via spring.main.lazy-initialization: true or annotate specific beans with @Lazy so they are created only on first use.
# application.yml
spring:
main:
lazy-initialization: true # Enable lazy init globally [citation:5] @Service
@Lazy // Enable for this bean only
public class HeavyService {
// Initialized on first injection or call
}Limit Component Scan : Restrict scanning to essential packages.
@SpringBootApplication(scanBasePackages = "com.yourcompany.core")
// Or exclude specific packages
@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.thirdparty.*"))
public class Application { }Exclude Unnecessary Auto‑Configuration : Turn off auto‑configs that are not needed, e.g., when no relational DB is used.
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class, // Exclude if no relational DB
MongoAutoConfiguration.class
})Asynchronous & Concurrent Processing
Goal: Separate time‑consuming tasks (email, file handling) from request threads to improve throughput and response speed.
Enable Async Support : Add @EnableAsync on a configuration class.
Use @Async with CompletableFuture for non‑blocking calls.
@Service
public class NotificationService {
@Async // Executed in thread pool [citation:4]
public CompletableFuture<String> sendAsync(String message) {
Thread.sleep(1000); // Simulate delay
return CompletableFuture.completedFuture("Sent: " + message);
}
}Configure Dedicated Thread Pool to avoid the default SimpleAsyncTaskExecutor.
spring:
task:
execution:
pool:
core-size: 5
max-size: 20
queue-capacity: 100Data Access Layer Deep Optimization
Goal: Reduce DB latency and round‑trips.
Connection‑Pool Tuning : Use HikariCP (default in Spring Boot 2.x) with appropriate pool sizes.
spring:
datasource:
hikari:
maximum-pool-size: 20 # Adjust per DB capacity [citation:1]
minimum-idle: 10
connection-timeout: 30000
idle-timeout: 600000JPA/Hibernate Batch Operations : Enable batch size and ordering to boost write efficiency.
spring:
jpa:
properties:
hibernate:
jdbc.batch_size: 20
order_inserts: true
order_updates: trueUse @BatchSize to mitigate N+1 queries.
@Entity
public class Author {
@OneToMany(mappedBy = "author")
@BatchSize(size = 10) // Load multiple books per author
private List<Book> books;
}Intelligent Multi‑Level Caching
Goal: Leverage fast memory to avoid repeated DB or downstream calls.
Local Cache (Caffeine) : Suitable for hot data with infrequent changes.
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000));
return manager;
}
}
@Service
public class ProductService {
@Cacheable(value = "products", key = "#id")
public Product getProductById(Long id) {
// Executes only on cache miss
return productRepository.findById(id).orElse(null);
}
@CacheEvict(value = "products", key = "#id")
public void updateProduct(Product product) { /* ... */ }
}Distributed Cache (Redis) : Use spring-boot-starter-data-redis for shared or large‑scale caching.
Containerization & Image Optimization
Goal: Build small, fast‑starting, reproducible container images for cloud‑native deployment.
Multi‑Stage Build : Reduces final image size by >70%.
# Stage 1: Build
FROM maven:3.8.6-openjdk-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn clean package -DskipTests
# Stage 2: Run
FROM openjdk:17-jdk-slim # Lightweight runtime [citation:6]
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar # Copy only the jar [citation:3]
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/app.jar"]JVM Tuning for Cloud‑Native Environments
Goal: Ensure efficient, stable JVM operation inside containers and avoid OOM.
Container‑Aware Memory Settings (JDK 8u191+ / JDK 10+). Use percentage‑based limits.
java -jar \
-XX:InitialRAMPercentage=50.0 \
-XX:MaxRAMPercentage=80.0 \
-XX:+UseContainerSupport \ # Enabled by default on JDK 8u191+ [citation:5]
app.jarTiered Compilation for Faster Startup (sacrifices peak performance for short‑lived functions).
JAVA_TOOL_OPTIONS="-XX:+TieredCompilation -XX:TieredStopAtLevel=1"Adjust Thread Stack Size to fit microservice concurrency needs.
JAVA_TOOL_OPTIONS="-Xss256k" # Test to avoid StackOverflowError [citation:5]Web Container & Network Transmission Optimization
Goal: Improve HTTP request handling efficiency.
Tomcat Thread Pool tuning based on load.
server:
tomcat:
threads:
max: 200 # Max worker threads [citation:1]
min-spare: 20
accept-count: 100 # Queue length [citation:1]
connection-timeout: 5000msEnable HTTP/2 and Compression for better transfer performance.
server:
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css,application/json,application/javascript
http2:
enabled: trueRate Limiting, Circuit Breaking & Degradation
Goal: Protect core functionality when downstream services are unstable or under heavy load.
Resilience4j replaces Netflix Hystrix with a lighter, more powerful library.
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
</dependency>Annotations for Rate Limiting & Circuit Breaking .
@Service
public class ExternalApiService {
// Allow max 2 calls per second
@RateLimiter(name = "externalApi")
// Open circuit when failure rate > 50%
@CircuitBreaker(name = "externalApi", fallbackMethod = "fallback")
public String callUnstableApi() {
// Call external API
}
private String fallback(Exception e) {
return "Fallback response due to: " + e.getMessage();
}
}Observability: Monitoring, Metrics & Tracing
Goal: Build a complete monitoring system so performance issues are visible, traceable, and alertable.
Core Stack : Spring Boot Actuator, Micrometer, Prometheus + Grafana.
Key Configuration to expose endpoints and enable Prometheus scraping.
management:
endpoints:
web:
exposure:
include: health, metrics, prometheus # Expose necessary endpoints
metrics:
export:
prometheus:
enabled: true
tracing:
sampling:
probability: 1.0 # Set sampling rateTest‑Driven Development (TDD) to Safeguard Optimizations
Goal: Ensure each performance tweak or refactor is safe, reliable, and sustainable.
Red → Green → Refactor cycle: write failing test, make it pass, then clean code.
Example Test for a Service Method .
@SpringBootTest
class ProductServiceTest {
@Test
void getProductById_shouldReturnProduct_whenExists() {
// Prepare test data
// Call method under optimization
// Assert expected result
}
@Test
void getProductById_shouldThrow_whenNotExists() { /* ... */ }
}Run tests, apply optimization (e.g., add @Cacheable), run tests again to verify no regression.
Summary & Action Roadmap
Measure First : Establish a performance baseline (e.g., JMeter QPS, P95 latency) using Actuator/Prometheus metrics to locate real bottlenecks.
Inside‑Out Approach : Optimize in order – Application/JVM code → Data layer (cache, SQL) → Architecture layer (async, splitting).
Trade‑offs : Each optimization has cost – lazy init adds first‑request latency, caching introduces consistency concerns, async adds system complexity.
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.
Senior Xiao Ying
Dedicated to sharing Java backend technical experience and original tutorials, offering career transition advice and resume editing. Recognized as a rising star in CSDN's Java backend community and ranked Top 3 in the 2022 New Star Program for Java backend.
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.
