Spring Boot: From Basics to Production · Spring Core and Spring Boot Fundamentals

Bean Scopes, Lifecycle and Events

Singletons, prototype scope, initialization hooks and application events.

Beans are singletons by default — one instance shared across threads — so they must be stateless or thread-safe. Other scopes include prototype (new instance per injection) and web scopes (request, session). Use @PostConstruct/@PreDestroy or ApplicationRunner for startup logic, and application events (ApplicationEventPublisher, @EventListener, @TransactionalEventListener) to decouple side effects from core logic.

public record OrderPlaced(long orderId, String email) {}

@Service
class OrderService {
    private final ApplicationEventPublisher events;
    OrderService(ApplicationEventPublisher events) { this.events = events; }

    @Transactional
    public Order place(Cart cart) {
        Order order = /* save */ null;
        events.publishEvent(new OrderPlaced(order.getId(), cart.email()));
        return order;
    }
}

@Component
class OrderEmails {
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)   // only if the transaction commits
    void onOrderPlaced(OrderPlaced event) {
        // send confirmation email
    }
}

Common pitfalls

  • Mutable fields in singleton beans (shared across requests → race conditions).
  • Heavy work in constructors/@PostConstruct slowing startup.
  • Sending emails in plain @EventListener before the transaction commits.

Key points

  • Singletons must be thread-safe
  • Events decouple side effects
  • AFTER_COMMIT listeners for post-transaction work

Further reading: Spring: Bean scopes

Go deeper: Spring Boot: Filters, DispatcherServlet and Interceptors in the Request Lifecycle course traces this step of the request, with a production bug and a runnable simulation.

Practice questions

Why is a mutable field in a @Service dangerous?

Answer

Services are singletons shared by all request threads, so mutable state causes race conditions and data leaking between requests.

Why use @TransactionalEventListener(AFTER_COMMIT) for sending emails?

Answer

The listener runs only after the transaction commits, so no email is sent for orders that were rolled back.

Open in the app to mark lessons complete, take notes and track your progress.