首页 > 其他分享 >Spring事件监听机制

Spring事件监听机制

时间:2023-08-07 19:45:54浏览次数:30  
标签:PayloadApplicationEvent Spring class public 事件 机制 dataSts 监听

背景

当我们的数据发生变化时,有很多别的业务逻辑需要去做,那么很适合使用事件监听来解耦合。比如目前做过的一个接口,会去修改指令的状态,修改完之后,需要调用持仓、额度等接口,那么每次有新增逻辑都需要来改我的这个接口,这很不方便,我完全可以修改完了之后,直接发布一个事件,让别的模块来监听这个事件,来完成他们的逻辑。

使用

使用起来非常简单,基本上就是定义一个event、listener即可。

当发布事件时,会遍历所有的Listener,挑出符合当前发布事件的Listener,然后执行Listener中的逻辑。

编写的Listener需要注册到Spring容器中。

第一步,声明一个事件

public class IstrnDataStsEvent extends ApplicationEvent {

    /**
     * 数据, 简单起见只使用一个状态
     */
    private final String dataSts;

    public IstrnDataStsEvent(Object source, String dataSts) {
        super(source);
        this.dataSts = dataSts;
    }

    public String getDataSts() {
        return dataSts;
    }
}

第二步,监听这个事件,执行自己的逻辑

/**
 * 持仓
 */
@Slf4j
@Component
public class PositionIstrnDataStsListener implements ApplicationListener<IstrnDataStsEvent> {

    @Override
    public void onApplicationEvent(IstrnDataStsEvent event) {
        log.info("position exec logic, dataSts: {}", event.getDataSts());
    }
}
/**
 * 额度
 */
@Slf4j
@Component
public class QuotaIstrnDataStsListener implements ApplicationListener<IstrnDataStsEvent> {

    @Override
    public void onApplicationEvent(IstrnDataStsEvent event) {
        log.info("quota exec logic, dataSts: {}", event.getDataSts());
    }
}

第三步,发布该事件

@Service
public class IstrnDataStsChangeService implements ApplicationContextAware {

    private ApplicationContext ac;

    public void changeDataSts(String dataSts) {
        ac.publishEvent(new IstrnDataStsEvent(this, dataSts));
    }

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        this.ac = applicationContext;
    }
}

异步执行

默认情况下,监听逻辑是同步顺序执行的,当然Spring也提供异步执行的方式。不过这需要自己注册一个ApplicationEventMulticaster,Spring就是使用该接口来注册监听以及发布事件的。

ApplicationEventMulticaster的创建在AbstractApplicationContext.refresh()方法中完成,里面会调用initApplicationEventMulticaster方法。

protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    // 从容器中获取
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        if (logger.isTraceEnabled()) {
            logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
        }
    }
    else {
        // 容器中没有,则自己创建
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                    "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
        }
    }
}

从初始方法可知,只需要我们自己创建一个SimpleApplicationEventMulticaster放到容器中,然后为它设置一个线程池。

@Configuration
public class EventConfig {

    /**
     * 注意bean的名称必须为这个
     */
    @Bean(name = AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)
    public ApplicationEventMulticaster applicationEventMulticaster(BeanFactory beanFactory) {
        SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        // 设置线程池, 用于异步执行监听逻辑(线程池参数视情况而定)
        eventMulticaster.setTaskExecutor(Executors.newFixedThreadPool(10));
        return eventMulticaster;
    }
}

通用事件PayloadApplicationEvent

该类声明了一个泛型,因此可以存任意类型的数据,不过我认为还是自己创建一个专门的事件比较好,这里简单提下,是因为Spring可以通过泛型来区分事件。举个例子

/**
 * 监听PayloadApplicationEvent<Integer>
 */
public class IntegerListener implements ApplicationListener<PayloadApplicationEvent<Integer>> {
    
    @Override
    public void onApplicationEvent(PayloadApplicationEvent<Integer> event) {
        
    }
}
/**
 * 监听PayloadApplicationEvent<String>
 */
public class StringListener implements ApplicationListener<PayloadApplicationEvent<String>> {

    @Override
    public void onApplicationEvent(PayloadApplicationEvent<String> event) {

    }
}
// 发布事件
ac.publishEvent(new PayloadApplicationEvent<>(this, "string"));

在该例子中,虽然Java中由于泛型擦除PayloadApplicationEvent<Integer>PayloadApplicationEvent<String>是同一个类,但是只会触发StringListener。因为Spring内部会去解析Listener的ResolvableType,并不是简单比较类型。

标签:PayloadApplicationEvent,Spring,class,public,事件,机制,dataSts,监听
From: https://www.cnblogs.com/wt20/p/17612538.html

相关文章

  • SpringSecurity5.7+最新案例 -- 授权 --
    一、前提书接上回SpringSecurity5.7+最新案例--用户名密码+验证码+记住我······本文继续处理SpringSecurity授权......目前由难->简,即自定义数据库授权,注解授权,config配置授权二、自定义授权0.数据准备SETNAMESutf8mb4;SETFOREIGN_KEY_CHECKS=0;----......
  • springboot的AOP整理总结
    aop是spring的两大功能模块之一,功能非常强大,为解耦提供了非常优秀的解决方案。现在就以springboot中aop的使用来了解一下aop。一:使用aop来完成全局请求日志处理pom文件如下:<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmln......
  • springboot中的缓存介绍
    前言Spring框架支持透明地向应用程序添加缓存对缓存进行管理,其管理缓存的核心是将缓存应用于操作数据的方法(包括增删查改等),从而减少操作数据的执行次数(主要是查询,直接从缓存中读取数据),同时不会对程序本身造成任何干扰。SpringBoot继承了Spring框架的缓存管理功能,通过使用@Enable......
  • springboot中redis作为缓存使用
    springboot中redis作为缓存使用springboot中的redis作为缓存使用application.yamlserver:port:8089#servlet:#context-path:/demoRedis1spring:redis:host:127.0.0.1port:6379password:pom文件<!--添加的依赖--><!--Redis......
  • Java Reflection机制 实现类的反射与动态调用
    JavaReflection机制实现类的反射与动态调用JavaReflection机制被广泛用于实现类的反射和动态调用,反射是指在运行时检查和操作类的能力。只需要一个类的名称或对象的引用,就可以获取类的信息,调用类的方法,创建对象实例等。JavaReflection机制实现类的反射与动态调用JavaRefle......
  • 易基因:RNA-BS揭示叶酸调控神经干细胞m5C修饰和mRNA翻译机制|科研速递
    大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。叶酸作为一种必需B族维生素,是一种具有重要生物学功能(包括DNA甲基化调控)的甲基供体。正常的神经发育和生理对细胞叶酸水平很敏感,而叶酸缺乏或过量都可能导致神经系统疾病。最近已有研究表明叶酸与哺乳动物线粒体中tRNA......
  • SpringBoot学习
    SpringBoot学习1.SpringBoot入门1.1SpringbootWeb项目pom.xml基本配置 <properties> <java.version>1.8</java.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot......
  • springboot集成seata1.5.2+nacos2.1.1
    一、前言Seata出现前,大部分公司使用的都是TCC或者MQ(RocketMq)等来解决分布式事务的问题,TCC代码编写复杂,每个业务均需要实现三个入口,侵入性强,RocketMQ保证的是最终一致性。二、环境准备1、nacos:(这里采用最新版本2.1.1)下载地址:https://github.com/alibaba/nacos/releases......
  • spring cloud gateway 配置动态路由
    在mysql建表存储路由信息DROPTABLEIFEXISTS`route`;CREATETABLE`route`(`id`varchar(255)CHARACTERSETutf8mb4COLLATEutf8mb4_0900_ai_ciNOTNULL,`uri`varchar(255)CHARACTERSETutf8mb4COLLATEutf8mb4_0900_ai_ciNULLDEFAULTNULL,`predicates`......
  • Linux 中的零拷贝机制
    目录Zero-Copy机制内存管理物理内存和虚拟内存物理内存虚拟内存页表(PageTable)Linux体系结构内核空间和用户空间为什么需要区分内核空间与用户空间内核空间和用户空间内核空间用户空间LinuxI/O读写方式I/O中断原理DMA缓存I/O(BufferedI/O)直接I/O内存映射mmpSendfileSend......