codecamp

Micronaut Context Events

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
      }
    }
  }
}


Micronaut 生命周期方法
Micronaut Bean Events
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

Micronaut 独立命令行应用程序

Micronaut 安全

Micronaut 多租户

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }