Spring 事件推送publishEvent

Spring 事件推送publishEvent

一、 简介

ApplicationContext.publishEvent 是 Spring 提供的解耦的一种方式,在 org.springframework.context 包下。

如果项目规模较大,已经引入了 MQ、XxlJob 等中间件,可以使用中间件替代。

默认是同步操作的,也就是说发布完之后需要等监听执行完毕才可以;异步需要单独开启,加 @Async 注解即可。



二、 原理

本质上是设计模式中的观察者模式。

事件模型有三个组成部分:事件源 source(被监听对象)、事件 event 和监听对象 listener。


三、 使用

简单示例代码

1. 定义事件

事件中需要在构造方法中调用父类的构造方法,将事件源传入。

也可以在构造方法中添加其他参数或者在事件源中添加其他方法,在监听类中可以调用相应方法,结合具体业务进行拓展。

public class SelfEvent extends ApplicationEvent {

    public SelfEvent(Object source) {
        super(source);
    }

}

2. 定义事件源

事件源就是要监听的对象,比如要记录系统登录信息,那就定义一个对象以及表来存储信息,定义的对象就是事件源。

本文以 Map 为例。


3. 定义监听对象

监听对象有两种形式:一种是类定义,就是针对一个事件用一个监听类;另一种是基于注解实现,该方式可以针对一类业务,即一个监听类中可以监听多个事件。

@Component
public class SelfEventListener implements ApplicationListener<SelfEvent> {

  	/**
     *  类定义方式 只能针对于一个事件进行处理
     */
  
    @Override
    @Async
    public void onApplicationEvent(SelfEvent selfEvent) {
        HashMap<String, Object> source = (HashMap<String, Object>) selfEvent.getSource();

        System.out.println("类形式监听: {} " + source.toString());
    }

}
@Component
public class AnnotationEventListener {

    /**
     * 基于注解实现的监听 可以在一个监听类中实现对多个事件的监听 适合某一类业务
     * 比如: 记录日志信息, 有多种日志格式, 多个事件, 但是是同一类业务
     */
    
    @Async
    @EventListener(SelfEvent.class)
    // 事务监听, 使用该监听方式要注意失效问题(发送事件的动作必须在事务中,否则监听会失效)
    // @TransactionalEventListener(value = MdmMaterialInfoEvent.class, phase = TransactionPhase.AFTER_COMMIT)
    public void typeOne(SelfEvent event) {
        HashMap<String, Object> source = (HashMap<String, Object>) event.getSource();

        System.out.println("基于注解的监听 :{} " + source.toString());
    }

    // 可以根据 typeOne 进行对其他事件进行监听 建议根据业务分类:比如不同的日志可以用同一个监听类
    public void typeTwo() {
        return;
    }

}

4. 统一发送事件

定义统一发送事件类,相当于工厂,可以在里面进行一些拓展。

@Component
public class SelfEventPublisher {

    @Resource
    private ApplicationContext applicationContext;

    // 直接以 ApplicationContext 为入参 统一发布路径
    public void publish(ApplicationEvent applicationEvent) {
        applicationContext.publishEvent(applicationEvent);
    }

}

5. 测试
@RestController
@RequestMapping("/publishEvent")
public class PublishEventController {

    @Resource
    private SelfEventPublisher eventPublisher;

    @PostMapping("/classListener")
    public void classListener(@RequestParam Map<String, Object> params) {
        this.eventPublisher.publish(new SelfEvent(params));
    }

    @PostMapping("/annotationListener")
    public void annotationListener(Map<String, Object> params) {
        this.eventPublisher.publish(new SelfEvent(params));
    }

}


四、项目地址

https://github.com/lzhcccccch/Personal-Practice/tree/master/ApplicationContext-PublishEvent

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot 中,我们可以通过使用 ApplicationEventPublisher 接口的 publishEvent() 方法来发布事件。默认情况下,该方法是同步执行的,即事件发布后会等待所有监听器处理完事件后才会返回。 如果我们想要异步执行事件处理,可以使用 @Async 注解来实现。具体步骤如下: 1.在配置类上添加 @EnableAsync 注解启用异步执行。 2.在对应的事件监听器方法上添加 @Async 注解。 这样,当事件发布时,对应的监听器方法会在一个新线程中异步执行,从而不会阻塞主线程的执行。 示例代码如下: ```java @Configuration @EnableAsync public class AsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(100); executor.setQueueCapacity(10); executor.setThreadNamePrefix("AsyncThread-"); executor.initialize(); return executor; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new SimpleAsyncUncaughtExceptionHandler(); } } @Component public class MyEventListener { @Async @EventListener public void handleEvent(MyEvent event) { // 处理事件 } } @Component public class MyEventPublisher { @Autowired private ApplicationEventPublisher publisher; public void publishEvent(MyEvent event) { publisher.publishEvent(event); } } ``` 在上面的示例代码中,我们先定义了一个 AsyncConfig 配置类,通过实现 AsyncConfigurer 接口来配置线程池等参数。然后在 MyEventListener 类中,我们使用 @Async 注解来标识 handleEvent() 方法是一个异步方法。最后,在 MyEventPublisher 类中,我们调用 ApplicationEventPublisher 的 publishEvent() 方法来发布事件。 这样,当我们调用 MyEventPublisher 的 publishEvent() 方法时,MyEventListener 中对应的 handleEvent() 方法就会在一个新线程中异步执行,不会阻塞主线程的执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值