Spring的事件机制知识点详解及实例分析

同步事件和异步事件

  • 同步事件: 在一个线程里,按顺序执行业务,做完一件事再去做下一件事。
  • 异步事件: 在一个线程里,做一个事的同事,可以另起一个新的线程执行另一件事,这样两件事可以同时执行。

用一个例子来解释同步事件和异步事件的使用场景,有时候一段完整的代码逻辑,可能分为几部分,拿最常见的注册来说,假设完整流程是,1.点击注册->2.检验信息并存库->3.发送邮件通知->4.返回给用户.代码这么写是正确,但不是最好的,缺点如下:

逻辑复杂,业务耦合,我们把校验数据并存库和发送邮件写到一个大的业务方法里了,发送邮件我们可以看做一个相对独立的业务方法。
效率低,假设2和3分别需要1秒的时候,那么用户在点击注册2秒后才能看到响应。

同步事件可以解决上面第一个问题,我们把发邮件的方法独立出来,放到事件里执行,这样注册的这个方法就可以只做2操作,完成之后发布一个事件去执行3,可以很好的解决业务耦合的问题.

异步事件可以完美解决以上两个问题,注册方法执行2操作,执行之后发布一个异步事件,另起一个线程执行3操作,注册方法所在的线程可直接返回给用户,这样不仅实现了业务解耦还提高了效率,用户点击注册,1秒后就能看到响应.

Spring的事件机制

Spring 事件发送监听涉及3个部分

  • ApplicationEvent:表示事件本身,自定义事件需要继承该类,可以用来传递数据,比如上述操作,我们需要将用户的邮箱地址传给事件监听器.
  • ApplicationEventPublisherAware :事件发送器,通过实现这个接口,来触发事件.  
  • ApplicationListener:事件监听器接口,事件的业务逻辑封装在监听器里面.

接下来使用spring的异步事件机制来模拟上面的注册流程.有配置文件和注解两种方式。

使用配置文件的方式创建事件:

新建TestEvent:

public class TestEvent extends ApplicationEvent {

     private TestParam source;

     public TestEvent(TestParam source) {
         super(source);
         this.source = source;
     }
 }

 @Data
 public class TestParam {
     private String email;
 }

新建TestListener:

@Component
 public class TestListener implements ApplicationListener<TestEvent> {

     @Override
     public void onApplicationEvent(TestEvent testEvent) {

         TestParam param = (TestParam) testEvent.getSource();
         System.out.println(".......开始.......");
         System.out.println("发送邮件:"+param.getEmail());
         System.out.println(".......结束.....");
     }
 }

新建 EventPublisher:

@Component
public class TestPublish implements ApplicationEventPublisherAware {

    private static ApplicationEventPublisher applicationEventPublisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        TestPublish.applicationEventPublisher = applicationEventPublisher;
    }

    public static void  publishEvent(ApplicationEvent communityArticleEvent) {
        applicationEventPublisher.publishEvent(communityArticleEvent);
    }
}

spring-context.xml中添加:

  <bean id="applicationEventAsyncMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
         <property name="taskExecutor">
             <bean class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
                 <property name="corePoolSize" value="5"/>
                 <property name="keepAliveSeconds" value="3000"/>
                 <property name="maxPoolSize" value="50"/>
                 <property name="queueCapacity" value="200"/>
             </bean>
         </property>
     </bean>

注意:如果加<propery name="taskExecutor",则使用异步方式执行,否则为同步方式

使用注解方式创建事件

使用 @Async 需要在配置文件添加一下支持,线程池也是需要配置一下的

<!-- 开启@AspectJ AOP代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>

    <!-- 任务执行器 -->
    <task:executor id="executor" pool-size="10"/>

    <!--开启注解调度支持 @Async -->
    <task:annotation-driven executor="executor" proxy-target-class="true"/>

TestListener中在方法中添加@Async

 @Component
 public class TestListener implements ApplicationListener<TestEvent> {

     @Async
     @Override
     public void onApplicationEvent(TestEvent testEvent) {

         TestParam param = (TestParam) testEvent.getSource();
         System.out.println(".......开始.......");
         System.out.println("发送邮件:"+param.getEmail());
         System.out.println(".......结束.....");
     }
 }

Listener其实还可以做得更彻底一点,使用注解@EventListener可代替实现ApplicationListener,原理是通过扫描这个注解来创建监听器并自动添加到ApplicationContext中.

新建自定义EventHandler:

 @Component
 public class TestEventHandler {

     @Async
     @EventListener
     public void handleTestEvent(TestEvent testEvent) {

         TestParam param = (TestParam) testEvent.getSource();
         System.out.println(".......开始.......");
         System.out.println("发送邮件:"+param.getEmail());
         System.out.println(".......结束.....");
     }
 } 

测试及控制台的打印就不贴了,这里主要记录一下具体的实现方法.

总结:

使用spring事件机制能很好地帮助我们消除不同业务间的耦合关系,也可以提高执行效率,应该根据业务场景灵活选择。

到此这篇关于Spring的事件机制知识点详解及实例分析的文章就介绍到这了,更多相关Spring的事件机制详解内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringBoot事件机制相关知识点汇总

    要"监听"事件,我们总是可以将"监听器"作为事件源中的另一个方法写入事件,但这将使事件源与监听器的逻辑紧密耦合. 对于实际事件,我们比直接方法调用更灵活.我们可以根据需要动态注册和注销某些事件的侦听器.我们还可以为同一事件设置多个侦听器. 本教程概述了如何发布和侦听自定义事件,并解释了 Spring Boot 的内置事件. 为什么我应该使用事件而不是直接方法调用? 事件和直接方法调用都适合于不同的情况.使用方法调用,就像断言一样-无论发送和接收模块的状态如何,他们都

  • 详解JAVA Spring 中的事件机制

    说到事件机制,可能脑海中最先浮现的就是日常使用的各种 listener,listener去监听事件源,如果被监听的事件有变化就会通知listener,从而针对变化做相应的动作.这些listener是怎么实现的呢?说listener之前,我们先从设计模式开始讲起. 观察者模式 观察者模式一般包含以下几个对象: Subject:被观察的对象.它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify().目标类可以是接口,也可以是抽象类或具体类. ConcreteSubject:具体的

  • Tomcat和Spring中的事件机制深入讲解

    引言 最近在看tomcat源码,源码中出现了大量事件消息,可以说整个tomcat的启动流程都可以通过事件派发机制串起来,研究透了tomcat的各种事件消息,基本上对tomcat的启动流程也就有了一个整体的认识.在这一基础上,联想到之前在看spring源码过程中也存在不少事件相关知识,于是想对这两个框架中的事件派发机制做一个简单的总结,加深理解. 事件机制原理其实比较简单,抽象来看的话,设计模式中的观察者模式可以说是最经典的事件驱动机制的体现了,观察者和被观察者就体现了事件监听和事件派发的角色.还

  • EventBus与Spring Event区别详解(EventBus 事件机制,Spring Event事件机制)

    本地异步处理,采用事件机制 可以使 代码解耦,更易读.事件机制实现模式是 观察者模式(或发布订阅模式),主要分为三部分:发布者.监听者.事件. Guava EventBus Guava EventBus实现是观察者模式,用法很简单,先上代码. /** * Desc: 事件对象 */ @Data @NoArgsConstructor @AllArgsConstructor public class HelloEvent { private String eventName; } @Data @No

  • springBoot的事件机制GenericApplicationListener用法解析

    什么是ApplicationContext? 它是Spring的核心,Context我们通常解释为上下文环境,但是理解成容器会更好些. ApplicationContext则是应用的容器. Spring把Bean(object)放在容器中,需要用就通过get方法取出来. ApplicationEvent 是个抽象类,里面只有一个构造函数和一个长整型的timestamp. springboot的event的类型: ApplicationStartingEvent ApplicationEnviro

  • 使用Spring事件机制实现异步的方法

    当把一个事件发布到Spring提供的ApplicationContext中,被监听器侦测到,就会执行对应的处理方法. 事件本身 事件是一个自定义的类,需要继承Spring提供的ApplicationEvent. @Data public class MyEvent extends ApplicationEvent { private String msg; public MyEvent(Object source, String msg) { super(source); this.msg =

  • Spring的事件机制知识点详解及实例分析

    同步事件和异步事件 同步事件: 在一个线程里,按顺序执行业务,做完一件事再去做下一件事. 异步事件: 在一个线程里,做一个事的同事,可以另起一个新的线程执行另一件事,这样两件事可以同时执行. 用一个例子来解释同步事件和异步事件的使用场景,有时候一段完整的代码逻辑,可能分为几部分,拿最常见的注册来说,假设完整流程是,1.点击注册->2.检验信息并存库->3.发送邮件通知->4.返回给用户.代码这么写是正确,但不是最好的,缺点如下: 逻辑复杂,业务耦合,我们把校验数据并存库和发送邮件写到一个

  • Spring AOP的实现原理详解及实例

    Spring AOP的实现原理详解及实例 spring 实现AOP是依赖JDK动态代理和CGLIB代理实现的. 以下是JDK动态代理和CGLIB代理简单介绍 JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理. CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类.CGLIB是高效的代码生成包,底层是依靠ASM(开源的Java字节码编辑类库)操作字节码实现的,性能比JDK强. 在Spring中

  • mysql分区功能详解,以及实例分析

    一,什么是数据库分区 前段时间写过一篇关于mysql分表的 的文章,下面来说一下什么是数据库分区,以mysql为例.mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面 (可以通过my.cnf中的datadir来查看),一张表主要对应着三个文件,一个是frm存放表结构的,一个是myd存放表数据的,一个是myi存表 索引的.如果一张表的数据量太大的话,那么myd,myi就会变的很大,查找数据就会变的很慢,这个时候我们可以利用mysql的分区功能,在物理上将这 一张

  • Java List 用法详解及实例分析

    Java List 用法详解及实例分析 Java中可变数组的原理就是不断的创建新的数组,将原数组加到新的数组中,下文对Java List用法做了详解. List:元素是有序的(怎么存的就怎么取出来,顺序不会乱),元素可以重复(角标1上有个3,角标2上也可以有个3)因为该集合体系有索引 ArrayList:底层的数据结构使用的是数组结构(数组长度是可变的百分之五十延长)(特点是查询很快,但增删较慢)线程不同步 LinkedList:底层的数据结构是链表结构(特点是查询较慢,增删较快) Vector

  • Spring MVC异常处理机制示例详解

    前言 在Spring MVC中,当一个请求发生异常(Controller抛出一个异常时), DispatcherServlet 采用委托的方式交给一个处理链来处理或者解析这个抛出的异常,这是在request和Servlet Container之间的一道屏障,所以我们可以在这里做一些处理工作,如转换异常,转换成友好的error page或者http 状态码等. 核心接口 这个处理机制在Spring是以HandlerExceptionResolver接口为核心的,该接口只有一个处理方法: Model

  • Java 回调机制(CallBack) 详解及实例代码

     Java 回调机制 概要: 最近学习java,接触到了回调机制(CallBack).初识时感觉比较混乱,而且在网上搜索到的相关的讲解,要么一言带过,要么说的比较单纯的像是给CallBack做了一个定义.当然了,我在理解了回调之后,再去看网上的各种讲解,确实没什么问题.但是,对于初学的我来说,缺了一个循序渐进的过程.此处,将我对回调机制的个人理解,按照由浅到深的顺序描述一下,如有不妥之处,望不吝赐教! 开始之前,先想象一个场景:幼稚园的小朋友刚刚学习了10以内的加法. 第1章. 故事的缘起 幼师

  • Java Spring中Quartz调度器详解及实例

    一.Quartz的特点 * 按作业类的继承方式来分,主要有以下两种: 1.作业类继承org.springframework.scheduling.quartz.QuartzJobBean类的方式 2.作业类不继承org.springframework.scheduling.quartz.QuartzJobBean类的方式 注:个人比较推崇第二种,因为这种方式下的作业类仍然是POJO. * 按任务调度的触发时机来分,主要有以下两种: 1.每隔指定时间则触发一次,对应的调度器为org.springf

  • 微信 小程序前端源码详解及实例分析

    微信小程序前端源码逻辑和工作流 看完微信小程序的前端代码真的让我热血沸腾啊,代码逻辑和设计一目了然,没有多余的东西,真的是大道至简. 废话不多说,直接分析前端代码.个人观点,难免有疏漏,仅供参考. 文件基本结构: 先看入口app.js,app(obj)注册一个小程序.接受一个 object 参数,其指定小程序的生命周期函数等.其他文件可以通过全局方法getApp()获取app实例,进而直接调用它的属性或方法,例如(getApp().globalData) //app.js App({ onLau

  • javascript中的深复制详解及实例分析

     javascript中的深复制 JavaScript深拷贝是初学者甚至有经验的开发着,都会经常遇到问题,并不能很好的理解javascript的深拷贝.        深拷贝(deepClone)是神马,与深拷贝相对应的就是浅拷贝,刚开始我也没弄懂. 在很多情况下,我们都需要给变量赋值,给内存地址赋予一个值,但是在赋值引用值类型的时候,只是共享一个内存区域,导致赋值的时候,还跟之前的值保持一直性. 看一个具体的例子 // 给test赋值了一个对象 var test = { a: 'a', b:

  • Spring事件监听机制观察者模式详解

    目录 前言 观察者模式 观察者的角色定义 Java中的事件机制 Spring中的事件机制 Spring事件监听案例 小结 前言 Spring中提供了一套默认的事件监听机制,在容器初始化时便使用了这套机制.同时,Spring也提供了事件监听机制的接口扩展能力,开发者基于此可快速实现自定义的事件监听功能. Spring的事件监听机制是在JDK事件监听的基础上进行的扩展,也是在典型观察者模式上的进一步抽象和改进.所以,结合Spring的事件监听机制与观察者模式来学习,可以达到理论与实践的完美融合. 本

随机推荐