All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.common.eventbus.package-info Maven / Gradle / Ivy

/*
 * Copyright (C) 2007 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

/**
 * The EventBus allows publish-subscribe-style communication between components without requiring
 * the components to explicitly register with one another (and thus be aware of each other). It is
 * designed exclusively to replace traditional Java in-process event distribution using explicit
 * registration. It is not a general-purpose publish-subscribe system, nor is it intended
 * for interprocess communication.
 *
 * 

See the Guava User Guide article on {@code EventBus}. * *

One-Minute Guide

* *

Converting an existing EventListener-based system to use the EventBus is easy. * *

For Listeners

* *

To listen for a specific flavor of event (say, a CustomerChangeEvent)... * *

    *
  • ...in traditional Java events: implement an interface defined with the * event — such as CustomerChangeEventListener. *
  • ...with EventBus: create a method that accepts CustomerChangeEvent as its * sole argument, and mark it with the {@link com.google.common.eventbus.Subscribe} * annotation. *
* *

To register your listener methods with the event producers... * *

    *
  • ...in traditional Java events: pass your object to each producer's {@code * registerCustomerChangeEventListener} method. These methods are rarely defined in common * interfaces, so in addition to knowing every possible producer, you must also know its type. *
  • ...with EventBus: pass your object to the {@link * com.google.common.eventbus.EventBus#register(Object)} method on an EventBus. You'll need to * make sure that your object shares an EventBus instance with the event producers. *
* *

To listen for a common event supertype (such as EventObject or Object)... * *

    *
  • ...in traditional Java events: not easy. *
  • ...with EventBus: events are automatically dispatched to listeners of any * supertype, allowing listeners for interface types or "wildcard listeners" for Object. *
* *

To listen for and detect events that were dispatched without listeners... * *

    *
  • ...in traditional Java events: add code to each event-dispatching method * (perhaps using AOP). *
  • ...with EventBus: subscribe to {@link * com.google.common.eventbus.DeadEvent}. The EventBus will notify you of any events that were * posted but not delivered. (Handy for debugging.) *
* *

For Producers

* *

To keep track of listeners to your events... * *

    *
  • ...in traditional Java events: write code to manage a list of listeners to * your object, including synchronization, or use a utility class like EventListenerList. *
  • ...with EventBus: EventBus does this for you. *
* *

To dispatch an event to listeners... * *

    *
  • ...in traditional Java events: write a method to dispatch events to each * event listener, including error isolation and (if desired) asynchronicity. *
  • ...with EventBus: pass the event object to an EventBus's {@link * com.google.common.eventbus.EventBus#post(Object)} method. *
* *

Glossary

* *

The EventBus system and code use the following terms to discuss event distribution: * *

*
Event *
Any object that may be posted to a bus. *
Subscribing *
The act of registering a listener with an EventBus, so that its subscriber * methods will receive events. *
Listener *
An object that wishes to receive events, by exposing subscriber methods. *
Subscriber method *
A public method that the EventBus should use to deliver posted events. Subscriber * methods are marked by the {@link com.google.common.eventbus.Subscribe} annotation. *
Posting an event *
Making the event available to any listeners through the EventBus. *
* *

FAQ

* *

Why must I create my own Event Bus, rather than using a singleton?

* *

The Event Bus doesn't specify how you use it; there's nothing stopping your application from * having separate EventBus instances for each component, or using separate instances to separate * events by context or topic. This also makes it trivial to set up and tear down EventBus objects * in your tests. * *

Of course, if you'd like to have a process-wide EventBus singleton, there's nothing stopping * you from doing it that way. Simply have your container (such as Guice) create the EventBus as a * singleton at global scope (or stash it in a static field, if you're into that sort of thing). * *

In short, the EventBus is not a singleton because we'd rather not make that decision for you. * Use it how you like. * *

Why use an annotation to mark subscriber methods, rather than requiring the listener to * implement an interface?

* *

We feel that the Event Bus's {@code @Subscribe} annotation conveys your intentions just as * explicitly as implementing an interface (or perhaps more so), while leaving you free to place * event subscriber methods wherever you wish and give them intention-revealing names. * *

Traditional Java Events use a listener interface which typically sports only a handful of * methods -- typically one. This has a number of disadvantages: * *

    *
  • Any one class can only implement a single response to a given event. *
  • Listener interface methods may conflict. *
  • The method must be named after the event (e.g. {@code handleChangeEvent}), rather than its * purpose (e.g. {@code recordChangeInJournal}). *
  • Each event usually has its own interface, without a common parent interface for a family of * events (e.g. all UI events). *
* *

The difficulties in implementing this cleanly has given rise to a pattern, particularly common * in Swing apps, of using tiny anonymous classes to implement event listener interfaces. * *

Compare these two cases: * *

{@code
 * class ChangeRecorder {
 *   void setCustomer(Customer cust) {
 *     cust.addChangeListener(new ChangeListener() {
 *       void customerChanged(ChangeEvent e) {
 *         recordChange(e.getChange());
 *       }
 *     };
 *   }
 * }
 *
 * // Class is typically registered by the container.
 * class EventBusChangeRecorder {
 *  }{@code @Subscribe void recordCustomerChange(ChangeEvent e) {
 *     recordChange(e.getChange());
 *   }
 * }
 * }
* *

The intent is actually clearer in the second case: there's less noise code, and the event * subscriber has a clear and meaningful name. * *

What about a generic {@code Subscriber} interface?

* *

Some have proposed a generic {@code Subscriber} interface for EventBus listeners. This runs * into issues with Java's use of type erasure, not to mention problems in usability. * *

Let's say the interface looked something like the following: * *

{@code
 * interface Subscriber {
 *   void handleEvent(T event);
 * }
 * }
* *

Due to erasure, no single class can implement a generic interface more than once with * different type parameters. This is a giant step backwards from traditional Java Events, where * even if {@code actionPerformed} and {@code keyPressed} aren't very meaningful names, at least you * can implement both methods! * *

Doesn't EventBus destroy static typing and eliminate automated refactoring support?

* *

Some have freaked out about EventBus's {@code register(Object)} and {@code post(Object)} * methods' use of the {@code Object} type. * *

{@code Object} is used here for a good reason: the Event Bus library places no restrictions on * the types of either your event listeners (as in {@code register(Object)}) or the events * themselves (in {@code post(Object)}). * *

Event subscriber methods, on the other hand, must explicitly declare their argument type -- * the type of event desired (or one of its supertypes). Thus, searching for references to an event * class will instantly find all subscriber methods for that event, and renaming the type will * affect all subscriber methods within view of your IDE (and any code that creates the event). * *

It's true that you can rename your {@code @Subscribed} event subscriber methods at will; Event * Bus will not stop this or do anything to propagate the rename because, to Event Bus, the names of * your subscriber methods are irrelevant. Test code that calls the methods directly, of course, * will be affected by your renaming -- but that's what your refactoring tools are for. * *

What happens if I {@code register} a listener without any subscriber methods?

* *

Nothing at all. * *

The Event Bus was designed to integrate with containers and module systems, with Guice as the * prototypical example. In these cases, it's convenient to have the container/factory/environment * pass every created object to an EventBus's {@code register(Object)} method. * *

This way, any object created by the container/factory/environment can hook into the system's * event model simply by exposing subscriber methods. * *

What Event Bus problems can be detected at compile time?

* *

Any problem that can be unambiguously detected by Java's type system. For example, defining a * subscriber method for a nonexistent event type. * *

What Event Bus problems can be detected immediately at registration?

* *

Immediately upon invoking {@code register(Object)}, the listener being registered is checked * for the well-formedness of its subscriber methods. Specifically, any methods marked with * {@code @Subscribe} must take only a single argument. * *

Any violations of this rule will cause an {@code IllegalArgumentException} to be thrown. * *

(This check could be moved to compile-time using APT, a solution we're researching.) * *

What Event Bus problems may only be detected later, at runtime?

* *

If a component posts events with no registered listeners, it may indicate an error * (typically an indication that you missed a {@code @Subscribe} annotation, or that the listening * component is not loaded). * *

(Note that this is not necessarily indicative of a problem. There are many cases where * an application will deliberately ignore a posted event, particularly if the event is coming from * code you don't control.) * *

To handle such events, register a subscriber method for the {@code DeadEvent} class. Whenever * EventBus receives an event with no registered subscribers, it will turn it into a {@code * DeadEvent} and pass it your way -- allowing you to log it or otherwise recover. * *

How do I test event listeners and their subscriber methods?

* *

Because subscriber methods on your listener classes are normal methods, you can simply call * them from your test code to simulate the EventBus. */ @CheckReturnValue @ParametersAreNonnullByDefault package com.google.common.eventbus; import com.google.errorprone.annotations.CheckReturnValue; import jakarta.annotation.ParametersAreNonnullByDefault;





© 2015 - 2024 Weber Informatics LLC | Privacy Policy