Skip to content
Christian Streibl edited this page Mar 15, 2017 · 6 revisions

Introduction

  • implementation of pub sub pattern; decouples components communication by using messages|events as senders and receivers common protocol.
  • listeners have to be subscribed explicitly; their configuration is provided declaratively using annotations
  • messages can be published by any component that has a reference to the bus; the bus will handle the lookup of appropriate receivers and deliver the messages according to the listeners configuration
  • terminology ++ handler = any method meant to handle messages (annotated respectively) ++ listener = any java class specifying or inheriting one or more handlers
  • mbassador provides fully concurrent (aka thread-safe) sync/async bus implementation and sync-only bus out-of-the-box

Instantiation

Any bus implementation provided by mbassador is quite a POJO and users may create as many instances as they see fit for their use cases. Depending on the scenario there might be different bus implementations for different scopes as in web frameworks - as described in guice-integration.

Constructors

  • each bus provides a default (non-arg) constructor to be used for the standard use cases

  • explicit configuration is recommended (and easy to do)

      // Use a default constructor for convenience and create as many instances as you like
      MBassador<TestMessage> bus = new MBassador<TestMessage>();
      SyncMessageBus<String> bus2 = new SyncMessageBus<String>();
    

Configuration

  • Based on common configuration object that is passed as constructor argument, ref-javadoc:IBusConfiguration
  • Configuration object is validated and properties are transferred/applied to the bus instance; see code of constructor of ref-javadoc:AbstractPubSubSupport
  • Mainly based on named properties but provides some convenience methods for the most important ones
  • Note: Configuration objects should not be shared across bus instances!

Features

  • Configuration composed of features relating to different capabilities provided by each bus type

  • A feature groups related properties into a coherent view and allow to provide custom constructors for convenient instantiation

  • Features can be added to a configuration object

        new BusConfiguration()
           .addFeature(Feature.SyncPubSub.Default()) // configure the synchronous message publication
           .addFeature(Feature.AsynchronousHandlerInvocation.Default()) // configure asynchronous invocation of handlers
           .addFeature(Feature.AsynchronousMessageDispatch.Default()) // configure asyncronous message publication (fire&forget)
           .addPublicationErrorHandler(new IPublicationErrorHandler{...})
           .setProperty(Properties.Common.Id, "global bus")); // this is used for identification in #toString
    

Listeners

  • Any class with handlers (defined or inherited)

      public class StandardMessageListener extends BaseListener {
    
          @Handler(rejectSubtypes = true, priority = 4)
          public void handle(StandardMessage message){
              ...
          }
      }
    
  • Referenced using weak references by default -> subscribed listeners will be GC'ed if not referenced outside the bus

  • Strong references can be configured explicitly using @Listener annotation, ref-javadoc

       @Listener(reference = Reference.Strong)
       public class StandardMessageListener extends BaseListener {
    
          // any number of handlers and other code...
          
       }
    

Handlers

  • specified using annotations: ref-javadoc (@Handler, @Enveloped)

  • support for inheritance from super classes (interfaces not yet supported, see #67)

  • simple no arg annotation for most common use cases

      @Handler
      public void handleTestMessage(TestMessage message) {
      	// do something
      }
    
  • more elaborate configurations possible

      @Handler(delivery = Invoke.Asynchronously, rejectSubtypes = true)
      @Enveloped(messages = {TestMessage.class, TestMessage2.class})
      public void handleVariousEvents(MessageEnvelope envelope) {
          // the envelope will contain either an instance of TestMessage or TestMessage2
          // if rejectSubtypes were set to 'false' (default) also subtypes of TestMessage or TestMessage2 would be allowed
      }
    
  • read Handlers for more details on configuration inheritance and

Subscription

  • The process of adding a listener (instance with defined handlers) to a bus
  • Configuration is read from class metadata (annotations) and applied to the internal reference

Message publication

Publication modes

Dispatch

Filtering

Error handling

Extensions

Custom invocation

Custom annotations

A message bus offers facilities for publishing messages to registered listeners. Messages can be dispatched synchronously or asynchronously and the dispatch mechanism can by controlled for each message handler and per message publication.

Each message publication is isolated from all other running publications such that it does not interfere with them. Hence, the bus expects message handlers to be stateless as they may be invoked concurrently if multiple messages of the same type get published asynchronously.

Messages are published to all listeners that accept the type or super type of the published message. Additionally a message handler may define filters to narrow the set of messages that it accepts.

Subscribed listeners are available to all pending message publications that have not yet started processing. Any message listener may only be subscribed once - subsequent subscriptions of an already subscribed message listener will be silently ignored.

The basic contract of the bus is that it will deliver a specific message exactly once to each of the subscribed message handlers. Currently, message handlers will be invoked in inverse sequence of subscription but any client using this bus should not rely on this assumption.

The bus uses weak references to all listeners such that registered listeners do not need to be explicitly unregistered to be eligible for garbage collection. Dead (garbage collected) listeners are removed on-the-fly as messages get published.

Unsubscribing a listener means removing all subscribed message handlers of that listener. This remove operation immediately effects all running publications processes -> A removed listener will under no circumstances receive any message publications. A listener is considered removed after the unsubscribe(Object) call returned.Any running message publication that has not yet delivered the message to the recently removed listener will not see the listener after the remove operation completed.

Terminology

Listener configuration

Feel welcome to participate in extending the documentation on how to use/customize MBassador.