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

作者:飘渺Jam 时间:2023-11-01 07:48:54 

目录
  • Spring事件驱动

  • 源码实战

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


@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;
   }
}

来源:https://blog.csdn.net/jianzhang11/article/details/118209620

标签:SpringBoot,异步,事件驱动
0
投稿

猜你喜欢

  • Java中ArrayList的工作原理详解

    2021-12-18 08:01:45
  • Java Swing 多线程加载图片(保证顺序一致)

    2023-10-26 10:10:36
  • 详解Spring Security认证流程

    2022-04-16 15:48:46
  • Java中的对称加密详解

    2023-09-30 12:17:16
  • 详细介绍Android-Room数据库的使用

    2022-10-30 09:10:53
  • Java实现登录和注册案例

    2022-02-27 04:57:46
  • Android RecyclerView详解及简单实例

    2023-03-06 21:31:29
  • Java实现通讯录管理系统项目

    2022-11-17 02:41:03
  • mybatis源码解读之executor包懒加载功能 

    2022-09-17 00:28:05
  • Spring Boot中如何使用断路器详解

    2022-03-03 06:34:49
  • ANDROID中自定义对话框AlertDialog使用示例

    2023-07-22 17:24:12
  • c++回调之利用函数指针示例

    2022-07-26 06:59:32
  • JAVA过滤标签实现将html内容转换为文本的方法示例

    2022-10-16 21:02:40
  • Jackson中json格式的字符串与对象的互相转换方式

    2022-01-29 03:31:07
  • Android开发使用strings.xml多语言翻译解决方案

    2023-06-27 14:19:24
  • java实现打砖块游戏算法

    2023-01-28 20:51:06
  • Java利用cors实现跨域请求实例

    2023-02-24 14:57:35
  • 关于Android中自定义ClassLoader耗时问题的追查

    2021-08-10 06:15:23
  • java之路径分隔符介绍

    2022-12-14 22:35:23
  • Spring Boot2发布调用REST服务实现方法

    2023-12-10 20:03:49
  • asp之家 软件编程 m.aspxhome.com