欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

扩展:Spring中的观察者模式(事件监听机制)

时间:2023-08-02
Spring观察者模式

1、ApplicationContext事件机制是观察者设计模式的具体实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext事件处理。
2、如果容器中由一个ApplicationListener Bean,当ApplicationContext发布ApplicationEvent时,ApplicationListener Bean会自动触发,这种事件机制需要程序显示的触发,
3、其中Spring有一些内置的事件,当完成某种操作会发出某些事件动作,例如监听ContextRefreshedEvent事件,当所有Bean促使和完成并被成功装载会触发该事件,实现ApplicationListener<‘ContextRefreshedEvent’>接口可以收到监听动作,接着实现自己的业务逻辑,事件Event也可以自己自定义、监听Listener也可以自定义,根据业务逻辑按需处理。


文章目录

Spring观察者模式一、对象说明二、事件模式实体概念三、本文场景:容器启动的时候装填缓存数据(加载数据字典)

1.创建监听器CountryDirectoryEventListener2.运行截图 思考问题:事件的发布与监听是一个同步的过程是同步的?

1.创建自定义事件类:MessageEvent2.创建自定义事件监听类:MessageEventListener3.运行效果4.异步执行效果 高级写法@EventListener注解总结


一、对象说明

1、ApplicationContext容器对象
2、ApplicationEvent事件对象
3、ContextRefreshedEvent容器刷新事件
4、ApplicationListener事件监听对象

二、事件模式实体概念

1.事件源:事件的触发的地方,比如我在容器加载的时候需要触发加载数据字典实现缓存预热。
2.事件:描述发生了什么事情的对象,比如上面的:加载数据字典数据
3.事件监听器:监听到事件发生的时候,做一些处理,比如更新缓存实现缓存预热


三、本文场景:容器启动的时候装填缓存数据(加载数据字典)

某个零售电商系统,mysql数据库中有储存系统内设置好的所有省市区信息,现在要将这部分地址数据查询出来放到redis做缓存(缓存预热),方便用户购买的时候自动级联填写快递省市区地址,为了避免直接写到监听的时候对象还未加载完毕,导致缓存预热失败,打算从ContextRefreshedEvent等容器加载完毕的时候进行缓存预热,可以进行以下处理:

1.创建监听器CountryDirectoryEventListener

CountryDirectoryEventListener必须实现ApplicationListener类并指定监听事件ContextRefreshedEvent,如果不指明监听类型则会监听所有事件,因为所有事件继承ApplicationContextEvent类

代码如下(示例):

@Componentpublic class CountryDirectoryEventListener implements ApplicationListener { @Override public void onApplicationEvent(ContextRefreshedEvent event) { ApplicationContext applicationContext = event.getApplicationContext(); System.out.println("---查询数据库省市区数据---"); System.out.println("---填充到redis缓存---"); System.out.println("---数据预热结束---"); }}

2.运行截图

这里只是打印输出,具体实现思路大致如此

MyApplicationEventListener类没有指定具体的监听器,则所有事件都会监听到

思考问题:事件的发布与监听是一个同步的过程是同步的?

是的,事件的发布与监听是一个同步的过程,一般缓存预热这里可以使用异步的方法实现,通过在监听方法前使用@Async,并且工程要支持异步,springboot工程启动类需要加@EnableAsync注解。下面看看实际效果

1.创建自定义事件类:MessageEvent

必须继承ApplicationEvent,可以支持多参数传递

@Componentpublic class MessageEventListener implements ApplicationListener { @Override public void onApplicationEvent(MessageEvent event) { for (int i = 0 ; i < 10 ; i++){ System.out.println("---等待一秒钟---" + System.currentTimeMillis()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("监听到消息事件"); }}

2.创建自定义事件监听类:MessageEventListener

@Componentpublic class MessageEventListener implements ApplicationListener { @Override public void onApplicationEvent(MessageEvent event) { System.out.println("监听到消息事件"); }}

这里偷懒不写接口调用方法,直接在刚刚缓存预热的监听方法之前去发布事件MessageEvent看看会不会是同步的。

@Componentpublic class CountryDirectoryEventListener implements ApplicationListener { @Override public void onApplicationEvent(ContextRefreshedEvent event) { ApplicationContext applicationContext = event.getApplicationContext(); applicationContext.publishEvent(new MessageEvent("我来发消息了")); System.out.println("---查询数据库省市区数据---"); System.out.println("---填充到redis缓存---"); System.out.println("---数据预热结束---"); }}

3.运行效果

事件的发布与监听是一个同步的过程

4.异步执行效果

使用@Async注解

@Componentpublic class MessageEventListener implements ApplicationListener { @Async @Override public void onApplicationEvent(MessageEvent event) { for (int i = 0 ; i < 10 ; i++){ System.out.println("---等待一秒钟---" + System.currentTimeMillis()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("监听到消息事件"); }}//启动类@SpringBootApplication@EnableAsyncpublic class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}}

高级写法@EventListener注解

@Componentpublic class CommentSyncEventListener { @Async @EventListener public void sync(CommentSyncEvent event) { logger.error("评论同步失败", e); } }


总结

Spring的事件机制简便地将我们的代码解耦从而优化我们的代码,方便我们扩展。

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。