springboot实战之事件驱动模型

前言

假设有这么一种业务场景,业务A处理完后,同时触发B、C、D业务执行,在不利用MQ的情况下,会有什么样的解决思路?可能的解决思路有如下 1、业务A处理后,开启线程处理B、C、D 2、使用disruptor进行处理 3、生产消费者模式 4、观察者模式 ... 解决的思路有多种多样,这边介绍一种思路->事件驱动模式,事件驱动模式与观察者模式在某些方面极为相似:当一个主体发生改变时,所有依属体都得到通知。不过,观察者模式与单个事件源关联,而事件驱动模式则可以与多个事件源关联。本文就介绍一下基于spring实现的事件驱动

spring事件驱动组成

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

1、ApplicationEvent:表示事件本身,自定义事件需要继承该类。用来定义事件

2、ApplicationEventPublisherAware:事件发送器,需要实现该接口。主要用来发布事件

3、ApplicationListener:事件监听器接口。监听类实现ApplicationListener 里onApplicationEvent方法即可

spring事件驱动示例

示例演示了当数据库信息配置发生变更时,通过事件驱动异步变更spring的数据库配置信息bean,并通过定时器输出数据库配置信息。

本例子没有用ApplicationListener接口来实现监听。在spring4.2+推出了更优雅,基于注解的方式@EventListener来实现

1、发布事件

@Service
public class JdbcConfigServiceImpl implements JdbcConfigService, ApplicationEventPublisherAware {

    @Autowired
    private Mapper dozerMapper;

    @Autowired
    ApplicationEventPublisher applicationEventPublisher;

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

    @Override
    public String refreshJdbcConfig(JdbcConfigDTO jdbcConfigDTO) {
        JdbcConfig jdbcConfig = dozerMapper.map(jdbcConfigDTO,JdbcConfig.class);
        JdbcConfig cacheJdbcConfig = CacheJdbcConfigUtil.INSTANCE.getjdbcConfig();
        JdbcConfig changeFieldJdbcConfig = getChangeJdbcConfig(jdbcConfig, cacheJdbcConfig);

        if(StringUtils.isBlank(changeFieldJdbcConfig.getDriverClassName()) && StringUtils.isBlank(changeFieldJdbcConfig.getPassword())
                && StringUtils.isBlank(changeFieldJdbcConfig.getUrl())&& StringUtils.isBlank(changeFieldJdbcConfig.getUsername())){
            applicationEventPublisher.publishEvent("noChange");
            return "no change";
        }
        applicationEventPublisher.publishEvent(changeFieldJdbcConfig);
        return "refresh success";
    }

2、定义事件源以及监听器

@EventListener
    @Async
    public void changeRegisterBean(JdbcConfig jdbcConfig){
      log.info("refresh {}",jdbcConfig);
      JdbcConfig config = CacheJdbcConfigUtil.INSTANCE.refreshAndGet(jdbcConfig);
      BeanUtils.copyProperties(config,this.jdbcConfig);
      System.out.println(config);
    }

注:方法参数JdbcConfig jdbcConfig就是事件源

spring事件驱动注意点

  • 事件没要处理的监听器,就会被抛弃。
  • 一个事件可以同时被多个监听处理类监听处理。
  • 默认情况下事件是同步的,即事件被publish后会等待Listener的处理。如果发布事件处的业务存在事务,监听器处理也会在相同的事务中。
  • 如果对于事件的处理不想受到影响,可以onApplicationEvent方法上加@Aync支持异步/在有@EventListener的注解方法上加上@Aync。注:启动类上同时要加上@EnableAsync

利用@TransactionalEventListener实现监听事件时的事务隔离

@TransactionalEventListener和@EventListener都可以监听事件,但前者可以对发布事件和监听事件进行一些事务上的隔离。@TransactionalEventListener指不和发布事件的方法在同一个事务内,发布事件的方法事务结束后才会执行本监听方法,监听逻辑内发生异常不会回滚发布事件方法的事务。

@TransactionalEventListener有一个属性为fallbackExecution,默认为false,指发布事件的方法没有事务控制时,监听器不进行监听事件,此为默认情况!fallbackExecution=true,则指发布事件的方法没有事务控制时,监听方法仍可以监听事件进行处理。

总结

你有一件事情,做这件事情的过程包含了许多职责单一的子过程,而这些子过程有如下特点

  • 这些子过程有一定的执行次序;
  • 这些子过程之间需要较灵活的跳转;
  • 这些子过程也许需要围绕同一个上下文做操作;

此时就可以采用事件驱动模式,从而使得各个子过程的开发可以专注于自己的业务。

参考文档

SpringCloud工作笔记078---SpringBoot中使用sping事件驱动模型 https://blog.csdn.net/lidew521/article/details/94403577

事件驱动模型和观察者模式 https://blog.csdn.net/asdfsadfasdfsa/article/details/78175567

demo链接

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-event-driven

原文发布于微信公众号 - Linyb极客之路(gh_c420b2cf6b47)

原文发表时间:2019-08-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券