# What Is Guava's EventBus? A Complete Guide to Google's Publish-Subscribe Framework

> Learn about Guava's EventBus, a publish-subscribe framework for decoupled component communication. Explore synchronous and asynchronous event dispatch with annotated methods.

- Repository: [Google/guava](https://github.com/google/guava)
- Tags: deep-dive
- Published: 2026-08-10

---

**Guava's EventBus is a lightweight, in-process publish-subscribe messaging system that enables decoupled component communication through annotated subscriber methods and synchronous or asynchronous event dispatch.**

Guava's EventBus eliminates the need for complex observer patterns or explicit listener interfaces in Java applications. According to the google/guava source code, this framework allows objects to communicate without direct references by routing events through a central bus. Whether building modular monoliths or decoupling internal services, EventBus provides a type-safe, annotation-driven alternative to traditional event handling.

## Core Architecture: How EventBus Works

At its heart, the EventBus implementation in [`guava/src/com/google/common/eventbus/EventBus.java`](https://github.com/google/guava/blob/main/guava/src/com/google/common/eventbus/EventBus.java) maintains a `SubscriberRegistry` that maps event types to subscriber methods. When an event is posted, the registry returns an iterator of `Subscriber` objects, which a `Dispatcher` then invokes on the configured executor.

The system relies on three primary operations: **registering listeners**, **posting events**, and **handling exceptions**. Each subscriber method must be annotated with `@Subscribe` and accept exactly one argument representing the event type. The bus uses the argument's class type to determine routing, delivering the event to every subscriber whose method parameter is assignable from the posted event's class.

## Registering Listeners with @Subscribe

Listeners expose public methods annotated with `@Subscribe` (defined in [`guava/src/com/google/common/eventbus/Subscribe.java`](https://github.com/google/guava/blob/main/guava/src/com/google/common/eventbus/Subscribe.java)). These methods must accept a single argument that defines the event type they handle.

Registration occurs through `EventBus.register(Object)`, which scans the provided object for `@Subscribe` annotations and caches the subscriber methods in the `SubscriberRegistry`.

```java
// Define an event class
public class MessageEvent {
    public final String text;
    public MessageEvent(String text) { this.text = text; }
}

// Listener with a @Subscribe method
public class MessageListener {
    @Subscribe
    public void handle(MessageEvent event) {
        System.out.println("Received: " + event.text);
    }
}

// Set up the bus and register the listener
EventBus bus = new EventBus();               // synchronous bus
bus.register(new MessageListener());

```

## Posting Events and Dispatching

Events are delivered via `EventBus.post(Object)`, which routes the object to all matching subscribers. The `Dispatcher` class (located in [`guava/src/com/google/common/eventbus/Dispatcher.java`](https://github.com/google/guava/blob/main/guava/src/com/google/common/eventbus/Dispatcher.java)) handles the actual invocation of subscriber methods, respecting the executor and concurrency rules.

By default, dispatch is **synchronous** and occurs on the caller's thread. The implementation guarantees that a subscriber method will not be invoked concurrently unless explicitly marked with `@AllowConcurrentEvents`.

```java
// Post an event
bus.post(new MessageEvent("Hello Guava!"));

```

## Asynchronous Event Processing with AsyncEventBus

For non-blocking event delivery, Guava provides `AsyncEventBus` (implemented in [`guava/src/com/google/common/eventbus/AsyncEventBus.java`](https://github.com/google/guava/blob/main/guava/src/com/google/common/eventbus/AsyncEventBus.java)). This extension accepts an `Executor` and delivers events via that thread pool, allowing the posting thread to return immediately.

```java
// Asynchronous version – uses a thread pool executor
Executor executor = Executors.newFixedThreadPool(4);
AsyncEventBus asyncBus = new AsyncEventBus(executor);
asyncBus.register(new MessageListener());

// Posting is non‑blocking; listeners run on the executor thread pool
asyncBus.post(new MessageEvent("Async hello"));

```

## Handling Dead Events

When no subscriber matches a posted event type, Guava wraps the event in a `DeadEvent` and reposts it. This mechanism, implemented in the core `EventBus` class, provides a catch-all for "unhandled" events. Subscribers can listen for `DeadEvent` instances to log or process orphaned messages.

```java
// Handling dead events
public class DeadEventListener {
    @Subscribe
    public void onDeadEvent(DeadEvent dead) {
        System.out.println("No subscriber for: " + dead.getEvent());
    }
}
bus.register(new DeadEventListener());
// If no subscriber matches, this will be invoked
bus.post("Unsubscribed payload");

```

## Exception Handling and Thread Safety

Exception handling is delegated to a `SubscriberExceptionHandler` (defaulting to `LoggingHandler`). If a subscriber throws an exception, the bus catches it and routes it to the configured handler without interrupting delivery to other subscribers.

Regarding concurrency: unless a subscriber method carries the `@AllowConcurrentEvents` annotation, the EventBus ensures the method will not be invoked concurrently, even when using `AsyncEventBus`. This provides thread-safety guarantees without requiring explicit synchronization in listener code.

## Summary

- **Guava EventBus** is an in-process publish-subscribe system that decouples components through a central messaging bus.
- Subscribers use the `@Subscribe` annotation on single-argument methods, registered via `EventBus.register()`.
- Events are posted via `EventBus.post()` and dispatched synchronously by default; `AsyncEventBus` enables thread-pool-based asynchronous delivery.
- Unmatched events become `DeadEvent` objects that can be captured by specialized listeners.
- The implementation in [`guava/src/com/google/common/eventbus/EventBus.java`](https://github.com/google/guava/blob/main/guava/src/com/google/common/eventbus/EventBus.java) uses `SubscriberRegistry` for type mapping and `Dispatcher` for method invocation, with pluggable exception handling via `SubscriberExceptionHandler`.

## Frequently Asked Questions

### What is the difference between EventBus and AsyncEventBus in Guava?

`EventBus` delivers events synchronously on the calling thread, blocking until all subscribers complete. `AsyncEventBus` (located in [`guava/src/com/google/common/eventbus/AsyncEventBus.java`](https://github.com/google/guava/blob/main/guava/src/com/google/common/eventbus/AsyncEventBus.java)) accepts an `Executor` and dispatches events asynchronously, allowing the posting thread to continue immediately while subscriber methods execute on the provided thread pool.

### How does Guava EventBus handle exceptions thrown by subscribers?

The EventBus catches all exceptions thrown by subscriber methods and delegates them to a `SubscriberExceptionHandler`. By default, this uses `LoggingHandler` to log errors, but you can provide a custom handler via the constructor. This ensures that one failing subscriber does not prevent other subscribers from receiving the event.

### Can multiple threads invoke the same subscriber method concurrently?

By default, no. The EventBus guarantees that a subscriber method will not be invoked concurrently unless it is explicitly annotated with `@AllowConcurrentEvents`. This applies even when using `AsyncEventBus`, providing thread-safety for subscriber state without requiring explicit synchronization.

### What happens if I post an event with no registered listeners?

If no subscriber matches the posted event's type, Guava wraps the event in a `DeadEvent` object and reposts it. You can register a listener that accepts `DeadEvent` as its parameter to capture and handle these orphaned events, useful for debugging or logging unhandled messages.