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

观察者模式:

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


观察者模式(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. NVIDIA GPU上的随机数生成

    NVIDIA GPU上的随机数生成 NVIDIA CUDA随机数生成库(cuRAND)提供高性能的GPU加速的随机数生成(RNG).cuRAND库使用NVIDIA GPU中提供的数百个处理器内核,将质 ...

  2. CPU消耗,跟踪定位理论与实践

    CPU消耗,跟踪定位理论与实践 一.性能指标之资源指标定位方案 1.打tprof报告方法 抓取perfpmr文件 60秒. perfpmr.sh 60 从结果文件中取出tprof.sum 或直接抓取t ...

  3. AI框架类FAQ

    AI框架类FAQ 数据处理 问题:如何在训练过程中高效读取数量很大的数据集? 答复:当训练时使用的数据集数据量较大或者预处理逻辑复杂时,如果串行地进行数据读取,数据读取往往会成为训练效率的瓶颈.这种情 ...

  4. ARM Cortex-M嵌入式C基础编程(上)

    ARM Cortex-M嵌入式C基础编程(上) ARM Cortex-M Embedded C Fundamentals/Tutorial -Aviral Mittal 此技术是关于从编写简单的嵌入式 ...

  5. TVM源码框架安装方法

    TVM源码框架安装方法 本文提供如何在各种系统上从零构建和安装TVM包的说明.它包括两个步骤: 首先从C++代码中构建共享库(linux的libtvm.so,macOS的libtvm.dylib和wi ...

  6. 【NX二次开发】Block UI 切换开关

    属性说明 常规         类型 描述     BlockID     String 控件ID     Enable     Logical 是否可操作     Group     Logical ...

  7. 【NX二次开发】Block UI 整形

    属性说明 常规         类型 描述     BlockID     String 控件ID     Enable     Logical 是否可操作     Group     Logical ...

  8. 你有一份经典SQL语句大全,请注意查收

    一.基础部分 1.创建数据库 CREATE DATABASE dbname 2.删除数据库 DROP DATABASE dbname 3.创建新表 CREATE TABLE tabname(col1 ...

  9. RobotFramework + Python 自动化入门 四 (Web进阶)

    在<RobotFramwork + Python 自动化入门 一>中,完成了一个Robot环境搭建及测试脚本的创建和执行. 在<RobotFramwork + Python 自动化入 ...

  10. Go语言十六进制转十进制

    Go语言十六进制转十进制 代码Demo import ( "fmt" "strconv" "testing" ) func Test_1(t ...