The API supports events of any type, however all events that Micronaut publishes extend ApplicationEvent.

    To publish an event, obtain an instance of either directly from the context or through dependency injection, and execute the method with your event object.

    Publishing an Event

    Publishing an Event

    1. class SampleEvent {
    2. String message = "Something happened"
    3. }
    4. import io.micronaut.context.event.ApplicationEventPublisher
    5. import javax.inject.Inject
    6. import javax.inject.Singleton
    7. @Singleton
    8. class SampleEventEmitterBean {
    9. @Inject
    10. ApplicationEventPublisher eventPublisher
    11. void publishSampleEvent() {
    12. eventPublisher.publishEvent(new SampleEvent())
    13. }
    14. }

    Publishing an Event

    1. data class SampleEvent(val message: String = "Something happened")
    2. import io.micronaut.context.event.ApplicationEventPublisher
    3. import javax.inject.Inject
    4. import javax.inject.Singleton
    5. @Singleton
    6. class SampleEventEmitterBean {
    7. @Inject
    8. internal var eventPublisher: ApplicationEventPublisher? = null
    9. fun publishSampleEvent() {
    10. eventPublisher!!.publishEvent(SampleEvent())
    11. }
    12. }

    Listening for Events

    Listening for Events with ApplicationEventListener

    1. import io.micronaut.context.event.ApplicationEventListener;
    2. import io.micronaut.docs.context.events.SampleEvent;
    3. @Singleton
    4. public class SampleEventListener implements ApplicationEventListener<SampleEvent> {
    5. private int invocationCounter = 0;
    6. @Override
    7. public void onApplicationEvent(SampleEvent event) {
    8. invocationCounter++;
    9. }
    10. public int getInvocationCounter() {
    11. return invocationCounter;
    12. }
    13. }
    14. import io.micronaut.context.ApplicationContext;
    15. import io.micronaut.docs.context.events.SampleEventEmitterBean;
    16. import org.junit.Test;
    17. import static org.junit.Assert.assertEquals;
    18. public class SampleEventListenerSpec {
    19. @Test
    20. public void testEventListenerIsNotified() {
    21. try (ApplicationContext context = ApplicationContext.run()) {
    22. SampleEventEmitterBean emitter = context.getBean(SampleEventEmitterBean.class);
    23. SampleEventListener listener = context.getBean(SampleEventListener.class);
    24. assertEquals(0, listener.getInvocationCounter());
    25. emitter.publishSampleEvent();
    26. assertEquals(1, listener.getInvocationCounter());
    27. }
    28. }
    29. }

    Listening for Events with ApplicationEventListener

    Listening for Events with ApplicationEventListener

    1. import io.micronaut.context.event.ApplicationEventListener
    2. import io.micronaut.docs.context.events.SampleEvent
    3. @Singleton
    4. class SampleEventListener : ApplicationEventListener<SampleEvent> {
    5. var invocationCounter = 0
    6. override fun onApplicationEvent(event: SampleEvent) {
    7. invocationCounter++
    8. }
    9. }
    10. import io.kotlintest.shouldBe
    11. import io.kotlintest.specs.AnnotationSpec
    12. import io.micronaut.context.ApplicationContext
    13. import io.micronaut.docs.context.events.SampleEventEmitterBean
    14. class SampleEventListenerSpec : AnnotationSpec() {
    15. val context = ApplicationContext.run()
    16. val emitter = context.getBean(SampleEventEmitterBean::class.java)
    17. val listener = context.getBean(SampleEventListener::class.java)
    18. listener.invocationCounter.shouldBe(0)
    19. emitter.publishSampleEvent()
    20. listener.invocationCounter.shouldBe(1)
    21. context.close()
    22. }
    23. }
    The method can be overridden to further clarify events that should be processed.

    Alternatively you can use the @EventListener annotation if you do not wish to specifically implement an interface or utilize one of the built in events like and ShutdownEvent:

    Listening for Events with @EventListener

    1. import io.micronaut.docs.context.events.SampleEvent;
    2. import io.micronaut.context.event.StartupEvent;
    3. import io.micronaut.context.event.ShutdownEvent;
    4. import io.micronaut.runtime.event.annotation.EventListener;
    5. @Singleton
    6. public class SampleEventListener {
    7. private int invocationCounter = 0;
    8. @EventListener
    9. public void onSampleEvent(SampleEvent event) {
    10. invocationCounter++;
    11. }
    12. @EventListener
    13. public void onStartupEvent(StartupEvent event) {
    14. // startup logic here
    15. }
    16. @EventListener
    17. public void onShutdownEvent(ShutdownEvent event) {
    18. // shutdown logic here
    19. }
    20. public int getInvocationCounter() {
    21. return invocationCounter;
    22. }
    23. }
    1. import io.micronaut.docs.context.events.SampleEvent
    2. import io.micronaut.context.event.StartupEvent
    3. import io.micronaut.context.event.ShutdownEvent
    4. import io.micronaut.runtime.event.annotation.EventListener
    5. @Singleton
    6. class SampleEventListener {
    7. int invocationCounter = 0
    8. @EventListener
    9. void onSampleEvent(SampleEvent event) {
    10. invocationCounter++
    11. }
    12. @EventListener
    13. void onStartupEvent(StartupEvent event) {
    14. // startup logic here
    15. }
    16. @EventListener
    17. void onShutdownEvent(ShutdownEvent event) {
    18. // shutdown logic here
    19. }
    20. }

    Listening for Events with @EventListener

    If your listener performs work that could take a while then you can use the annotation to run the operation on a separate thread:

    Asynchronously listening for Events with @EventListener

    1. import io.micronaut.docs.context.events.SampleEvent;
    2. import io.micronaut.runtime.event.annotation.EventListener;
    3. import io.micronaut.scheduling.annotation.Async;
    4. @Singleton
    5. public class SampleEventListener {
    6. private AtomicInteger invocationCounter = new AtomicInteger(0);
    7. @EventListener
    8. @Async
    9. public void onSampleEvent(SampleEvent event) {
    10. invocationCounter.getAndIncrement();
    11. }
    12. public int getInvocationCounter() {
    13. return invocationCounter.get();
    14. }
    15. }
    16. import io.micronaut.context.ApplicationContext;
    17. import io.micronaut.docs.context.events.SampleEventEmitterBean;
    18. import org.junit.Test;
    19. import static org.junit.Assert.assertEquals;
    20. import static java.util.concurrent.TimeUnit.SECONDS;
    21. import static org.awaitility.Awaitility.await;
    22. import static org.hamcrest.Matchers.equalTo;
    23. public class SampleEventListenerSpec {
    24. @Test
    25. public void testEventListenerIsNotified() {
    26. SampleEventEmitterBean emitter = context.getBean(SampleEventEmitterBean.class);
    27. SampleEventListener listener = context.getBean(SampleEventListener.class);
    28. assertEquals(0, listener.getInvocationCounter());
    29. emitter.publishSampleEvent();
    30. await().atMost(10, SECONDS).until(listener::getInvocationCounter, equalTo(1));
    31. }
    32. }
    33. }

    Asynchronously listening for Events with @EventListener

    1. import io.micronaut.docs.context.events.SampleEvent
    2. import io.micronaut.runtime.event.annotation.EventListener
    3. import io.micronaut.scheduling.annotation.Async
    4. @Singleton
    5. class SampleEventListener {
    6. AtomicInteger invocationCounter = new AtomicInteger(0)
    7. @EventListener
    8. @Async
    9. void onSampleEvent(SampleEvent event) {
    10. invocationCounter.getAndIncrement()
    11. }
    12. }
    13. import io.micronaut.context.ApplicationContext
    14. import io.micronaut.docs.context.events.SampleEventEmitterBean
    15. import spock.lang.Specification
    16. import spock.util.concurrent.PollingConditions
    17. class SampleEventListenerSpec extends Specification {
    18. void "test event listener is notified"() {
    19. given:
    20. ApplicationContext context = ApplicationContext.run()
    21. SampleEventEmitterBean emitter = context.getBean(SampleEventEmitterBean)
    22. SampleEventListener listener = context.getBean(SampleEventListener)
    23. assert listener.invocationCounter.get() == 0
    24. when:
    25. emitter.publishSampleEvent()
    26. then:
    27. new PollingConditions().eventually {
    28. listener.invocationCounter.get() == 1
    29. }
    30. cleanup:
    31. context.close()
    32. }
    33. }

    Asynchronously listening for Events with @EventListener

    1. import io.micronaut.docs.context.events.SampleEvent
    2. import io.micronaut.runtime.event.annotation.EventListener
    3. import io.micronaut.scheduling.annotation.Async
    4. import java.util.concurrent.atomic.AtomicInteger
    5. @Singleton
    6. open class SampleEventListener {
    7. var invocationCounter = AtomicInteger(0)
    8. @EventListener
    9. @Async
    10. open fun onSampleEvent(event: SampleEvent) {
    11. println("Incrementing invocation counter...")
    12. invocationCounter.getAndIncrement()
    13. }
    14. }
    15. import io.kotlintest.eventually
    16. import io.kotlintest.seconds
    17. import io.kotlintest.shouldBe
    18. import io.kotlintest.specs.AnnotationSpec
    19. import io.micronaut.context.ApplicationContext
    20. import io.micronaut.docs.context.events.SampleEventEmitterBean
    21. import org.opentest4j.AssertionFailedError
    22. class SampleEventListenerSpec : AnnotationSpec() {
    23. @Test
    24. // @Ignore // TODO can't get this to pass on CI, any help is welcome
    25. fun testEventListenerWasNotified() {
    26. val context = ApplicationContext.run()
    27. val emitter = context.getBean(SampleEventEmitterBean::class.java)
    28. val listener = context.getBean(SampleEventListener::class.java)
    29. listener.invocationCounter.get().shouldBe(0)
    30. emitter.publishSampleEvent()
    31. eventually(5.seconds, AssertionFailedError::class.java) {
    32. println("Current value of counter: " + listener.invocationCounter.get())
    33. listener.invocationCounter.get().shouldBe(1)
    34. }
    35. context.close()
    36. }

    Configuring Scheduled Task Thread Pool