当前位置: 首页 > article >正文

spring ApplicationContext的事件监听机制

目录

    • 测试代码
      • 继承ApplicationEvent定义自己的事件
      • 实现ApplicationListener接口定义listener
      • 事件发布
      • 测试输出:
    • 原理
      • 事件如何发布
      • listener如何添加的
      • 补充:发布-订阅/观察者模式

测试代码

继承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工具。


http://www.kler.cn/a/514718.html

相关文章:

  • 3.CSS的背景
  • mac 电脑上安装adb命令
  • C#,入门教程(06)——解决方案资源管理器,代码文件与文件夹的管理工具
  • [Computer Vision]实验三:图像拼接
  • 将UI界面交给第三方库
  • Java复习第四天
  • 「全网最细 + 实战源码案例」设计模式——简单工厂模式
  • 循环队列(C语言版)
  • AGI发展的现实约束与定义困境
  • 学习记录-统计记录场景下的Redis写请求合并优化实践
  • [矩阵扩散]
  • VUE elTree 无子级 隐藏展开图标
  • Java高频面试之SE-16
  • C++----STL(vector)
  • curl简介与libcurl开源库的使用总结
  • 在电商行业中,3D模型的应用有哪些?
  • ECCV 2024,全新激活函数!
  • 【面试题】MQ部分[2025/1/13 ~ 2025/1/19]
  • 【Uniapp-Vue3】StorageSync数据缓存API
  • OGG 19C 集成模式启用DDL复制
  • ORA-15041 ORA-15023
  • Kotlin 2.1.0 入门教程(八)
  • js截取video视频某一帧为图片
  • Kafka 入门与应用实战:吞吐量优化与与 RabbitMQ、RocketMQ 的对比
  • SVM模型实战1
  • RabbitMQ 在实际应用时要注意的问题