自学内容网 自学内容网

spring ApplicationContext的事件监听机制

测试代码

继承ApplicationEvent定义自己的事件

public class MyEvent extends ApplicationEvent {
    String message;

    public MyEvent(Object source, String message) {
        super(source);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

}

实现ApplicationListener接口定义listener

eg:

@Component
public class MyEventListener implements ApplicationListener<MyEvent> {
    @Override
    public void onApplicationEvent(MyEvent event) {
        System.out.println("MyEventListener received: " + event.getMessage());
    }
}

事件发布

@Service
public class MyEventPublisher {

    @Autowired
    private ApplicationContext context;

    public void publish(String message) {
        MyEvent myEvent = new MyEvent(this, message);
        context.publishEvent(myEvent);
    }
}

测试controller中测试发布事件

@RestController
public class TestControl {

    @Autowired
    private MyEventPublisher myEventPublisher;


    @GetMapping(value = "/test")
    public String getTest(@Param("msg") String msg) {
        myEventPublisher.publish(msg);
        return "hello test";
    }

测试输出:

在这里插入图片描述

原理

事件如何发布

本例用springboot开启一个web项目,内置了ApplicationContext bean 直接获取到,然后就可以发布事件了
在这里插入图片描述

org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext

走到
org.springframework.context.support.AbstractApplicationContext#publishEvent(org.springframework.context.ApplicationEvent),广播事件

在这里插入图片描述

获取到对应事件类型监听器,然后丢到线程池去执行

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}

调用listener的onApplicationEvent方法

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}

listener如何添加的

bean生命周期初始化阶段会执行所有BeanPostProcessor的postProcessAfterInitialization方法
在这里插入图片描述

通过内置的org.springframework.context.support.ApplicationListenerDetectorBeanPostProcessor添加到applicationContext的listener缓存中

补充:发布-订阅/观察者模式

观察者模式

  • 被观察者直接发消息给观察者,当消息事件触发时,被观察者直接通知所有列表中的观察者。
  • 被观察者耦合了一个观察者列表。
  • 异步支持不够,当触发消息事件时,被观察者直接通知观察者。
  • 安全性存在一定问题,观察者通常会对被观察者监听,可能得到被观察者内部的状态。

发布订阅模式

  • 不再直接通信,发布者和订阅者中间存在一个第三方中介,发布者和订阅者都与这个第三方通信。
  • 发布者不再维护观察者列表,甚至发布者和订阅者彼此并不知道对方的存在关系。
  • 异步可支持,当触发消息事件时,第三方中介可以进行延迟发送。
  • 安全性较好,发布者和订阅者解耦,需要通过第三方中介通信,获取发布者内部状态也必须通过特意暴露的方法才能访问。

发布订阅模式更适合一些大型的、复杂的、有异步要求、安全性要求高的场景,如:消息队列(RabbitMQ)、流处理(Kafka)。观察者模式相对实现更简单,适合一些轻量级、无特别要求的场景,如一些GUI工具。


原文地址:https://blog.csdn.net/qq_26437925/article/details/145281285

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!