12 Proven SpringBoot Performance Hacks to Boost Your API Speed
Discover twelve practical SpringBoot performance optimization techniques—from connection pool tuning and JVM memory settings to caching, async processing, and full‑stack monitoring—each illustrated with code snippets and actionable guidance to prevent full‑table scans, OOM errors, and latency spikes in high‑traffic applications.
Introduction
In many SpringBoot projects developers unintentionally query all orders at once, causing a full‑table scan of hundreds of thousands of rows, severe performance degradation, and even OOM errors.
Tip 1: Connection Pool Parameter Tuning
Problem scenario: Default configuration wastes connection pool resources and leads to waiting under high concurrency.
spring:
datasource:
hikari:
maximum-pool-size: 1000
connection-timeout: 30000The maximum pool size is set too high and the timeout too long.
Optimization:
spring:
datasource:
hikari:
maximum-pool-size: ${CPU_CORE_COUNT*2} # dynamic adjustment
minimum-idle: 5
connection-timeout: 3000 # 3 seconds
max-lifetime: 1800000 # 30 minutes
idle-timeout: 600000 # 10 minutesAdjust the maximum connections based on CPU cores and shorten the timeout.
Tip 2: JVM Memory Optimization
Problem scenario: Frequent Full GC causes service stutter.
Startup parameters:
java -jar -Xms4g -Xmx4g
-XX:NewRatio=1
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=35
-XX:+AlwaysPreTouchSet both initial and maximum heap to 4 GB, split new and old generations equally, use G1 GC, and limit pause time to 200 ms.
Tip 3: Disable Unused Auto‑Configuration
Problem scenario: Auto‑loading unnecessary beans.
Optimization:
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
SecurityAutoConfiguration.class
})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}Exclude components that are not needed at startup.
Tip 4: Enable Response Compression
Problem scenario: JSON response bodies are too large.
Optimization:
server:
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/json
min-response-size: 1024Compress responses to reduce payload size.
Tip 5: Request Parameter Validation
Problem scenario: Malicious requests exhaust resources.
Defensive code:
@GetMapping("/products")
public PageResult<Product> list(
@RequestParam @Max(value=100, message="Page size cannot exceed 100") int pageSize,
@RequestParam @Min(1) int pageNum) {
// ...
}Validate request parameters to block abusive calls.
Tip 6: Asynchronous Processing
Problem scenario: Synchronous handling blocks threads.
Optimization:
@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;
}Use a custom thread pool for async tasks.
Tip 7: Use Caching
Cache improves efficiency.
Cache architecture:
Code implementation:
@Cacheable(cacheNames = "products", key = "#id", cacheManager = "caffeineCacheManager")
public Product getDetail(Long id) {
return productDao.getById(id);
}Leverage in‑memory cache for read‑heavy data.
Tip 8: Batch Operation Optimization
Problem scenario: Inserting records one by one degrades performance.
Optimization:
@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());
});
}Insert in batches of 500 rows.
Tip 9: Deep Index Optimization
Problem scenario: Slow queries with full‑table scans.
Incorrect case:
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;Solution 1 – Composite Index:
ALTER TABLE products ADD INDEX idx_category_price_create (category, price, create_time);Solution 2 – Covering Index:
SELECT id, category, price, create_time FROM products WHERE category = '手机' AND price > 5000 ORDER BY create_time DESC;Solution 3 – Prevent Index Loss:
SELECT * FROM products WHERE create_time BETWEEN '2023-01-01 00:00:00' AND '2023-01-01 23:59:59';Solution 4 – Index Monitoring:
SELECT index_name, rows_read, rows_selected FROM sys.schema_index_statistics WHERE table_name = 'products';
EXPLAIN FORMAT=JSON SELECT ...;Golden principles:
Left‑most prefix: The first column of a composite index must appear in the WHERE clause.
Short index: Prefer integer columns; use prefix indexes for strings.
Moderate index count: No more than five indexes per table, total length < 30% of table size.
Tip 10: Custom Thread Pool
Problem scenario: Default thread pool causes resource contention.
Optimization:
@Bean("customPool")
public Executor customThreadPool() {
return new ThreadPoolExecutor(
10, // core threads
50, // max threads
60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000),
new CustomThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
}Define a thread pool tailored to high‑concurrency workloads.
Tip 11: Circuit Breaker & Rate Limiting
Problem scenario: Sudden traffic spikes cause service collapse.
Solution:
// Sentinel rate‑limit annotation
@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("Service busy, please retry later");
}
public Order handleFallback(Long id, Throwable t) {
return Order.getDefaultOrder();
}Apply rate limiting, circuit breaking, and fallback handling.
Tip 12: Full‑Link Monitoring System
Problem scenario: Difficult to locate issues in production due to lack of data.
Monitoring configuration:
management:
endpoints:
web:
exposure:
include: "*"
metrics:
export:
prometheus:
enabled: trueEnable Prometheus metrics for comprehensive observability.
Monitoring architecture:
Core metrics:
Conclusion
SpringBoot Performance Checklist
Adjust connection pool parameters per business load.
Validate JVM settings through load testing.
Ensure all queries use caching.
Replace per‑row operations with batch processing.
Customize thread pools for each scenario.
Cover the entire call chain with monitoring.
Three golden rules:
Preventive optimization: Consider performance impact during coding.
Data‑driven: Use monitoring metrics to guide optimizations.
Continuous iteration: Treat performance tuning as an ongoing process.
Performance toolbox:
Arthas for online diagnosis.
JProfiler for profiling.
Prometheus for metrics collection.
(Seeing a stable QPS curve on the dashboard, I can finally sleep well tonight.)
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
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.