在SpringBoot中实现异步事件驱动-阿里云开发者社区

开发者社区> 飘渺Jam> 正文

在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。


6a3303dffa0bf740b33991cfe389f2ab.png


源码实战


  • 创建事件
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;
    }

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
10074 0
AI 事件驱动场景 Serverless 实践
事件驱动是指事件在持续事务管理过程中,进行决策的一种策略。可以通过调动可用资源执行相关任务,从而解决不断出现的问题。通俗地说是当用户触发使用行为时对用户行为的响应。在 Serverless 场景下,事件驱动完美符合其设计初衷之一:按需付费。
6617 0
弹性计算OOS事件驱动自动化运维
本方案适合Terraform的迁移用户或准备使用Terraform的用户。可以帮助客户在阿里云安全、高效地预配和管理云基础产品。用户在正式使用前,对Terraform模块与实际使用模块的基本验证,用于对管理和维护IT资源的日常操作的验证。
5089 0
EDA 事件驱动架构与 EventBridge 二三事
事件驱动型架构 (EDA) 方兴未艾,作为一种 Serverless 化的应用概念对云原生架构具有着深远影响。当我们讨论到一个具体架构时,首当其冲的是它的发展是否具有技术先进性。这里从我们熟悉的 MVC 架构,SOA 架构谈起,聊一聊关于消息事件领域的历史与发展趋势。
169 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13882 0
阿里云ECS云服务器初始化设置教程方法
阿里云ECS云服务器初始化是指将云服务器系统恢复到最初状态的过程,阿里云的服务器初始化是通过更换系统盘来实现的,是免费的,阿里云百科网分享服务器初始化教程: 服务器初始化教程方法 本文的服务器初始化是指将ECS云服务器系统恢复到最初状态,服务器中的数据也会被清空,所以初始化之前一定要先备份好。
11888 0
函数计算:事件驱动的无服务器计算服务
本文整理自2017云栖大会-成都峰会上阿里云存储服务高级专家杨皓然的分享讲义,讲义主要介绍了阿里云函数计算在计算新需求的驱动下的逐步进化历程,将传统计算服务与函数计算相对比,使函数计算运维成本低等核心优势得以凸显,函数计算在截然不同的场景中都极具吸引力,并介绍了更多函数计算的应用示例。
2189 0
阿里云ECS云服务器初始化设置教程方法
阿里云ECS云服务器初始化是指将云服务器系统恢复到最初状态的过程,阿里云的服务器初始化是通过更换系统盘来实现的,是免费的,阿里云百科网分享服务器初始化教程: 服务器初始化教程方法 本文的服务器初始化是指将ECS云服务器系统恢复到最初状态,服务器中的数据也会被清空,所以初始化之前一定要先备份好。
7365 0
+关注
飘渺Jam
飘渺Jam,CSDN博客专家, 一名写代码的架构师,做架构的程序员,可以通过 jianzh5 与我联系,咱们一起聊技术!
108
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载