Contents

  1. Instantiation — Spring creates the bean instance.
  2. Property Population — dependencies are injected.
  3. Initialisation@PostConstruct methods are called.
  4. Active use — the bean serves the application.
  5. Destruction@PreDestroy methods are called when the context is closed.

A method annotated with @PostConstruct is called by Spring after the bean is fully initialised. Use it for one-time setup such as loading configuration or warming up a cache.

import jakarta.annotation.PostConstruct; import org.springframework.stereotype.Service; import java.util.List; @Service public class CacheWarmupService { private final ProductRepository productRepository; private List<Product> cachedProducts; public CacheWarmupService(ProductRepository productRepository) { this.productRepository = productRepository; } @PostConstruct public void warmUpCache() { cachedProducts = productRepository.findAll(); System.out.println("Cache warmed up with " + cachedProducts.size() + " products"); } }

Rules: the method must be void, take no parameters, and must not be static.

A method annotated with @PreDestroy is called by Spring before the bean is removed from the context. Use it to release resources such as thread pools or file handles.

import jakarta.annotation.PreDestroy; import org.springframework.stereotype.Service; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @Service public class AsyncTaskService { private final ExecutorService executor = Executors.newFixedThreadPool(4); public void submitTask(Runnable task) { executor.submit(task); } @PreDestroy public void shutdown() throws InterruptedException { System.out.println("Shutting down thread pool..."); executor.shutdown(); if (!executor.awaitTermination(30, TimeUnit.SECONDS)) { executor.shutdownNow(); } System.out.println("Thread pool terminated."); } }

An older approach is implementing InitializingBean or DisposableBean. This couples the class to Spring's API and is generally less preferred than the annotation approach.

import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Component; @Component public class DatabaseConnectionPool implements InitializingBean, DisposableBean { @Override public void afterPropertiesSet() throws Exception { System.out.println("Connection pool initialised"); } @Override public void destroy() throws Exception { System.out.println("Connection pool closed"); } }

Prefer @PostConstruct / @PreDestroy — they are part of the Jakarta EE standard and keep your classes Spring-independent.