DEV Community

DevCorner2
DevCorner2

Posted on

πŸ“’ Spring Application Events: A Complete Guide with Real-world Code Examples

πŸ” What Are Spring Events?

Spring Events provide a way for different components of a Spring application to communicate with each other in a loosely coupled way using the Publisher-Listener model. It follows the Observer Design Pattern.


🧠 Why Use Spring Events?

βœ… Loose coupling
βœ… Asynchronous event handling (if needed)
βœ… Clean separation of concerns
βœ… Easy to extend & test


πŸ“¦ Core Concepts

Component Description
ApplicationEvent The event object (can also be a POJO from Spring 4.2+)
ApplicationEventPublisher Used to publish events
@EventListener Used to listen and act on events

🧱 Use Case Example: User Registration System

Let’s build a real-world example:
When a user registers, send a welcome email and log an audit trail using Spring Events.


1️⃣ Create a Custom Event

// src/main/java/com/example/events/UserRegisteredEvent.java
package com.example.events;

public class UserRegisteredEvent {
    private final String email;
    private final String username;

    public UserRegisteredEvent(String email, String username) {
        this.email = email;
        this.username = username;
    }

    public String getEmail() { return email; }
    public String getUsername() { return username; }
}
Enter fullscreen mode Exit fullscreen mode

2️⃣ Create an Event Publisher

// src/main/java/com/example/service/UserService.java
package com.example.service;

import com.example.events.UserRegisteredEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private final ApplicationEventPublisher publisher;

    public UserService(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void registerUser(String email, String username) {
        // Logic to save user to DB (skipped)
        System.out.println("βœ… User registered: " + username);

        // Fire event
        publisher.publishEvent(new UserRegisteredEvent(email, username));
    }
}
Enter fullscreen mode Exit fullscreen mode

3️⃣ Create Event Listeners

a. Email Notification Listener

// src/main/java/com/example/listeners/EmailNotificationListener.java
package com.example.listeners;

import com.example.events.UserRegisteredEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class EmailNotificationListener {

    @EventListener
    public void handleUserRegistered(UserRegisteredEvent event) {
        System.out.println("πŸ“§ Sending welcome email to " + event.getEmail());
        // Logic to send email
    }
}
Enter fullscreen mode Exit fullscreen mode

b. Audit Log Listener

// src/main/java/com/example/listeners/AuditLogListener.java
package com.example.listeners;

import com.example.events.UserRegisteredEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class AuditLogListener {

    @EventListener
    public void logUserRegistration(UserRegisteredEvent event) {
        System.out.println("πŸ“ Audit: New user - " + event.getUsername());
        // Write to audit log
    }
}
Enter fullscreen mode Exit fullscreen mode

4️⃣ Make It Asynchronous (Optional)

If you want to asynchronously handle events:

a. Enable Async support

// src/main/java/com/example/DemoApplication.java
@SpringBootApplication
@EnableAsync
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
Enter fullscreen mode Exit fullscreen mode

b. Annotate listener with @Async

@Async
@EventListener
public void handleUserRegistered(UserRegisteredEvent event) {
    // async logic
}
Enter fullscreen mode Exit fullscreen mode

πŸ§ͺ 5️⃣ Triggering the Event

Let’s wire this into a controller:

// src/main/java/com/example/controller/UserController.java
package com.example.controller;

import com.example.service.UserService;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/users")
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping("/register")
    public String register(@RequestParam String email, @RequestParam String username) {
        userService.registerUser(email, username);
        return "User registration successful!";
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ“Œ Summary

Step Action
βœ… 1 Create event class
βœ… 2 Publish event from business logic
βœ… 3 Create one or more listeners
βœ… 4 (Optional) Use @Async for async handling

βš™οΈ Project Structure

src/main/java/com/example
β”œβ”€β”€ controller
β”‚   └── UserController.java
β”œβ”€β”€ events
β”‚   └── UserRegisteredEvent.java
β”œβ”€β”€ listeners
β”‚   β”œβ”€β”€ AuditLogListener.java
β”‚   └── EmailNotificationListener.java
β”œβ”€β”€ service
β”‚   └── UserService.java
└── DemoApplication.java
Enter fullscreen mode Exit fullscreen mode

πŸ“ˆ Real-World Use Cases

  • Notification systems (email, SMS)
  • Audit logging
  • Domain-driven design (domain events)
  • Metrics/logging hooks
  • Microservices communication with event sourcing (with external brokers)

βœ… Best Practices

  • Keep events immutable
  • Avoid business logic in listeners
  • Use @Async wisely (thread pool tuning)
  • Consider bounded context and domain event separation in complex systems

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.