Observer Pattern Real-World Examples in Java
Fast recall
Quick revision
Core answer
PropertyChangeListener, servlet lifecycle listeners, and Spring application events. In Spring, ApplicationEventPublisher hands an event to the configured multicaster and matching @EventListener methods receive it. Delivery is synchronous by default but can be configured differently. @TransactionalEventListener binds delivery to a transaction phase; its default is AFTER_COMMIT when a transaction exists.Interview-ready guide
Interview answer
Common Observer-style examples are UI action listeners, PropertyChangeListener, servlet lifecycle listeners, and Spring application events. In Spring, ApplicationEventPublisher hands an event to the configured multicaster, which finds matching @EventListener methods. For example, an OrderPlaced event can update an in-process read model in the publishing thread. The default delivery is synchronous, although an executor or asynchronous listener can change that behavior. @TransactionalEventListener ties a callback to a transaction phase and defaults to after commit when a transaction exists; without a transaction it normally does not run unless fallback execution is enabled. For reliable publication to Kafka or another external system, an after-commit callback alone does not solve the dual-write problem, so I would consider an outbox.
Observer Pattern Real-World Examples in Java
Direct Answer
Observer-style APIs in Java include Swing and JavaFX listeners, JavaBeans PropertyChangeListener, servlet lifecycle listeners, and Spring application events. In Spring, ApplicationEventPublisher hands an event to the configured multicaster and matching @EventListener methods receive it. Delivery is synchronous by default but can be configured differently. @TransactionalEventListener binds delivery to a transaction phase; its default is AFTER_COMMIT when a transaction exists.
Code Example
@Service
class OrderService {
private final ApplicationEventPublisher publisher; // the subject
OrderService(ApplicationEventPublisher publisher) { this.publisher = publisher; }
@Transactional
public void placeOrder(Order order) {
order.setStatus(OrderStatus.CONFIRMED);
// notify every observer without naming a single one of them
publisher.publishEvent(new OrderPlacedEvent(order.getId()));
}
}
record OrderPlacedEvent(Long orderId) {} // carries the data to observers
@Component
class EmailListener { // observer 1
@EventListener // synchronous: runs in publisher's thread
void onOrder(OrderPlacedEvent e) { System.out.println("Email for " + e.orderId()); }
}
@Component
class LoyaltyListener { // observer 2
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
void onOrder(OrderPlacedEvent e) { System.out.println("Award points for " + e.orderId()); }
}
Add a third listener tomorrow — OrderService never changes. That is Observer's decoupling.
Common Mistakes & Pitfalls
- Using
java.util.Observable. It's deprecated since Java 9. Use Spring events orPropertyChangeSupport. - Assuming
@EventListeneris async. It runs synchronously in the publisher's thread; add@Async(with@EnableAsync) for background execution. - Ignoring transaction boundaries. A plain
@EventListenercan run before the DB commit. If the transaction rolls back, you've already emailed the customer. Use@TransactionalEventListener(AFTER_COMMIT). - Only quoting stock-ticker textbook examples. Name real APIs — that's what separates a fresher who has used Spring from one who memorized a diagram.
Check your understanding
Answer these without looking back at the article.
- How does @TransactionalEventListener differ from @EventListener?
- How does Observer relate to reactive programming?
- How do you make a Spring @EventListener run asynchronously?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.