Careeroza
Application Events
Why Events
When an order is placed, many things should happen: send email, award loyalty points, update analytics, notify the warehouse. If OrderService calls each one directly, it depends on every other module. With events, OrderService just announces "an order was placed" and other modules listen.
OrderService --publish--> OrderPlacedEvent
|
+---------------------+---------------------+
v v v
EmailListener LoyaltyListener WarehouseListenerPublishing an Event
public record OrderPlacedEvent(Long orderId, Long userId, BigDecimal total) {} // any object can be an event
@Service
@RequiredArgsConstructor
public class OrderService {
private final OrderRepository orders;
private final ApplicationEventPublisher events;
@Transactional
public OrderResponse placeOrder(PlaceOrderRequest req) {
Order order = orders.save(Order.from(req));
events.publishEvent(new OrderPlacedEvent(order.getId(), req.userId(), order.getTotal()));
return OrderResponse.from(order);
}
}An Event Publisher in Plain Java
Example
Spring's publisher keeps a list of listeners per event type and calls each one. The core idea fits in a few lines:
import java.math.BigDecimal;
import java.util.*;
import java.util.function.*;
public class Main {
public static void main(String[] args) {
EventBus bus = new EventBus();
bus.subscribe(OrderPlacedEvent.class, e -> System.out.println("Email: order " + e.orderId() + " confirmed"));
bus.subscribe(OrderPlacedEvent.class, e -> System.out.println("Loyalty: +" + e.total().intValue() / 100 + " points for user " + e.userId()));
bus.subscribe(OrderCancelledEvent.class, e -> System.out.println("Warehouse: stop packing order " + e.orderId()));
bus.publish(new OrderPlacedEvent(1001L, 7L, new BigDecimal("2499.00")));
bus.publish(new OrderCancelledEvent(1001L));
}
}
record OrderPlacedEvent(Long orderId, Long userId, BigDecimal total) {}
record OrderCancelledEvent(Long orderId) {}
class EventBus {
private final Map<Class<?>, List<Consumer<Object>>> listeners = new LinkedHashMap<>();
@SuppressWarnings("unchecked")
<T> void subscribe(Class<T> type, Consumer<T> listener) {
listeners.computeIfAbsent(type, k -> new ArrayList<>()).add(e -> listener.accept((T) e));
}
void publish(Object event) {
System.out.println("publish " + event.getClass().getSimpleName());
listeners.getOrDefault(event.getClass(), List.of()).forEach(l -> l.accept(event));
}
}Output
publish OrderPlacedEvent Email: order 1001 confirmed Loyalty: +24 points for user 7 publish OrderCancelledEvent Warehouse: stop packing order 1001