Events

Modules in an Across application often use events to communicate with each other. To this end, Across fully supports the Spring framework event listening features.

This chapter lists the most common event features, please refer to the Spring framework documentation for all details.

Subscribing to events

The most common way to subscribe to an event is by simply providing an @EventListener annotated method. A single object can have many listener methods. All beans created in the ApplicationContext are automatically scanned for event listener methods.

Example component with an event listener method
@Component
public class MyHandler {
    @EventListener
    public void handle( SomeEvent event ) {
        // Called whenever an event of type SomeEvent is published
    }
}

Publishing events

Publishing events is done via the ApplicationEventPublisher bean.

@Autowired
private ApplicationEventPublisher eventPublisher;

public void sendEvent() {
  eventPublisher.publishEvent( new SomeEvent() );
}

Filtering events

Event listeners can subscribe to specific events using one of several mechanisms:

Setting a specific (base) class as the event argument on an @EventListener method
@EventListener
public void handle( SomeEvent event ) {
    // Called whenever an event of type SomeEvent is published
}
Setting one or more base classes on the @EventListener annotation
@EventListener( {SomeEvent.class, SomeOtherEvent.class} )
public void handleEvents() {
    // In this case a method parameter is not actually required
}
Using the SpEL condition attribute on the @EventListener annotation
@EventListener(condition = "#event.eventName == 'myEvent'")
public void handle( NamedEvent event ) {
    // Called if the event is of type NamedEvent
    // and property 'eventName' has the value 'myEvent'
}
Using a generic event with type parameters
@EventListener
public void onManCreated( EntityCreatedEvent<Man> event ) {
    // Called if the generic type is exactly Man
}

@EventListener
public void onHumanCreated( EntityCreatedEvent<? extends Human> event ) {
    // Called whenever the generic type implements Human
}


// The event must implement ResolvableTypeProvider if it is not a specific class
public class EntityCreatedEvent<T> implements ResolvableTypeProvider {
    private final T entity;

    public EntityCreatedEvent( T entity ) {
        this.entity = entity;
    }

    @Override
    public ResolvableType getResolvableType() {
        return ResolvableType.forClassWithGenerics( getClass(), ResolvableType.forInstance( entity ) );
    }
}

Asynchronous listeners

You can use a @Async to handle events asynchronously. This has some limitations, see the Spring framework documentation.

Please note as well that asynchronous execution must be enabled in the module where you register the event listener.

Ordering listeners

Ordering of listeners is one of the aspects where an Across application differs from default Spring ApplicationContext behaviour.

When a module publishes an event, it will be received by all other modules in bootstrap order. This means that event listeners from a previous module might handle the event before listeners from the module that actually published it. By default, listener methods from the same across module do not have a specific order assigned.

The default ordering is reliable and works best for most use cases: you can rely on event listeners from previous modules having been executed before you. Thus, listeners registered in your application module will usually fire last.

Once an event has been handled by all modules, it will be sent to the (optional) parent ApplicationContext.

Events published directly from a parent ApplicationContext - for example directly from within your @AcrossApplication class - will not be sent downstream to the modules!

Just like with other Across related ordering, you can influence the default behaviour:

  • use @OrderInModule on your methods to order listener execution within the same module

  • use @Order on your methods to suppress the default module bootstrap order and order listeners explicitly