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
class SampleEvent {
String message = "Something happened"
}
import io.micronaut.context.event.ApplicationEventPublisher
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class SampleEventEmitterBean {
@Inject
ApplicationEventPublisher eventPublisher
void publishSampleEvent() {
eventPublisher.publishEvent(new SampleEvent())
}
}
Publishing an Event
data class SampleEvent(val message: String = "Something happened")
import io.micronaut.context.event.ApplicationEventPublisher
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class SampleEventEmitterBean {
@Inject
internal var eventPublisher: ApplicationEventPublisher? = null
fun publishSampleEvent() {
eventPublisher!!.publishEvent(SampleEvent())
}
}
Listening for Events
Listening for Events with ApplicationEventListener
import io.micronaut.context.event.ApplicationEventListener;
import io.micronaut.docs.context.events.SampleEvent;
@Singleton
public class SampleEventListener implements ApplicationEventListener<SampleEvent> {
private int invocationCounter = 0;
@Override
public void onApplicationEvent(SampleEvent event) {
invocationCounter++;
}
public int getInvocationCounter() {
return invocationCounter;
}
}
import io.micronaut.context.ApplicationContext;
import io.micronaut.docs.context.events.SampleEventEmitterBean;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class SampleEventListenerSpec {
@Test
public void testEventListenerIsNotified() {
try (ApplicationContext context = ApplicationContext.run()) {
SampleEventEmitterBean emitter = context.getBean(SampleEventEmitterBean.class);
SampleEventListener listener = context.getBean(SampleEventListener.class);
assertEquals(0, listener.getInvocationCounter());
emitter.publishSampleEvent();
assertEquals(1, listener.getInvocationCounter());
}
}
}
Listening for Events with ApplicationEventListener
Listening for Events with ApplicationEventListener
import io.micronaut.context.event.ApplicationEventListener
import io.micronaut.docs.context.events.SampleEvent
@Singleton
class SampleEventListener : ApplicationEventListener<SampleEvent> {
var invocationCounter = 0
override fun onApplicationEvent(event: SampleEvent) {
invocationCounter++
}
}
import io.kotlintest.shouldBe
import io.kotlintest.specs.AnnotationSpec
import io.micronaut.context.ApplicationContext
import io.micronaut.docs.context.events.SampleEventEmitterBean
class SampleEventListenerSpec : AnnotationSpec() {
val context = ApplicationContext.run()
val emitter = context.getBean(SampleEventEmitterBean::class.java)
val listener = context.getBean(SampleEventListener::class.java)
listener.invocationCounter.shouldBe(0)
emitter.publishSampleEvent()
listener.invocationCounter.shouldBe(1)
context.close()
}
}
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
import io.micronaut.docs.context.events.SampleEvent;
import io.micronaut.context.event.StartupEvent;
import io.micronaut.context.event.ShutdownEvent;
import io.micronaut.runtime.event.annotation.EventListener;
@Singleton
public class SampleEventListener {
private int invocationCounter = 0;
@EventListener
public void onSampleEvent(SampleEvent event) {
invocationCounter++;
}
@EventListener
public void onStartupEvent(StartupEvent event) {
// startup logic here
}
@EventListener
public void onShutdownEvent(ShutdownEvent event) {
// shutdown logic here
}
public int getInvocationCounter() {
return invocationCounter;
}
}
import io.micronaut.docs.context.events.SampleEvent
import io.micronaut.context.event.StartupEvent
import io.micronaut.context.event.ShutdownEvent
import io.micronaut.runtime.event.annotation.EventListener
@Singleton
class SampleEventListener {
int invocationCounter = 0
@EventListener
void onSampleEvent(SampleEvent event) {
invocationCounter++
}
@EventListener
void onStartupEvent(StartupEvent event) {
// startup logic here
}
@EventListener
void onShutdownEvent(ShutdownEvent event) {
// shutdown logic here
}
}
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
import io.micronaut.docs.context.events.SampleEvent;
import io.micronaut.runtime.event.annotation.EventListener;
import io.micronaut.scheduling.annotation.Async;
@Singleton
public class SampleEventListener {
private AtomicInteger invocationCounter = new AtomicInteger(0);
@EventListener
@Async
public void onSampleEvent(SampleEvent event) {
invocationCounter.getAndIncrement();
}
public int getInvocationCounter() {
return invocationCounter.get();
}
}
import io.micronaut.context.ApplicationContext;
import io.micronaut.docs.context.events.SampleEventEmitterBean;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.Matchers.equalTo;
public class SampleEventListenerSpec {
@Test
public void testEventListenerIsNotified() {
SampleEventEmitterBean emitter = context.getBean(SampleEventEmitterBean.class);
SampleEventListener listener = context.getBean(SampleEventListener.class);
assertEquals(0, listener.getInvocationCounter());
emitter.publishSampleEvent();
await().atMost(10, SECONDS).until(listener::getInvocationCounter, equalTo(1));
}
}
}
Asynchronously listening for Events with @EventListener
import io.micronaut.docs.context.events.SampleEvent
import io.micronaut.runtime.event.annotation.EventListener
import io.micronaut.scheduling.annotation.Async
@Singleton
class SampleEventListener {
AtomicInteger invocationCounter = new AtomicInteger(0)
@EventListener
@Async
void onSampleEvent(SampleEvent event) {
invocationCounter.getAndIncrement()
}
}
import io.micronaut.context.ApplicationContext
import io.micronaut.docs.context.events.SampleEventEmitterBean
import spock.lang.Specification
import spock.util.concurrent.PollingConditions
class SampleEventListenerSpec extends Specification {
void "test event listener is notified"() {
given:
ApplicationContext context = ApplicationContext.run()
SampleEventEmitterBean emitter = context.getBean(SampleEventEmitterBean)
SampleEventListener listener = context.getBean(SampleEventListener)
assert listener.invocationCounter.get() == 0
when:
emitter.publishSampleEvent()
then:
new PollingConditions().eventually {
listener.invocationCounter.get() == 1
}
cleanup:
context.close()
}
}
Asynchronously listening for Events with @EventListener
import io.micronaut.docs.context.events.SampleEvent
import io.micronaut.runtime.event.annotation.EventListener
import io.micronaut.scheduling.annotation.Async
import java.util.concurrent.atomic.AtomicInteger
@Singleton
open class SampleEventListener {
var invocationCounter = AtomicInteger(0)
@EventListener
@Async
open fun onSampleEvent(event: SampleEvent) {
println("Incrementing invocation counter...")
invocationCounter.getAndIncrement()
}
}
import io.kotlintest.eventually
import io.kotlintest.seconds
import io.kotlintest.shouldBe
import io.kotlintest.specs.AnnotationSpec
import io.micronaut.context.ApplicationContext
import io.micronaut.docs.context.events.SampleEventEmitterBean
import org.opentest4j.AssertionFailedError
class SampleEventListenerSpec : AnnotationSpec() {
@Test
// @Ignore // TODO can't get this to pass on CI, any help is welcome
fun testEventListenerWasNotified() {
val context = ApplicationContext.run()
val emitter = context.getBean(SampleEventEmitterBean::class.java)
val listener = context.getBean(SampleEventListener::class.java)
listener.invocationCounter.get().shouldBe(0)
emitter.publishSampleEvent()
eventually(5.seconds, AssertionFailedError::class.java) {
println("Current value of counter: " + listener.invocationCounter.get())
listener.invocationCounter.get().shouldBe(1)
}
context.close()
}
Configuring Scheduled Task Thread Pool