搜索
首页Javajava教程springboot事件监听器怎么使用

springboot事件监听器怎么使用

May 14, 2023 am 10:01 AM
springboot

引导案例

下面看一个简单的案例,

@Configuration
public class SelfBusiness {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SelfBusiness.class);
        context.getBean(MyService.class).doBusiness();
        context.close();
    }
    @Component
    static class MyService {
        private static final Logger logger = LoggerFactory.getLogger(MyService.class);
        @Autowired
        private ApplicationEventPublisher publisher;
        public void doBusiness (){
            logger.debug("主线业务");
            logger.debug("发送短信");
            logger.debug("发送邮件");
        }
    }

运行上面的代码,观察效果

springboot事件监听器怎么使用

结合输出结果,这这段代码要实现的逻辑是,在主线业务执行完成后,需要执行发短信,发邮件等操作,这样写也没毛病,但不够优雅,从后续的业务可扩展性上来讲,不够友好,如果后续主线业务执行完毕,还需再增加一个其他的审计操作,则需要新增代码逻辑,这就将主线业务和支线逻辑紧密的耦合了起来;

就是说,我们期待的效果是,主线业务根本不关心其他的业务操作,只需要完成自身的逻辑就ok了,这就需要使用到spring提供的事件监听器功能;

使用事件监听器改造过程

springboot(spring)的事件监听器使用主要有两种方式,通过实现ApplicationListener接口,另一个就是在类上添加 @EventListener 注解来实现,接下来将对这两种方式逐一说明;

一、通过实现ApplicationListener接口实现步骤

1、自定义一个事件类(对象),继承ApplicationEvent

 static class MyEvent extends ApplicationEvent {
        public MyEvent(Object source) {
            super(source);
        }
    }

可以这么理解,在代码中,可能有很多种类型的事件,不同的业务对应着不同的事件,对于某个具体的监听器来说,它只想监听A这种类型的事件;

2、自定义业务类实现ApplicationListener 接口

  
	@Data
    static class Params {
        private String id ;
        private String name;
        private String phone;
    }
	@Component
    static class SmsApplicationListener implements ApplicationListener<MyEvent> {
        private static final Logger logger = LoggerFactory.getLogger(SmsApplicationListener.class);
        @Override
        public void onApplicationEvent(MyEvent myEvent) {
            Object source = myEvent.getSource();
            try {
                Params params = objectMapper.readValue(source.toString(), Params.class);
                logger.debug("userId : {}",params.getId());
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            logger.debug("执行 sms 发短信业务");
        }
    }
    @Component
    static class EmailApplicationListener implements ApplicationListener<MyEvent> {
        private static final Logger logger = LoggerFactory.getLogger(SmsApplicationListener.class);
        @Override
        public void onApplicationEvent(MyEvent myEvent) {
            Object source = myEvent.getSource();
            logger.debug("执行 email 发邮件业务");
        }
    }

显然,这里的监听器要监听的事件类型,正是上面我们定义的MyEvent ,这样,当业务被触发的时候,就可以在onApplicationEvent中拿到传递过来的参数,从而执行发短信(发邮件)业务操作了

3、主线业务发布事件

@Component
    static class MyService {
        private static final Logger logger = LoggerFactory.getLogger(MyService.class);
        @Autowired
        private ApplicationEventPublisher publisher;
        public void doBusiness (){
            Params params = new Params();
            params.setId("001");
            params.setName("xiaoma");
            params.setPhone("133******");
            logger.debug("主线业务");
            try {
                publisher.publishEvent(new MyEvent(objectMapper.writeValueAsString(params)));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            //publisher.publishEvent(new MyEvent("MyService doBusiness()"));
            //logger.debug("发送短信");
            //logger.debug("发送邮件");
        }
    }

对主线业务来说,这时候就不再需要写发送短信或邮件逻辑了,只需要一个publisher将事件发布出去即可,如果需要传递参数,将参数一起传递过去

完整的代码

@Configuration
public class SelfBusiness {
    private static ObjectMapper objectMapper = new ObjectMapper();
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SelfBusiness.class);
        context.getBean(MyService.class).doBusiness();
        context.close();
    }
    @Data
    static class Params {
        private String id ;
        private String name;
        private String phone;
    }
    /**
     * 自定义事件对象
     */
    static class MyEvent extends ApplicationEvent {
        public MyEvent(Object source) {
            super(source);
        }
    }
    @Component
    static class MyService {
        private static final Logger logger = LoggerFactory.getLogger(MyService.class);
        @Autowired
        private ApplicationEventPublisher publisher;
        public void doBusiness (){
            Params params = new Params();
            params.setId("001");
            params.setName("xiaoma");
            params.setPhone("133******");
            logger.debug("主线业务");
            try {
                publisher.publishEvent(new MyEvent(objectMapper.writeValueAsString(params)));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            //publisher.publishEvent(new MyEvent("MyService doBusiness()"));
            //logger.debug("发送短信");
            //logger.debug("发送邮件");
        }
    }
    /**
     * 监听事件触发后要执行的业务
     */
    @Component
    static class SmsApplicationListener implements ApplicationListener {
        private static final Logger logger = LoggerFactory.getLogger(SmsApplicationListener.class);
        @Override
        public void onApplicationEvent(MyEvent myEvent) {
            Object source = myEvent.getSource();
            try {
                Params params = objectMapper.readValue(source.toString(), Params.class);
                logger.debug("userId : {}",params.getId());
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            logger.debug("执行 sms 发短信业务");
        }
    }
    @Component
    static class EmailApplicationListener implements ApplicationListener {
        private static final Logger logger = LoggerFactory.getLogger(SmsApplicationListener.class);
        @Override
        public void onApplicationEvent(MyEvent myEvent) {
            Object source = myEvent.getSource();
            logger.debug("执行 email 发邮件业务");
        }
    }
}

再次运行上面的代码,观察效果,可以看到,仍然能满足预期的效果

springboot事件监听器怎么使用

二、通过添加 @EventListener 注解来实现

这种方式不再需要实现ApplicationListener 接口,而是直接在监听类的方法上面添加 @EventListener注解即可,相对要简化了一些,下面直接贴出完整的代码

package com.congge.config;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Configuration
public class SelfBusiness2 {
    private static ObjectMapper objectMapper = new ObjectMapper();
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SelfBusiness2.class);
        context.getBean(MyService.class).doBusiness();
        context.close();
    }
    @Data
    static class Params {
        private String id ;
        private String name;
        private String phone;
    }
    /**
     * 自定义事件对象
     */
    static class MyEvent extends ApplicationEvent {
        public MyEvent(Object source) {
            super(source);
        }
    }
    @Component
    static class MyService {
        private static final Logger logger = LoggerFactory.getLogger(MyService.class);
        @Autowired
        private ApplicationEventPublisher publisher;
        public void doBusiness (){
            Params params = new Params();
            params.setId("001");
            params.setName("xiaoma");
            params.setPhone("133******");
            logger.debug("主线业务");
            try {
                publisher.publishEvent(new MyEvent(objectMapper.writeValueAsString(params)));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
    }
    @Component
    static class SmsListenerService {
        private static final Logger logger = LoggerFactory.getLogger(SmsListenerService.class);
        @EventListener
        public void smsListener(MyEvent myEvent){
            Object source = myEvent.getSource();
            try {
                SelfBusiness2.Params params = objectMapper.readValue(source.toString(), SelfBusiness2.Params.class);
                logger.debug("userId : {}",params.getId());
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            logger.debug("执行 sms 发短信业务");
        }
    }
    @Component
    static class EmailListenerService {
        private static final Logger logger = LoggerFactory.getLogger(EmailListenerService.class);
        @EventListener
        public void emailListener(MyEvent myEvent){
            Object source = myEvent.getSource();
            try {
                SelfBusiness2.Params params = objectMapper.readValue(source.toString(), SelfBusiness2.Params.class);
                logger.debug("userId : {}",params.getId());
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            logger.debug("执行 email 发邮件业务");
        }
    }
}

运行上面的代码,观察效果,同样可以达到预期的效果

springboot事件监听器怎么使用

三、使用异步

更进一步来说,为了提升主线业务的逻辑执行效率,我们希望发布事件的业务逻辑异步执行,这个该如何做呢?

翻阅源码可以知道,ApplicationEventPublisher 默认发布事件时候采用单线程同步发送,如果需要使用异步,需要自定义 ThreadPoolTaskExecutor ,以及SimpleApplicationEventMulticaster ,因此我们只需要覆盖一下这两个组件的bean即可,在上面的业务类中将下面的这两个bean添加进去;

@Bean
    public ThreadPoolTaskExecutor executor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        return executor;
    }
    @Bean
    public SimpleApplicationEventMulticaster applicationEventMulticaster(ThreadPoolTaskExecutor executor) {
        SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
        eventMulticaster.setTaskExecutor(executor);
        return eventMulticaster;
    }

这时候再次运行代码,反复运行多次,就可以看到效果

springboot事件监听器怎么使用

对比下上面单线程效果

springboot事件监听器怎么使用

以上是springboot事件监听器怎么使用的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:亿速云。如有侵权,请联系admin@php.cn删除
Java开发的哪些方面取决于平台?Java开发的哪些方面取决于平台?Apr 26, 2025 am 12:19 AM

JavadevelovermentIrelyPlatForm-DeTueTososeVeralFactors.1)JVMVariationsAffectPerformanceNandBehaviorAcroSsdifferentos.2)Nativelibrariesviajnijniiniininiinniinindrododerplatefform.3)

在不同平台上运行Java代码时是否存在性能差异?为什么?在不同平台上运行Java代码时是否存在性能差异?为什么?Apr 26, 2025 am 12:15 AM

Java代码在不同平台上运行时会有性能差异。1)JVM的实现和优化策略不同,如OracleJDK和OpenJDK。2)操作系统的特性,如内存管理和线程调度,也会影响性能。3)可以通过选择合适的JVM、调整JVM参数和代码优化来提升性能。

Java平台独立性有什么局限性?Java平台独立性有什么局限性?Apr 26, 2025 am 12:10 AM

Java'splatFormentenceHaslimitations不包括PerformanceOverhead,versionCompatibilityIsissues,挑战WithnativelibraryIntegration,Platform-SpecificFeatures,andjvminstallation/jvminstallation/jvmintenance/jeartenance.therefactorscomplicatorscomplicatethe“ writeOnce”

解释平台独立性和跨平台发展之间的差异。解释平台独立性和跨平台发展之间的差异。Apr 26, 2025 am 12:08 AM

PlatformIndependendecealLowsProgramStormonanyPlograwsStormanyPlatFormWithOutModification,而LileCross-PlatFormDevelopmentRequiredquiresMomePlatform-specificAdjustments.platFormIndependence,EneblesuniveByjava,EnablesuniversUniversAleversalexecutionbutmayCotutionButMayComproMisePerformance.cross.cross.cross-platformd

即时(JIT)汇编如何影响Java的性能和平台独立性?即时(JIT)汇编如何影响Java的性能和平台独立性?Apr 26, 2025 am 12:02 AM

JITcompilationinJavaenhancesperformancewhilemaintainingplatformindependence.1)Itdynamicallytranslatesbytecodeintonativemachinecodeatruntime,optimizingfrequentlyusedcode.2)TheJVMremainsplatform-independent,allowingthesameJavaapplicationtorunondifferen

为什么Java是开发跨平台桌面应用程序的流行选择?为什么Java是开发跨平台桌面应用程序的流行选择?Apr 25, 2025 am 12:23 AM

javaispopularforcross-platformdesktopapplicationsduetoits“ writeonce,runanywhere”哲学。1)itusesbytbytybytecebytecodethatrunsonanyjvm-platform.2)librarieslikeslikeslikeswingingandjavafxhelpcreatenative-lookingenative-lookinguisis.3)

讨论可能需要在Java中编写平台特定代码的情况。讨论可能需要在Java中编写平台特定代码的情况。Apr 25, 2025 am 12:22 AM

在Java中编写平台特定代码的原因包括访问特定操作系统功能、与特定硬件交互和优化性能。1)使用JNA或JNI访问Windows注册表;2)通过JNI与Linux特定硬件驱动程序交互;3)通过JNI使用Metal优化macOS上的游戏性能。尽管如此,编写平台特定代码会影响代码的可移植性、增加复杂性、可能带来性能开销和安全风险。

与平台独立性相关的Java开发的未来趋势是什么?与平台独立性相关的Java开发的未来趋势是什么?Apr 25, 2025 am 12:12 AM

Java将通过云原生应用、多平台部署和跨语言互操作进一步提升平台独立性。1)云原生应用将使用GraalVM和Quarkus提升启动速度。2)Java将扩展到嵌入式设备、移动设备和量子计算机。3)通过GraalVM,Java将与Python、JavaScript等语言无缝集成,增强跨语言互操作性。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具