典型的事件驱动型应用有哪些 (典型事件举例)
本文目录导航:
- 典型的事件驱动型应用有哪些
- SpringBoot核心原理:自动配置、事件驱动、Condition
- JavaScript中,1)何为事件驱动模式(文字陈述和代码) 2)JS中事件类型分类(用代码举例说明)
典型的事件驱动型应用有哪些
事件驱动型应用是一种软件架构模式,其中应用程序的执行由外部事件触发和驱动。
以下是一些典型的事件驱动型应用的示例:1. 消息队列系统:消息队列系统通过将消息发送到队列中,实现不同组件之间的异步通信。
当有新的消息到达时,系统会触发相应的事件并处理消息。
2. 实时数据处理系统:实时数据处理系统用于处理大量的实时数据流。
数据的到达会触发事件,系统会对数据进行处理和分析,例如实时监控系统、实时推荐系统等。
3. GUI 应用程序:图形用户界面(GUI)应用程序通常使用事件驱动的方式处理用户的输入和操作。
例如,点击按钮、输入文本等操作会触发相应的事件,应用程序会根据事件进行响应。
4. Web 应用程序:Web 应用程序通常使用事件驱动的方式处理用户的请求和响应。
例如,当用户发起一个 HTTP 请求时,Web 服务器会触发相应的事件并返回相应的内容。
5. 多线程应用程序:多线程应用程序中的线程可以通过事件进行通信和同步。
当一个线程完成某个任务时,可以触发事件通知其他线程进行相应的操作。
6. IoT 应用程序:物联网(IoT)应用程序通常涉及多个设备和传感器之间的通信。
当设备状态发生变化或传感器检测到某个事件时,会触发相应的事件进行处理。
这些只是一些典型的事件驱动型应用的示例,实际上,事件驱动型应用可以适用于各种不同的领域和场景。

SpringBoot核心原理:自动配置、事件驱动、Condition
SpringBoot是Spring的包装,通过自动配置使得SpringBoot可以做到开箱即用,上手成本非常低,但是学习其实现原理的成本大大增加,需要先了解熟悉Spring原理。
如果还不清楚Spring原理的,可以先查看博主之前的文章,本篇主要分析SpringBoot的启动、自动配置、Condition、事件驱动原理。
SpringBoot启动非常简单,因其内置了Tomcat,所以只需要通过下面几种方式启动即可: 可以看到第一种是最简单的,也是最常用的方式,需要注意类上面需要标注@SpringBootApplication 注解,这是自动配置的核心实现,稍后分析,先来看看SpringBoot启动做了些什么? 在往下之前,不妨先猜测一下,run方法中需要做什么?对比Spring源码,我们知道,Spring的启动都会创建一个ApplicationContext 的应用上下文对象,并调用其refresh方法启动容器,SpringBoot只是Spring的一层壳,肯定也避免不了这样的操作。
另一方面,以前通过Spring搭建的项目,都需要打成War包发布到Tomcat才行,而现在SpringBoot已经内置了Tomcat,只需要打成Jar包启动即可,所以在run方法中肯定也会创建对应的Tomcat对象并启动。
以上只是我们的猜想,下面就来验证,进入run方法: SpringBoot的启动流程就是这个方法,先看getRunListeners 方法,这个方法就是去拿到所有的 SpringApplicationRunListener 实现类,这些类是用于SpringBoot事件发布的,关于事件驱动稍后分析,这里主要看这个方法的实现原理: 一步步追踪下去可以看到最终就是通过SPI机制根据接口类型从META-INF/ 文件中加载对应的实现类并实例化,SpringBoot的自动配置也是这样实现的。
为什么要这样做呢?通过注解扫描不可以么?当然不行,这些类都在第三方jar包中,注解扫描实现是很麻烦的,当然你也可以通过@Import 注解导入,但是这种方式不适合扩展类特别多的情况,所以这里采用SPI的优点就显而易见了。
回到run方法中,可以看到调用了createApplicationContext 方法,见名知意,这个就是去创建应用上下文对象: 注意这里通过反射实例化了一个新的没见过的上下文对象AnnotationConfigServletWebServerApplicationContext ,这个是SpringBoot扩展的,看看其构造方法: 如果你有看过Spring注解驱动的实现原理,这两个对象肯定不会陌生,一个实支持注解解析的,另外一个是扫描包用的。
上下文创建好了,下一步自然就是调用refresh方法启动容器: 这里首先会调用到其父类中ServletWebServerApplicationContext : 可以看到是直接委托给了父类: 这个方法不会陌生吧,之前已经分析过了,这里不再赘述,至此SpringBoot的容器就启动了,但是Tomcat启动是在哪里呢?run方法中也没有看到。
实际上Tomcat的启动也是在refresh流程中,这个方法其中一步是调用了onRefresh方法,在Spring中这是一个没有实现的模板方法,而SpringBoot就通过这个方法完成了Tomcat的启动: 这里首先拿到TomcatServletWebServerFactory 对象,通过该对象再去创建和启动Tomcat: 上面的每一步都可以对比Tomcat的配置文件,需要注意默认只支持了http协议: 如果想要扩展的话则可以对additionalTomcatConnectors 属性设置值,需要注意这个属性没有对应的setter方法,只有 addAdditionalTomcatConnectors 方法,也就是说我们只能通过实现 BeanFactoryPostProcessor 接口的 postProcessBeanFactory 方法,而不能通过 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法,因为前者可以通过传入的BeanFactory对象提前获取到 TomcatServletWebServerFactory 对象调用 addAdditionalTomcatConnectors 即可;而后者只能拿到BeanDefinition对象,该对象只能通过setter方法设置值。
这段代码会在控制台打印所有的事件名称,按照顺序如下: 以上是正常启动关闭,如果发生异常还有发布ApplicationFailedEvent 事件。
事件的发布遍布在整个容器的启动关闭周期中,事件发布对象刚刚我们也看到了是通过SPI加载的 SpringApplicationRunListener 实现类 EventPublishingRunListener ,同样事件监听器也是在 文件中配置的,默认实现了以下监听器: 可以看到有用于文件编码的(FileEncodingApplicationListener ),有加载日志框架的( LoggingApplicationListener ),还有加载配置的( ConfigFileApplicationListener )等等一系列监听器,SpringBoot也就是通过这系列监听器将必要的配置和组件加载到容器中来,这里不再详细分析,感兴趣的读者可以通过其实现的 onApplicationEvent 方法看到每个监听器究竟是监听的哪一个事件,当然事件发布和监听我们自己也是可以扩展的。
SpringBoot最核心的还是自动配置,为什么它能做到开箱即用,不再需要我们手动使用@EnableXXX 等注解来开启?这一切的答案就在 @SpringBootApplication 注解中: 这里重要的注解有三个:@SpringBootConfiguration 、 @EnableAutoConfiguration 、 @ComponentScan 。
@ComponentScan 就不用再说了, @SpringBootConfiguration 等同于 @Configuration ,而 @EnableAutoConfiguration 就是开启自动配置: @AutoConfigurationPackage 注解的作用就是将该注解所标记类所在的包作为自动配置的包,简单看看就行,主要看 AutoConfigurationImportSelector ,这个就是实现自动配置的核心类,注意这个类是实现的 DeferredImportSelector 接口。
在这个类中有一个selectImports 方法。
这个方法在我之前的文章这一次搞懂Spring事务注解的解析也有分析过,只是实现类不同,它同样会被 ConfigurationClassPostProcessor 类调用,先来看这个方法做了些什么: 追踪源码最终可以看到也是从META-INF/ 文件中拿到所有 EnableAutoConfiguration 对应的值(在 spring-boot-autoconfigure 中)并通过反射实例化,过滤后包装成 AutoConfigurationEntry 对象返回。
看到这里你应该会觉得自动配置的实现就是通过这个selectImports 方法,但实际上这个方法通常并不会被调用到,而是会调用该类的内部类 AutoConfigurationGroup 的process和selectImports方法,前者同样是通过 getAutoConfigurationEntry 拿到所有的自动配置类,而后者这是过滤排序并包装后返回。
下面就来分析ConfigurationClassPostProcessor 是怎么调用到这里的,直接进入 processConfigBeanDefinitions 方法: 前面一大段主要是拿到合格的Configuration 配置类,主要逻辑是在 方法中,该方法完成了对 @Component 、 @Bean 、 @Import 、 @ComponentScans 等注解的解析,这里主要看对 @Import 的解析,其它的读者可自行分析。
一步步追踪,最终会进入到 processConfigurationClass 方法: 这里需要注意 方法的调用,这个方法就是进行Bean加载过滤的,即根据 @Condition 注解的匹配值判断是否加载该Bean,具体实现稍后分析,继续跟踪主流程 doProcessConfigurationClass : 这里就是完成对一系列注解的支撑,我省略掉了,主要看processImports 方法,这个方法就是处理 @Import 注解的: 刚刚我提醒过AutoConfigurationImportSelector 是实现 DeferredImportSelector 接口的,如果不是该接口的实现类则是直接调用 selectImports 方法,反之则是调用 方法: 首先创建了一个DeferredImportSelectorHolder 对象,如果是第一次执行则是添加到 deferredImportSelectors 属性中,等到 的最后调用process方法: 反之则是直接执行,首先通过register拿到AutoConfigurationGroup 对象: 然后在processGroupImports 方法中进行真正的处理: 在getImports 方法中就完成了对process和 selectImports 方法的调用,拿到自动配置类后再递归调用调用 processImports 方法完成对自动配置类的加载。
至此,自动配置的加载过程就分析完了,下面是时序图: 在自动配置类中有很多Condition相关的注解,以AOP为例: 这里就能看到@ConditionalOnProperty 、 @ConditionalOnClass 、 @ConditionalOnMissingClass ,另外还有 @ConditionalOnBean 、 @ConditionalOnMissingBean 等等很多条件匹配注解。
这些注解表示条件匹配才会加载该Bean,以@ConditionalOnProperty 为例,表明配置文件中符合条件才会加载对应的Bean,prefix表示在配置文件中的前缀,name表示配置的名称, havingValue 表示配置为该值时才匹配, matchIfMissing 则是表示没有该配置是否默认加载对应的Bean。
其它注解可类比理解记忆,下面主要来分析该注解的实现原理。
这里注解点进去看会发现每个注解上都标注了@Conditional 注解,并且value值都对应一个类,比如 OnBeanCondition ,而这些类都实现了 Condition 接口,看看其继承体系: 上面只展示了几个实现类,但实际上Condition的实现类是非常多的,我们还可以自己实现该接口来扩展@Condition 注解。
Condition接口中有一个matches方法,这个方法返回true则表示匹配。
该方法在 ConfigurationClassParser 中多处都有调用,也就是刚刚我提醒过的shouldSkip方法,具体实现是在 ConditionEvaluator 类中: 再来看看matches的实现,但OnBeanCondition 类中没有实现该方法,而是在其父类 SpringBootCondition 中: getMatchOutcome 方法也是一个模板方法,具体的匹配逻辑就在这个方法中实现,该方法返回的 ConditionOutcome 对象就包含了是否匹配和日志消息两个字段。
进入到 OnBeanCondition 类中: 可以看到该类支持了@ConditionalOnBean 、 @ConditionalOnSingleCandidate 、 @ConditionalOnMissingBean 注解,主要的匹配逻辑在 getMatchingBeans 方法中: 这里逻辑看起来比较复杂,但实际上就做了两件事,首先通过getNamesOfBeansIgnoredByType 方法调用 拿到容器中对应的Bean实例,然后根据返回的结果判断哪些Bean存在,哪些Bean不存在(Condition注解中是可以配置多个值的)并返回MatchResult对象,而MatchResult中只要有一个Bean没有匹配上就返回false,也就决定了当前Bean是否需要实例化。
本篇分析了SpringBoot核心原理的实现,通过本篇相信读者也将能更加熟练地使用和扩展SpringBoot。
另外还有一些常用的组件我没有展开分析,如事务、MVC、监听器的自动配置,这些我们有了Spring源码基础的话下来看一下就明白了,这里就不赘述了。
最后读者可以思考一下我们应该如何自定义starter启动器,相信看完本篇应该难不倒你。
JavaScript中,1)何为事件驱动模式(文字陈述和代码) 2)JS中事件类型分类(用代码举例说明)
12.2事件驱动与事件处理事件驱动是JavaScript响应用户操作的一种处理方式,而事件处理是JavaScript响应用户操作所调用的程序代码。
12.2.1事件驱动在多年以前,计算机程序通常是以批处理的模式运行。
所谓批处理,就是开发者事先写好一些代码,再将这些代码一次运行。
这种处理方式有点类似于通过HTML代码直接编写的网页。
浏览器只是将HTML代码逐行解析,并显示在浏览器窗口。
后来,在批处理模式中,开发者可以加入一些特定的代码,在程序批处理期间,可以停下来等待用户输入一些信息,并根据用户输入的信息来判断和执行某个程序分支,这就使程序有了初步的交互性。
随着鼠标、触摸屏等设备的出现,批处理时代就逐渐远去,取而代之的是事件驱动的时代。
当然,批处理也还能使用,只是使用的范围和频率比事件驱动要少得多。
以鼠标为例,在事件驱动中,用户可以使用鼠标单击等方式进行操作,程序则根据鼠标指针的位置以及单击的方式进行响应。
JavaScript使用的就是这种事件驱动的程序设计方式。
在JavaScript中,事件(Even)包括以下两个方面:● 用户在浏览器中产生的操作是事件,如单击鼠标、按下键盘上的键等。
● 文档本身产生的事件,如文档加载完毕、卸载文档等,都是事件。
12.2.2事件处理在JavaScript中,浏览器会使用事件来通知JavaScript程序响应用户的操作。
事件的类型有很多种,如鼠标事件、键盘事件、加载与卸载事件、得到焦点与失去焦点事件等。
在事件产生的时候,浏览器会调用一个JavaScript程序来响应这个事件,这就是JavaScript的事件处理方式。
要想让浏览器可以调用合适的JavaScript程序,就必须要做到以下 3点:(1)设置HTML文档中响应事件的元素。
在一个HTML文档中,并非所有元素都会去响应事件。
就鼠标单击事件而言,一般在HTML文档的正文不会响应该事件,但在按钮中一般都会响应该事件。
(2)设置元素响应事件的类型。
在确定了哪些元素响应事件之后,要设置该元素响应事件的类型。
例如,一个按钮通常会响应鼠标单击事件(click事件),而一个下拉列表框通常会响应选项变化事件(change事件)。
在同一个元素中,也可以响应多个事件。
例如,一个超链接,在鼠标移动到该超链接上时,可以响应鼠标移动到对象上事件(mouseover事件),当鼠标从超链接上移开时,又可以响应鼠标移开事件(mouseout事件)。
(3)设置响应事件的程序。
为了让浏览器可以响应事件,必须要设置响应事件的程序。
例如一个按钮被单击时,浏览器会响应这个click事件,此时浏览器就会在JavaScript中寻找一个合适的程序,并运行该程序。
这个程序可以是用户自定义的函数,也可以是一段JavaScript代码,还可以是JavaScript内置对象的方法等。
看看这个更详细