服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - springboot 事件监听器的案例详解

springboot 事件监听器的案例详解

2023-02-24 14:46小码农叔叔 Java教程

这篇文章主要介绍了springboot 事件监听器,springboot(spring)的事件监听器使用主要有两种方式,通过实现ApplicationListener接口,另一个就是在类上添加 @EventListener 注解来实现,接下来将对这两种方式逐一说明,需要的朋友可以参考下

前言

在spring框架中,提供了很多动态灵活且可扩展的机制,开发者可以利用这些机制完成一些巧妙的业务,实现一些业务中的解耦,

 

引导案例

下面看一个简单的案例,

@Configuration
public class SelfBusiness {
  public static void main(String[] args) {
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SelfBusiness.class);
      context.getBean(MyService.class).doBusiness();
      context.close();
  }
  @Component
  static class MyService {
      private static final Logger logger = LoggerFactory.getLogger(MyService.class);
      @Autowired
      private ApplicationEventPublisher publisher;
      public void doBusiness (){
          logger.debug("主线业务");
          logger.debug("发送短信");
          logger.debug("发送邮件");
      }
  }

运行上面的代码,观察效果

springboot 事件监听器的案例详解

结合输出结果,这这段代码要实现的逻辑是,在主线业务执行完成后,需要执行发短信,发邮件等操作,这样写也没毛病,但不够优雅,从后续的业务可扩展性上来讲,不够友好,如果后续主线业务执行完毕,还需再增加一个其他的审计操作,则需要新增代码逻辑,这就将主线业务和支线逻辑紧密的耦合了起来;

就是说,我们期待的效果是,主线业务根本不关心其他的业务操作,只需要完成自身的逻辑就ok了,这就需要使用到spring提供的事件监听器功能;

使用事件监听器改造过程

springboot(spring)的事件监听器使用主要有两种方式,通过实现ApplicationListener接口,另一个就是在类上添加 @EventListener 注解来实现,接下来将对这两种方式逐一说明;

 

一、通过实现ApplicationListener接口实现步骤

1、自定义一个事件类(对象),继承ApplicationEvent

 static class MyEvent extends ApplicationEvent {
      public MyEvent(Object source) {
          super(source);
      }
  }

可以这么理解,在代码中,可能有很多种类型的事件,不同的业务对应着不同的事件,对于某个具体的监听器来说,它只想监听A这种类型的事件;

2、自定义业务类实现ApplicationListener 接口

  
	@Data
  static class Params {
      private String id ;
      private String name;
      private String phone;
  }
	@Component
  static class SmsApplicationListener implements ApplicationListener<MyEvent> {
      private static final Logger logger = LoggerFactory.getLogger(SmsApplicationListener.class);
      @Override
      public void onApplicationEvent(MyEvent myEvent) {
          Object source = myEvent.getSource();
          try {
              Params params = objectMapper.readValue(source.toString(), Params.class);
              logger.debug("userId : {}",params.getId());
          } catch (JsonProcessingException e) {
              e.printStackTrace();
          }
          logger.debug("执行 sms 发短信业务");
      }
  }
  @Component
  static class EmailApplicationListener implements ApplicationListener<MyEvent> {
      private static final Logger logger = LoggerFactory.getLogger(SmsApplicationListener.class);
      @Override
      public void onApplicationEvent(MyEvent myEvent) {
          Object source = myEvent.getSource();
          logger.debug("执行 email 发邮件业务");
      }
  }

显然,这里的监听器要监听的事件类型,正是上面我们定义的MyEvent ,这样,当业务被触发的时候,就可以在onApplicationEvent中拿到传递过来的参数,从而执行发短信(发邮件)业务操作了

3、主线业务发布事件

@Component
  static class MyService {
      private static final Logger logger = LoggerFactory.getLogger(MyService.class);
      @Autowired
      private ApplicationEventPublisher publisher;
      public void doBusiness (){
          Params params = new Params();
          params.setId("001");
          params.setName("xiaoma");
          params.setPhone("133******");
          logger.debug("主线业务");
          try {
              publisher.publishEvent(new MyEvent(objectMapper.writeValueAsString(params)));
          } catch (JsonProcessingException e) {
              e.printStackTrace();
          }
          //publisher.publishEvent(new MyEvent("MyService doBusiness()"));
          //logger.debug("发送短信");
          //logger.debug("发送邮件");
      }
  }

对主线业务来说,这时候就不再需要写发送短信或邮件逻辑了,只需要一个publisher将事件发布出去即可,如果需要传递参数,将参数一起传递过去

完整的代码

@Configuration
public class SelfBusiness {
  private static ObjectMapper objectMapper = new ObjectMapper();
  public static void main(String[] args) {
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SelfBusiness.class);
      context.getBean(MyService.class).doBusiness();
      context.close();
  }
  @Data
  static class Params {
      private String id ;
      private String name;
      private String phone;
  }
  /**
   * 自定义事件对象
   */
  static class MyEvent extends ApplicationEvent {
      public MyEvent(Object source) {
          super(source);
      }
  }
  @Component
  static class MyService {
      private static final Logger logger = LoggerFactory.getLogger(MyService.class);
      @Autowired
      private ApplicationEventPublisher publisher;
      public void doBusiness (){
          Params params = new Params();
          params.setId("001");
          params.setName("xiaoma");
          params.setPhone("133******");
          logger.debug("主线业务");
          try {
              publisher.publishEvent(new MyEvent(objectMapper.writeValueAsString(params)));
          } catch (JsonProcessingException e) {
              e.printStackTrace();
          }
          //publisher.publishEvent(new MyEvent("MyService doBusiness()"));
          //logger.debug("发送短信");
          //logger.debug("发送邮件");
      }
  }
  /**
   * 监听事件触发后要执行的业务
   */
  @Component
  static class SmsApplicationListener implements ApplicationListener<MyEvent> {
      private static final Logger logger = LoggerFactory.getLogger(SmsApplicationListener.class);
      @Override
      public void onApplicationEvent(MyEvent myEvent) {
          Object source = myEvent.getSource();
          try {
              Params params = objectMapper.readValue(source.toString(), Params.class);
              logger.debug("userId : {}",params.getId());
          } catch (JsonProcessingException e) {
              e.printStackTrace();
          }
          logger.debug("执行 sms 发短信业务");
      }
  }
  @Component
  static class EmailApplicationListener implements ApplicationListener<MyEvent> {
      private static final Logger logger = LoggerFactory.getLogger(SmsApplicationListener.class);
      @Override
      public void onApplicationEvent(MyEvent myEvent) {
          Object source = myEvent.getSource();
          logger.debug("执行 email 发邮件业务");
      }
  }
}

再次运行上面的代码,观察效果,可以看到,仍然能满足预期的效果

springboot 事件监听器的案例详解

 

二、通过添加 @EventListener 注解来实现

这种方式不再需要实现ApplicationListener 接口,而是直接在监听类的方法上面添加 @EventListener注解即可,相对要简化了一些,下面直接贴出完整的代码

package com.congge.config;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Configuration
public class SelfBusiness2 {
  private static ObjectMapper objectMapper = new ObjectMapper();
  public static void main(String[] args) {
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SelfBusiness2.class);
      context.getBean(MyService.class).doBusiness();
      context.close();
  }
  @Data
  static class Params {
      private String id ;
      private String name;
      private String phone;
  }
  /**
   * 自定义事件对象
   */
  static class MyEvent extends ApplicationEvent {
      public MyEvent(Object source) {
          super(source);
      }
  }
  @Component
  static class MyService {
      private static final Logger logger = LoggerFactory.getLogger(MyService.class);
      @Autowired
      private ApplicationEventPublisher publisher;
      public void doBusiness (){
          Params params = new Params();
          params.setId("001");
          params.setName("xiaoma");
          params.setPhone("133******");
          logger.debug("主线业务");
          try {
              publisher.publishEvent(new MyEvent(objectMapper.writeValueAsString(params)));
          } catch (JsonProcessingException e) {
              e.printStackTrace();
          }
      }
  }
  @Component
  static class SmsListenerService {
      private static final Logger logger = LoggerFactory.getLogger(SmsListenerService.class);
      @EventListener
      public void smsListener(MyEvent myEvent){
          Object source = myEvent.getSource();
          try {
              SelfBusiness2.Params params = objectMapper.readValue(source.toString(), SelfBusiness2.Params.class);
              logger.debug("userId : {}",params.getId());
          } catch (JsonProcessingException e) {
              e.printStackTrace();
          }
          logger.debug("执行 sms 发短信业务");
      }
  }
  @Component
  static class EmailListenerService {
      private static final Logger logger = LoggerFactory.getLogger(EmailListenerService.class);
      @EventListener
      public void emailListener(MyEvent myEvent){
          Object source = myEvent.getSource();
          try {
              SelfBusiness2.Params params = objectMapper.readValue(source.toString(), SelfBusiness2.Params.class);
              logger.debug("userId : {}",params.getId());
          } catch (JsonProcessingException e) {
              e.printStackTrace();
          }
          logger.debug("执行 email 发邮件业务");
      }
  }
}

运行上面的代码,观察效果,同样可以达到预期的效果

springboot 事件监听器的案例详解

 

三、使用异步

更进一步来说,为了提升主线业务的逻辑执行效率,我们希望发布事件的业务逻辑异步执行,这个该如何做呢?

翻阅源码可以知道,ApplicationEventPublisher 默认发布事件时候采用单线程同步发送,如果需要使用异步,需要自定义 ThreadPoolTaskExecutor ,以及SimpleApplicationEventMulticaster ,因此我们只需要覆盖一下这两个组件的bean即可,在上面的业务类中将下面的这两个bean添加进去;

@Bean
  public ThreadPoolTaskExecutor executor() {
      ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
      executor.setCorePoolSize(5);
      executor.setMaxPoolSize(10);
      executor.setQueueCapacity(100);
      return executor;
  }
  @Bean
  public SimpleApplicationEventMulticaster applicationEventMulticaster(ThreadPoolTaskExecutor executor) {
      SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
      eventMulticaster.setTaskExecutor(executor);
      return eventMulticaster;
  }

这时候再次运行代码,反复运行多次,就可以看到效果

springboot 事件监听器的案例详解

对比下上面单线程效果

springboot 事件监听器的案例详解

自定义事件发布器

到此这篇关于springboot 事件监听器的文章就介绍到这了,更多相关springboot 事件监听器内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/zhangcongyi420/article/details/125242354

延伸 · 阅读

精彩推荐
  • Java教程spring实例化javabean的三种方式分享

    spring实例化javabean的三种方式分享

    这篇文章介绍了spring实例化javabean的三种方式,有需要的朋友可以参考一下 ...

    java技术网6112019-10-16
  • Java教程详解Java中Collector接口的组成

    详解Java中Collector接口的组成

    今天给大家带来的是关于Java基础的相关知识,文章围绕着Collector接口的组成展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下...

    只要你一直跑4182021-09-22
  • Java教程java 操作gis geometry类型数据方式

    java 操作gis geometry类型数据方式

    这篇文章主要介绍了java 操作gis geometry类型数据方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...

    TNT_D11292022-09-14
  • Java教程Java中求Logn/log2 的精度问题

    Java中求Logn/log2 的精度问题

    这篇文章主要介绍了Java中求Logn/log2 的精度问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...

    杨瘦锅11862021-11-17
  • Java教程详解Spring Cloud Gateway 限流操作

    详解Spring Cloud Gateway 限流操作

    这篇文章主要介绍了详解Spring Cloud Gateway 限流操作,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    尹吉欢8772021-05-19
  • Java教程Java上传文件图片到服务器的方法

    Java上传文件图片到服务器的方法

    这篇文章主要为大家详细介绍了Java上传文件图片到服务器的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    故事说到这里9032021-03-17
  • Java教程10分钟看懂 Java NIO 底层原理

    10分钟看懂 Java NIO 底层原理

    四种IO模型,理论上越往后,阻塞越少,效率也是最优。在这四种 I/O 模型中,前三种属于同步 I/O,因为其中真正的 I/O 操作将阻塞线程。只有最后一种,才...

    Java建设者3212020-10-30
  • Java教程在RabbitMQ中实现Work queues工作队列模式

    在RabbitMQ中实现Work queues工作队列模式

    这篇文章主要介绍了如何在RabbitMQ中实现Work queues模式,代码详细,解释清晰,可以帮助大家更好理解java,对这方面感兴趣的朋友可以参考下...

    Java_Caiyo4672021-09-08