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.04
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