9 Spring Boot API Performance Tricks to Squeeze Every Millisecond

This article presents nine practical techniques—async processing, caching, database query tuning, response compression, WebFlux reactive endpoints, logging reduction, index optimization, connection‑pool configuration, and CDN static‑asset delivery—to dramatically cut Spring Boot API latency and boost throughput in high‑concurrency environments.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
9 Spring Boot API Performance Tricks to Squeeze Every Millisecond

Introduction

As a system grows, API calls become a major performance bottleneck. Each request may involve database queries, object mapping, serialization, network I/O, and thread scheduling, any of which can add milliseconds to response time. In high‑concurrency scenarios, shaving off even a few milliseconds can significantly increase overall throughput.

1. Asynchronous Processing

Offload long‑running tasks to a separate thread to avoid blocking the main request thread.

@Service
public class AsyncService {
    @Async
    public void longRunningTask() {
        System.out.println("Starting long-running task");
        try {
            Thread.sleep(5000); // simulate long task
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Long-running task completed");
    }
}

Controller example using DeferredResult:

@GetMapping("/deferred")
@ResponseBody
public DeferredResult<Map<String, Object>> deferred() {
    long start = System.currentTimeMillis();
    System.out.printf("%s - start: %d%n", Thread.currentThread().getName(), start);
    DeferredResult<Map<String, Object>> result = new DeferredResult<>();
    new Thread(() -> {
        try {
            TimeUnit.SECONDS.sleep(3);
            Map<String, Object> data = new HashMap<>();
            data.put("code", 1);
            data.put("data", "your business data");
            result.setResult(data);
        } catch (InterruptedException ignored) {}
    }).start();
    long end = System.currentTimeMillis();
    System.out.printf("%s - end: %d%n", Thread.currentThread().getName(), end);
    System.out.printf("Total time: %d ms%n", (end - start));
    return result;
}

2. Caching

Cache rarely‑changing data to avoid repeated database or remote calls.

@Service
@CacheConfig(cacheNames = {"userCache"})
public class UserService {
    private final Logger logger = LoggerFactory.getLogger(UserService.class);

    @Cacheable(key = "#id")
    public User queryById(Long id) {
        logger.info("Querying user from DB: {}", id);
        return new User(id, "Name-" + new Random().nextInt(1000), new Random().nextInt(100));
    }
}

3. Database Query Optimization

Limit selected fields and avoid complex joins.

@Service
public class DatabaseOptimizationService {
    @PersistenceContext
    private EntityManager entityManager;

    public List<Object> optimizedQuery() {
        Query query = entityManager.createQuery("SELECT field1, field2 FROM MyTable WHERE condition");
        return query.getResultList();
    }
}

Projection interface example:

public interface UserProjection {
    Long getId();
    String getUsername();
    String getPhone();
}

public interface UserRepository extends JpaRepository<User, Long> {
    @Query("SELECT u.id AS id, u.username AS username, u.phone AS phone FROM User u WHERE u.status = 1")
    List<UserProjection> findUserProjection();
}

4. Response Compression

Compress large JSON or XML payloads with GZIP and set the appropriate response header.

@RestController
public class CompressionController {
    @GetMapping("/compressedData")
    public void getCompressedData(HttpServletResponse response) throws IOException {
        String data = "This is a large amount of data that needs to be compressed...";
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPOutputStream gzip = new GZIPOutputStream(baos);
        gzip.write(data.getBytes());
        gzip.close();
        response.addHeader("Content-Encoding", "gzip");
        response.getOutputStream().write(baos.toByteArray());
    }
}

Enable compression globally:

server:
  compression:
    enabled: true
    min-response-size: 1024
    mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json,application/xml

5. WebFlux Reactive Endpoints

Use Spring WebFlux to handle massive concurrent requests with low resource consumption.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
@RestController
public class WebFluxController {
    @GetMapping("/reactiveData")
    public Mono<String> getReactiveData() {
        return Mono.just("Reactive programming data");
    }
}

6. Logging Optimization

Reduce unnecessary logging; check log level before emitting messages.

@RestController
public class LoggingController {
    private static final Logger logger = LoggerFactory.getLogger(LoggingController.class);

    @GetMapping("/efficientLogging")
    public String getEfficientLogging() {
        if (logger.isInfoEnabled()) {
            logger.info("Efficient logging");
        }
        return "Logging optimization example";
    }
}

7. Index Optimization

Create composite indexes that match query predicates.

CREATE INDEX idx_username_email_age ON User(username, email, age);

Repository method leveraging the index:

public interface UserRepository extends JpaRepository<User, Long> {
    User findByUsernameAndEmail(String username, String email);
}

8. Connection‑Pool Configuration

Configure HikariCP to reuse connections and reduce creation overhead.

common-datasource: &common-ds
  driver-class-name: com.mysql.cj.jdbc.Driver
  username: root
  password: '{cipher}...'
  type: com.zaxxer.hikari.HikariDataSource
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/testjpa
    <<: *common-ds
    hikari:
      minimumIdle: 20
      maximumPoolSize: 50
      autoCommit: true

9. CDN for Static Assets

Serve images, CSS, and JavaScript from a CDN to reduce latency for end users.

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

Placing static resources on a CDN shortens load time, indirectly improving overall API response speed.

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.

CachingLoggingSpring Bootdatabase optimizationWebFluxasynchronous processingcompressionAPI performance
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

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.