前言:在讲述内容之前 希望大家对设计模式有所了解 即使你学会了本片的内容 也不知道什么时候去使用 或者为什么要这样去用

观察者模式:

观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。在观察者模式中,主体是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅并接收通知。观察者模式不仅被广泛应用于软件界面元素之间的交互,在业务对象之间的交互、权限管理等方面也有广泛的应用


观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。


观察者设计模式定义了对象间的一种一对多的组合关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。(以上源于百度)

已经熟悉设计模式的可以直接向下阅读 对不熟悉的 希望通过上述内容 你们可以有一定的了解 通俗点说 观察者模式 是设计框架的一种
当然我们的Spring Boot当然也不会放过这么好的设计模式 那么Spring Boot中又有哪些地方使用到了

1.ApplicationStartingEvent

当应用启动还没有进行任何处理时,在对所有的监听器做初始化的时候发送的事件
public ConfigurableApplicationContext run(String... args) {
//记录服务启动事件
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
//开启awt的headless模式
//Headless模式是系统的一种配置模式。在系统可能缺少显示设备、键盘或鼠标这些外设的情况下可以使用该模式
this.configureHeadlessProperty();
//获取监听器列表
SpringApplicationRunListeners listeners = this.getRunListeners(args);
启动所有监听器
listeners.starting();
.................
}

此时监听列表中只有一个监听事件为EventPublishingRunListener

它的作用就是通知Spring Boot项目开始启动

2.ApplicationEnvironmentPreparedEvent

当已获取的了所有Spring Context上下文信息 但是此时还没有进行创建

此时Spring Boot开始启动 EventPublishingRunListener会发送ApplicationEnvironmentPreparedEvent事件 告诉Spring Boot应用环境已经准备就绪 准备做后续处理 监听此事件的监听器是ConfigFileApplicationListener

private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
//获取环境 资源 加载器
List<EnvironmentPostProcessor> postProcessors = this.loadPostProcessors();
postProcessors.add(this);
//对Order的大小进行排序 装载
AnnotationAwareOrderComparator.sort(postProcessors);
//使用迭代器 根据顺序开始执行 环境 资源 的配置
Iterator var3 = postProcessors.iterator(); while(var3.hasNext()) {
EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();
postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
} }

3.ApplicationContextInitializedEvent

测试Spring Context上下文已经初始化完毕 但是此时上下文是的空的

开始向Spring上下文装填内容

public void contextPrepared(ConfigurableApplicationContext context) {
//获取当前所有有关的上下文的监听器
Iterator var2 = this.listeners.iterator(); while(var2.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
//通知
listener.contextPrepared(context);
} }
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//向上下文中装填配置参数
//context.setEnvironment(environment);
//向应用中装填上下文
this.postProcessApplicationContext(context);
//进行初始化参数装填
this.applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
} ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
} if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
} Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
this.load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}

4.ApplicationPreparedEvent

应用加载完毕
public void contextLoaded(ConfigurableApplicationContext context) {
ApplicationListener listener;
//相容器中装填已经初始化的上下文对象
for(Iterator var2 = this.application.getListeners().iterator(); var2.hasNext(); context.addApplicationListener(listener)) {
listener = (ApplicationListener)var2.next();
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware)listener).setApplicationContext(context);
}
}
//通知
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}

5.ApplicationStartedEvent

应用初始化完成
public void started(ConfigurableApplicationContext context) {
//通知
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}

6.ApplicationReadyEvent

应用加载完毕
public void running(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
}

这就是Spring在启动的时候 发生的事件交互 最直观的我们可以看出 当一个具体的功能实现完毕之后 创建事件 去通知下一个阶段去做相对的事情 这样子比在一个方法里面 去直接调用好得多 并且可以支持广播模式(一对多)

当然在Spring Boot中使用观察者模式 也非常简单 首先我们创建一个名为旅游的事件

@Data
public class TravelEvent { private String money; private String location; private String sex; }

当我们需要去旅行时 需要带钱 带男/女朋友 去什么地方游玩

注册一个监听类用来监听我们发出的事件

1.监听类的实例必须由Spring容器管理 切必须有实例 否则无法监听到事件的发生
2.在方法上使用@EventListener(事件类)注解 可以将事件实例当做入参 进行业务处理
3.使用ApplicationEventPublisher发送事件 进行测试
@Component
public class TravelEventListener { @EventListener(TravelEvent.class)
public void location(TravelEvent travelEvent){
System.out.println("地方:"+travelEvent.getLocation());
} @EventListener(TravelEvent.class)
public void sex(TravelEvent travelEvent){
System.out.println("朋友:"+travelEvent.getSex());
} @EventListener(TravelEvent.class)
public void money(TravelEvent travelEvent){
System.out.println("钱:"+travelEvent.getMoney());
}
}
@RestController
@RequestMapping("/event")
public class EventController { @Autowired
ApplicationEventPublisher applicationEventPublisher; @PostMapping("/travel")
public String goTravel(@RequestBody TravelEvent travelEvent){
applicationEventPublisher.publishEvent(travelEvent);
return "ok";
} }

最后 Spring Boot中启动时 所发生的事件 已经在Spring Boot中如何使用事件已经讲完了 可以看出在Spring Boot中使用观察者模式 还是非常方便的 作为一名程序员 尤其是后台人员务必利用好设计模式 如果一个项目 没有使用任何设计模式 那么还不如去写面向过程 一旦有需求的变更 我们就可能成为 外行眼里吐槽的 加班狗 地中海等等......

Spring Boot(三):Spring Boot中的事件的使用 与Spring Boot启动流程(Event 事件 和 Listeners监听器)的更多相关文章

  1. SpringBoot启动流程分析(三):SpringApplication的run方法之prepareContext()方法

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  2. Slickflow.NET 开源工作流引擎高级开发(一) -- 流程外部事件的调用和变量存储实现

    前言:流程实现基本流转功能外,通常也需要调用外部事件,用于和业务系统的交互,同时存储一些流程变量,用于追踪和记录业务数据变化对流程流转的影响. 1. 流程事件 流程执行过程中,伴随各种事件的发生,而且 ...

  3. Spring boot(三)在Spring boot中Redis的使用

    spring boot对常用的数据库支持外,对nosql 数据库也进行了封装自动化. redis介绍 Redis是目前业界使用最广泛的内存数据存储.相比memcached,Redis支持更丰富的数据结 ...

  4. 精选Spring Boot三十五道必知必会知识点

    Spring Boot 是微服务中最好的 Java 框架. 我们建议你能够成为一名 Spring Boot 的专家.本文精选了三十五个常见的Spring Boot知识点,祝你一臂之力! 问题一 Spr ...

  5. Java精选面试题之Spring Boot 三十三问

    Spring Boot Spring Boot 是微服务中最好的 Java 框架. 我们建议你能够成为一名 Spring Boot 的专家. 问题一: Spring Boot.Spring MVC 和 ...

  6. 漫谈Spring Security 在Spring Boot 2.x endpoints中的应用(一)

    Spring Boot 2.x极大简化了默认的安全配置,并不是说有很多安全相关的配置,现在你只需要提供一个WebSecurityConfigurerAdapter继承类这样一个简单的操作,Spring ...

  7. Spring Boot 监听 Activemq 中的特定 topic ,并将数据通过 RabbitMq 发布出去

    1.Spring Boot 和 ActiveMQ .RabbitMQ 简介 最近因为公司的项目需要用到 Spring Boot , 所以自学了一下, 发现它与 Spring 相比,最大的优点就是减少了 ...

  8. spring boot 项目从配置文件中读取maven 的pom.xml 文件标签的内容。

    需求: 将pom.xml 文件中的版本号读取到配置文件并打印到日志中. 第一步: 在pom.xml 中添加以下标签. 第二步: 将version 标签的值读取到配置文件中 这里使用 @@  而不是  ...

  9. Spring boot(三)整合mybaties+thymeleaf实现基础crud

    工程结构: 首先在pom文件中引入依赖 <?xml version="1.0" encoding="UTF-8"?> <project xml ...

随机推荐

  1. mongodb创建用户创建库分配权限

    use unionserver db.createUser({ user: "rshy",pwd: "root1234@......",customData:{ ...

  2. Jmeter- 笔记7 - 服务器监控(ServerAgent配置)

    文件:ServerAgent - 2.2.3.zip  放网盘了 在服务器的操作:只需要把这个文件上传到被监控服务器,然后解压,启动sh startagent.sh --udp-port 0 --tc ...

  3. Jittor实现Conditional GAN

    Jittor实现Conditional GAN Generative Adversarial Nets(GAN)提出了一种新的方法来训练生成模型.然而,GAN对于要生成的图片缺少控制.Conditio ...

  4. eclipse 新建项目不可选择Java Project 解决方法

    解决方法一: 鼠标点击file-new-other,弹出选项框,选中java project,点击next,接下来就是正常创建java protect的流程了,这个虽然也可以解决,但每次新建java项 ...

  5. MySQL笔记03(黑马)

    今日内容 DQL:查询语句 排序查询 聚合函数 分组查询 分页查询 约束 多表之间的关系 范式 数据库的备份和还原 DQL:查询语句 排序查询 语法:order by 子句 order by 排序字段 ...

  6. 【C++】类

    一个简单例子: 1 //c++ 类 2 #include<iostream> 3 using namespace std; 4 class Point 5 { 6 private: 7 i ...

  7. SpringCloud 面试题 (持续更新、吐血推荐)

    文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...

  8. 浏览Github必备的5款神器级别的Chrome插件

    我们知道 Github 是程序员特有的宝藏,也可以称它为 GayHub, 大家浏览 Github 的时候,一定遇到过下面这些问题: 不克隆到本地的情况下阅读代码困难. 无法单独下载仓库中的某个文件/文 ...

  9. 32.qt quick-PathView实现好看的home界面

    pathView的使用类似与ListView,都需要模型(model)和代理(delegate),只不过pathView多了一个路径(path)属性,顾名思义路径就是item滑动的路径. 一个Path ...

  10. windows 上 OpenSSH 服务 启用秘钥登录(微软真心逆天)

    windows 上 OpenSSH 服务 启用秘钥登录(微软真心逆天) windows 安装 OpenSSH 服务 最近需要在windows 服务器上部署自动发布程序,那么就需要用到 scp 和 ss ...