Micronaut 通过上下文支持一个通用的事件系统。 ApplicationEventPublisher API 发布事件,ApplicationEventListener API 用于监听事件。事件系统不限于 Micronaut 发布的事件,支持用户创建的自定义事件。
发布活动
ApplicationEventPublisher API 支持任何类型的事件,尽管 Micronaut 发布的所有事件都扩展了 ApplicationEvent。
要发布事件,请使用依赖项注入获取 ApplicationEventPublisher 的实例,其中通用类型是事件类型,并使用您的事件对象调用 publishEvent 方法。
发布事件
Java |
Groovy |
Kotlin |
public class SampleEvent {
private String message = "Something happened";
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
import io.micronaut.context.event.ApplicationEventPublisher;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
@Singleton
public class SampleEventEmitterBean {
@Inject
ApplicationEventPublisher<SampleEvent> eventPublisher;
public void publishSampleEvent() {
eventPublisher.publishEvent(new SampleEvent());
}
}
|
class SampleEvent {
String message = "Something happened"
}
import io.micronaut.context.event.ApplicationEventPublisher
import jakarta.inject.Inject
import jakarta.inject.Singleton
@Singleton
class SampleEventEmitterBean {
@Inject
ApplicationEventPublisher<SampleEvent> eventPublisher
void publishSampleEvent() {
eventPublisher.publishEvent(new SampleEvent())
}
}
|
data class SampleEvent(val message: String = "Something happened")
import io.micronaut.context.event.ApplicationEventPublisher
import jakarta.inject.Inject
import jakarta.inject.Singleton
@Singleton
class SampleEventEmitterBean {
@Inject
internal var eventPublisher: ApplicationEventPublisher<SampleEvent>? = null
fun publishSampleEvent() {
eventPublisher!!.publishEvent(SampleEvent())
}
}
|
默认情况下发布事件是同步的! publishEvent 方法将在所有侦听器都已执行后才会返回。如果这项工作很耗时,请将其移至线程池。
监听事件
要侦听事件,请注册一个实现 ApplicationEventListener 的 bean,其中通用类型是事件的类型。
使用 ApplicationEventListener 监听事件
Java |
Groovy |
Kotlin |
import io.micronaut.context.event.ApplicationEventListener;
import io.micronaut.docs.context.events.SampleEvent;
import jakarta.inject.Singleton;
@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());
}
}
}
|
import io.micronaut.context.event.ApplicationEventListener
import io.micronaut.docs.context.events.SampleEvent
import jakarta.inject.Singleton
@Singleton
class SampleEventListener implements ApplicationEventListener<SampleEvent> {
int invocationCounter = 0
@Override
void onApplicationEvent(SampleEvent event) {
invocationCounter++
}
}
import io.micronaut.context.ApplicationContext
import io.micronaut.docs.context.events.SampleEventEmitterBean
import spock.lang.Specification
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)
expect:
listener.invocationCounter == 0
when:
emitter.publishSampleEvent()
then:
listener.invocationCounter == 1
cleanup:
context.close()
}
}
|
import io.micronaut.context.event.ApplicationEventListener
import io.micronaut.docs.context.events.SampleEvent
import jakarta.inject.Singleton
@Singleton
class SampleEventListener : ApplicationEventListener<SampleEvent> {
var invocationCounter = 0
override fun onApplicationEvent(event: SampleEvent) {
invocationCounter++
}
}
import io.kotest.matchers.shouldBe
import io.kotest.core.spec.style.AnnotationSpec
import io.micronaut.context.ApplicationContext
import io.micronaut.docs.context.events.SampleEventEmitterBean
class SampleEventListenerSpec : AnnotationSpec() {
@Test
fun testEventListenerWasNotified() {
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()
}
}
|
可以覆盖 supports 方法以进一步阐明要处理的事件。
或者,如果您不想实现接口或不使用 StartupEvent 和 ShutdownEvent 等内置事件之一,请使用 @EventListener 注释:
使用@EventListener 监听事件
Java |
Groovy |
Kotlin |
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
}
}
|
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 {
var invocationCounter = 0
@EventListener
internal fun onSampleEvent(event: SampleEvent) {
invocationCounter++
}
@EventListener
internal fun onStartupEvent(event: StartupEvent) {
// startup logic here
}
@EventListener
internal fun onShutdownEvent(event: ShutdownEvent) {
// shutdown logic here
}
}
|
如果您的侦听器执行的工作可能需要一段时间,请使用 @Async 注释在单独的线程上运行该操作:
使用@EventListener 异步监听事件
Java |
Groovy |
Kotlin |
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 java.util.concurrent.TimeUnit.SECONDS;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.Matchers.equalTo;
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();
await().atMost(5, SECONDS).until(listener::getInvocationCounter, equalTo(1));
}
}
}
|
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:
def context = ApplicationContext.run()
def emitter = context.getBean(SampleEventEmitterBean)
def listener = context.getBean(SampleEventListener)
expect:
listener.invocationCounter.get() == 0
when:
emitter.publishSampleEvent()
then:
new PollingConditions(timeout: 5).eventually {
listener.invocationCounter.get() == 1
}
cleanup:
context.close()
}
}
|
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.kotest.assertions.timing.eventually
import io.kotest.matchers.shouldBe
import io.kotest.core.spec.style.AnnotationSpec
import io.micronaut.context.ApplicationContext
import io.micronaut.docs.context.events.SampleEventEmitterBean
import org.opentest4j.AssertionFailedError
import kotlin.time.DurationUnit
import kotlin.time.ExperimentalTime
import kotlin.time.toDuration
@ExperimentalTime
class SampleEventListenerSpec : AnnotationSpec() {
@Test
suspend 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.toDuration(DurationUnit.SECONDS), AssertionFailedError::class) {
println("Current value of counter: " + listener.invocationCounter.get())
listener.invocationCounter.get().shouldBe(1)
}
context.close()
}
}
|
默认情况下,事件侦听器在计划的执行程序上运行。您可以根据需要在配置文件(例如 application.yml)中配置此线程池:
配置定时任务线程池
Properties |
Yaml |
Toml |
Groovy |
Hocon |
JSON |
micronaut.executors.scheduled.type=scheduled
micronaut.executors.scheduled.core-pool-size=30
|
micronaut:
executors:
scheduled:
type: scheduled
core-pool-size: 30
|
[micronaut]
[micronaut.executors]
[micronaut.executors.scheduled]
type="scheduled"
core-pool-size=30
|
micronaut {
executors {
scheduled {
type = "scheduled"
corePoolSize = 30
}
}
}
|
{
micronaut {
executors {
scheduled {
type = "scheduled"
core-pool-size = 30
}
}
}
}
|
{
"micronaut": {
"executors": {
"scheduled": {
"type": "scheduled",
"core-pool-size": 30
}
}
}
}
|
更多建议: