SpringBoot实现异步事件驱动的方法

在项目实际开发过程中,我们有很多这样的业务场景:一个事务中处理完一个业务逻辑后需要跟着处理另外一个业务逻辑,伪码大致如下:

@Service
public class ProductServiceImpl {
 ...
    public void saveProduct(Product product) {
        productMapper.saveOrder(product);
        notifyService.notify(product);
    }
 ...
}

很简单并且很常见的一段业务逻辑:首先将产品先保存数据库,然后发送通知。

某一天你们可能需要把新增的产品存到Es中,这时候也需要代码可能变成这样:

@Service
public class ProductServiceImpl {
 ...
    public void saveProduct(Product product) {
        productMapper.saveProduct(product);
        esService.saveProduct(product)
        notifyService.notify(product);
    }
 ...
}

随着业务需求的变化,代码也需要跟着一遍遍的修改。而且还会存在另外一个问题,如果通知系统挂了,那就不能再新增产品了。

对于上面这种情况非常适合引入消息中间件(消息队列)来对业务进行解耦,但并非所有的业务系统都会引入消息中间件(引入会第三方架构组件会带来很大的运维成本)。

Spring提供了事件驱动机制可以帮助我们实现这一需求。

Spring事件驱动

spring事件驱动由3个部分组成

  • ApplicationEvent:表示事件本身,自定义事件需要继承该类,用来定义事件
  • ApplicationEventPublisher:事件发送器,主要用来发布事件
  • ApplicationListener:事件监听器接口,监听类实现ApplicationListener 里onApplicationEvent方法即可,也可以在方法上增加@EventListener以实现事件监听。

实现Spring事件驱动一般只需要三步:

  • 自定义需要发布的事件类,需要继承ApplicationEvent类
  • 使用ApplicationEventPublisher来发布自定义事件
  • 使用@EventListener来监听事件

这里需要特别注意一点,默认情况下事件是同步的。即事件被publish后会等待Listener的处理。如果发布事件处的业务存在事务,监听器处理也会在相同的事务中。如果需要异步处理事件,可以onApplicationEvent方法上加@Aync支持异步或在有@EventListener的注解方法上加上@Aync。

源码实战

创建事件

public class ProductEvent extends ApplicationEvent {
    public ProductEvent(Product product) {
        super(product);
    }
}

发布事件

@Service
public class ProductServiceImpl implements IproductService {
 ...
    @Autowired
    private ApplicationEventPublisher publisher;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveProduct(Product product) {
  productMapper.saveProduct(product);
        //事件发布
        publisher.publishEvent(product);
    }
    ...
}

事件监听

@Slf4j
@AllArgsConstructor
public class ProductListener {

 private final NotifyService notifyServcie;

 @Async
 @Order
 @EventListener(ProductEvent.class)
 public void notify(ProductEvent event) {
  Product product = (Product) event.getSource();
  notifyServcie.notify(product, "product");
 }
}

在SpringBoot启动类上增加@EnableAsync 注解

@Slf4j
@EnableSwagger2
@SpringBootApplication
@EnableAsync
public class ApplicationBootstrap {
...
}

使用了Async后会使用默认的线程池SimpleAsyncTaskExecutor,一般我们会在项目中自定义一个线程池。

@Configuration
public class ExecutorConfig {
    /** 核心线程数 */
    private int corePoolSize = 10;
    /** 最大线程数  */
    private int maxPoolSize = 50;
    /** 队列大小  */
    private int queueCapacity = 10;
    /** 线程最大空闲时间   */
    private int keepAliveSeconds = 150;

    @Bean("customExecutor")
    public Executor myExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setThreadNamePrefix("customExecutor-");
        executor.setKeepAliveSeconds(keepAliveSeconds);

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

到此这篇关于SpringBoot实现异步事件驱动的方法的文章就介绍到这了,更多相关SpringBoot 异步事件驱动内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 基于SpringBoot核心原理(自动配置、事件驱动、Condition)

    前言 SpringBoot是Spring的包装,通过自动配置使得SpringBoot可以做到开箱即用,上手成本非常低,但是学习其实现原理的成本大大增加,需要先了解熟悉Spring原理.如果还不清楚Spring原理的,可以先查看博主之前的文章,本篇主要分析SpringBoot的启动.自动配置.Condition.事件驱动原理. 正文 启动原理 SpringBoot启动非常简单,因其内置了Tomcat,所以只需要通过下面几种方式启动即可: @SpringBootApplication(scanBas

  • SpringBoot实现异步事件驱动的方法

    在项目实际开发过程中,我们有很多这样的业务场景:一个事务中处理完一个业务逻辑后需要跟着处理另外一个业务逻辑,伪码大致如下: @Service public class ProductServiceImpl { ... public void saveProduct(Product product) { productMapper.saveOrder(product); notifyService.notify(product); } ... } 很简单并且很常见的一段业务逻辑:首先将产品先保存数

  • SpringBoot开启异步调用方法

    异步调用无需等待,方法相当于子线程,后台执行,主线程执行完成,子线程开始执行. SpringBoot 开启异步执行仅需两步: 方法上加 @Async @Override @Async @Transactional(rollbackFor = Exception.class) public Integer init(DatePojo datePojo){ //xxxxxxxxxxx 业务略 xxxxxxx log.info(" 起止日期为 : {} , {} ", start, end)

  • 详解SpringBoot中异步请求和异步调用(看完这一篇就够了)

    一.SpringBoot中异步请求的使用 1.异步请求与同步请求 特点: 可以先释放容器分配给请求的线程与相关资源,减轻系统负担,释放了容器所分配线程的请求,其响应将被延后,可以在耗时处理完成(例如长时间的运算)时再对客户端进行响应.一句话:增加了服务器对客户端请求的吞吐量(实际生产上我们用的比较少,如果并发请求量很大的情况下,我们会通过nginx把请求负载到集群服务的各个节点上来分摊请求压力,当然还可以通过消息队列来做请求的缓冲). 2.异步请求的实现 方式一:Servlet方式实现异步请求

  • springboot实现异步调用@Async的示例

    在后端开发中经常遇到一些耗时或者第三方系统调用的情况,我们知道Java程序一般的执行流程是顺序执行(不考虑多线程并发的情况),但是顺序执行的效率肯定是无法达到我们的预期的,这时就期望可以并行执行,常规的做法是使用多线程或线程池,需要额外编写代码实现.在spring3.0后引入了@Async注解,使用该注解可以达到线程池的执行效果,而且在开发上非常简单. 一.概述 springboot是基于spring框架的,在springboot环境下演示@Async注解的使用方式.先看下该注解的定义, @Ta

  • springboot实现异步任务

    本文实例为大家分享了springboot实现异步任务的具体代码,供大家参考,具体内容如下 1.什么异步任务 同步:一定要等任务执行完了,得到结果,才执行下一个任务. 异步:不等任务执行完,直接执行下一个任务. 2.异步任务使用场景 在许多网站中,都会有发送邮件验证邮箱功能,执行该任务时,需要较长的时间,此时为了更好的用户体验,前端可以先返回完成的信息,后台去执行任务. 3.异步任务的实现步骤 首先模拟一个网站跳转的过程,假设某一个线程执行任务时需要5秒,结束以后才会进行下一步操作,我们令线程休眠

  • SpringBoot中使用多线程的方法示例

    一.介绍 Spring是通过任务执行器(TaskExecutor)来实现多线程和并发编程,使用Spring提供的ThreadPoolTaskExecutor来创建一个基于线城池的TaskExecutor.在使用线程池的大多数情况下都是异步非阻塞的.节省更多的时间,提高效率. 工作原理 当主线程中调用execute接口提交执行任务时:则执行以下步骤:注意:线程池初始时,是空的. 如果当前线程数<corePoolSize,如果是则创建新的线程执行该任务 如果当前线程数>=corePoolSize,

  • 详解springboot使用异步注解@Async获取执行结果的坑

    目录 一.引言 二.获取异步执行结果 1.环境介绍 2.错误的方式 3.正确方式 三.异步执行@Async注解 四.总结 一.引言 在java后端开发中经常会碰到处理多个任务的情况,比如一个方法中要调用多个请求,然后把多个请求的结果合并后统一返回,一般情况下调用其他的请求一般都是同步的,也就是每个请求都是阻塞的,那么这个处理时间必定是很长的,有没有一种方法可以让多个请求异步处理那,答案是有的. springboot中提供了很便利的方式可以解决上面的问题,那就是异步注解@Async.正确的使用该注

  • springboot为异步任务规划自定义线程池的实现

    目录 一.Spring Boot任务线程池 二.自定义线程池 三.优雅地关闭线程池 一.Spring Boot任务线程池 线程池的作用 防止资源占用无限的扩张 调用过程省去资源的创建和销毁所占用的时间 在高并发环境下,不断的分配新资源,可能导致系统资源耗尽.所以为了避免这个问题,我们为异步任务规划一个线程池.当然,如果没有配置线程池的话,springboot会自动配置一个ThreadPoolTaskExecutor 线程池到bean当中. # 核心线程数 spring.task.executio

  • SpringBoot实现自定义事件的方法详解

    目录 简介 步骤1:自定义事件 步骤2:自定义监听器 方案1:ApplicationListener 方案2:SmartApplicationListener 步骤3:注册监听器 法1:@Component(适用于所有监听器) 法2:application.yml中添加配置 法3:启动类中注册 步骤4:发布事件 法1:注入ApplicationContext,调用其publishEvent方法 法2:启动类中发布 简介 说明 本文用实例来介绍如何在SpringBoot中自定义事件来使用观察者模式

  • PHP编程实现脚本异步执行的方法

    本文实例讲述了PHP编程实现脚本异步执行的方法.分享给大家供大家参考,具体如下: php语言得用fsockopen()函数,实现脚本异步运行,代码如下 异步请求函数(用debug参数若为true则为用为调试,开启调试可以看到异步的执行情况,但是失去异步的效果) main.php <?php function request_by_fsockopen($url,$post_data=array(),$debug=false){ $url_array = parse_url($url); $host

随机推荐