Cheat SheetsSpring BootAdvanced

Advanced — Cheat Sheet

Spring Boot · 4 topics. Download the PDF or the Instagram carousel and share it.

Cheat Sheet · AiCanCode.org
Advanced
Spring Boot4 topicsQuick revision reference
1

Async Processing with @Async

@Async runs a method in a background thread from a configurable TaskExecutor; combine with CompletableFuture to compose results without blocking the caller.

  • @EnableAsync on a @Configuration class activates @Async support; without it, @Async annotations are silently ignored.
  • @Async works via AOP proxy — self-invocation (calling an @Async method on the same bean) bypasses the proxy and runs synchronously.
  • Return CompletableFuture<T> for async methods that produce results; combine with CompletableFuture.allOf() for parallel fan-out.
  • Never use the default SimpleAsyncTaskExecutor in production — configure a ThreadPoolTaskExecutor with bounded pool and queue.
  • Exceptions thrown in void @Async methods are silently swallowed; configure AsyncUncaughtExceptionHandler to log or alert.
  • @Transactional and @Async on the same method is a trap — the transaction commits before the method returns, and the async work runs outside it.
Java — @Async Fire-and-Forget
// 1. Enable async processing
@SpringBootApplication
@EnableAsync
public class App { }

// 2. Async method — runs in background thread, caller does not wait
@Service
public class NotificationService {

    @Async   // executes in background thread
    public void sendOrderConfirmation(String email, String orderId) {
        // Caller returns immediately; this runs concurrently
        emailClient.send(email, "Order confirmed: " + orderId);
        log.info("Sent confirmation to {} on thread {}", email,
                 Thread.currentThread().getName());
    }
}

// 3. Caller — does not block
@Service
@RequiredArgsConstructor
public class OrderService {
    private final NotificationService notificationService;

    @Transactional
    public Order placeOrder(OrderRequest req) {
        Order order = orderRepo.save(new Order(req));
        // Returns immediately — email is sent asynchronously
        notificationService.sendOrderConfirmation(req.getEmail(), order.getId().toString());
        return order;
    }
}
2

Scheduling with @Scheduled

@Scheduled triggers a method on a fixed rate, fixed delay, or cron expression; @EnableScheduling must be present and methods must return void.

  • fixedRate: fires every N ms from last start — can overlap; fixedDelay: N ms after last end — safe
  • cron uses 6 fields (sec min hour day month weekday) — externalise via ${} for per-env config
  • Default scheduler is single-threaded — provide a ThreadPoolTaskScheduler bean for concurrency
  • @Async on a @Scheduled method offloads it to a separate executor thread pool
  • Multi-pod deployments: all pods run @Scheduled independently — use ShedLock for one-pod-only
  • setWaitForTasksToCompleteOnShutdown(true) ensures graceful drain on SIGTERM
Spring Boot — @Scheduled fixedRate / fixedDelay / cron
@Configuration
@EnableScheduling
public class SchedulingConfig { }

@Component
public class ReportScheduler {

    // Every 30 seconds regardless of execution time (can overlap)
    @Scheduled(fixedRate = 30_000)
    public void generateMetricsSnapshot() {
        metricsService.snapshot();
    }

    // 10 seconds AFTER the last run completes (no overlap)
    @Scheduled(fixedDelay = 10_000, initialDelay = 5_000)
    public void cleanExpiredSessions() {
        sessionRepo.deleteExpired(Instant.now());
    }

    // CRON: every day at 02:30 (6-field: sec min hour day month weekday)
    @Scheduled(cron = "0 30 2 * * *")
    public void dailyEmailReport() {
        reportService.sendDaily();
    }

    // Read cron from config — allows per-environment schedule
    @Scheduled(cron = "${reports.invoice.cron:0 0 1 * * *}")
    public void invoiceRun() {
        invoiceService.processAll();
    }
}
3

Spring Boot with Docker & Deployment

Spring Boot Maven/Gradle plugins build OCI-compliant images via Buildpacks or a Dockerfile; layered JARs reduce rebuild time by keeping dependencies in separate layers.

  • Buildpacks (spring-boot:build-image) create optimised OCI images without a Dockerfile — recommended for standard deployments
  • Layered JARs (default in Boot 2.3+) split the archive into dependency/application layers, enabling Docker layer caching
  • Multi-stage Dockerfiles extract layers in order from least-changed to most-changed to maximise build cache reuse
  • -XX:MaxRAMPercentage and -XX:+UseContainerSupport ensure the JVM uses container memory limits, not host RAM
  • Non-root user in Dockerfile reduces attack surface — never run JVM containers as root
  • Set Kubernetes memory requests == limits to prevent the pod being placed in the Burstable QoS class and risk OOMKill
XML + Shell — Buildpack image with registry publish
<!-- pom.xml — configure Buildpack image name and publish -->
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <image>
            <name>registry.example.com/myapp:${project.version}</name>
            <publish>true</publish>
            <env>
                <!-- JVM memory tuning in container -->
                <BPL_JVM_THREAD_COUNT>50</BPL_JVM_THREAD_COUNT>
                <BPL_JVM_HEAP_PERCENT>75</BPL_JVM_HEAP_PERCENT>
            </env>
        </image>
        <docker>
            <publishRegistry>
                <url>registry.example.com</url>
                <username>${REGISTRY_USER}</username>
                <password>${REGISTRY_PASSWORD}</password>
            </publishRegistry>
        </docker>
    </configuration>
</plugin>

# Build and push
./mvnw spring-boot:build-image -DskipTests

# Run locally
docker run -p 8080:8080 \
  -e SPRING_PROFILES_ACTIVE=dev \
  registry.example.com/myapp:1.0.0
4

Spring Boot with Redis

Spring Data Redis provides RedisTemplate and the @Cacheable abstraction over Redis; cache-aside, write-through, and pub/sub patterns are all supported out of the box.

  • @Cacheable with RedisCacheManager makes method results Redis-backed with per-cache TTL
  • Use GenericJackson2JsonRedisSerializer for human-readable JSON values in Redis
  • RedisTemplate.opsForValue().increment() + expire() implements atomic rate limiting
  • SET key value NX PX ttl is the foundation of a Redis distributed lock
  • Redis pub/sub broadcasts to all subscribers — useful for cache invalidation across pods
  • spring-session-data-redis stores HTTP session in Redis — enables stateless horizontally-scaled apps
Spring Boot — @Cacheable with RedisCacheManager
@Configuration
class RedisCacheConfig {
    @Bean
    CacheManager cacheManager(RedisConnectionFactory cf) {
        RedisCacheConfiguration cfg = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(30))
            .prefixCacheNameWith("myapp::")
            .serializeValuesWith(                           // JSON instead of Java serialisation
                RedisSerializationContext.SerializationPair
                    .fromSerializer(new GenericJackson2JsonRedisSerializer()));

        return RedisCacheManager.builder(cf)
            .cacheDefaults(cfg)
            .withCacheConfiguration("products", cfg.entryTtl(Duration.ofHours(1)))
            .build();
    }
}

@Service
class ProductService {
    @Cacheable(value = "products", key = "#id")
    public Product findById(Long id) { return productRepo.findById(id).orElseThrow(); }

    @CacheEvict(value = "products", key = "#product.id")
    public Product update(Product product) { return productRepo.save(product); }

    @CacheEvict(value = "products", allEntries = true)
    public void refreshAll() { /* clear all cache entries */ }
}
Learn this free with Aria, your AI tutor → AiCanCode.org/learn/spring-boot