• 如何实现业务解耦?spring中事件监听了解一下


    一、前言
    二、业务解耦之事件监听实战
            1.事件监听三大组件
             2.事件发布以及监听实战案例
             3.事件发布以及监听原理

    一、前言

        耦合这个词在平常的开发工作中应该不陌生,简单理解就是代码中各部分关联度过高。举一个大家都遇见过的经典耦合场景:用户注册成功之后需要进行发送短信通知或是邮件通知,用户注册逻辑与发送短信或是邮件通知逻辑放在一块就是一种耦合现象,如果短信或是邮件功能异常,整个用户注册功能就会异常,会带来不好的用户体验,另外的缺点是维护复杂,不便于拓展。将业务逻辑与功能性逻辑进行拆分开就是属于解耦。spring中IOC思想就是解耦的一种体现,毕竟在一个实现类中如果调用另一个实现类不用繁琐的创建对象,只需要把需要用到实现类进行注入就可以了,减少代码量的同时也便于后期的拓展与维护。本文主要解决的问题就是在平常的开发中,如何将业务代码与固定功能性代码进行剥离,就是如何实现业务解耦。本文介绍一种解耦的实现思路:spring事件监听实现解耦。

    二、业务解耦之事件监听实战

    1.事件监听三大组件

        关于事件监听大家都听过,现在重新认识一下事件监听的三个重要部分:
        1.1 事件源
        可以理解为事件类型。比如说我们将的发送邮件或是发送短信都算是一种事件类型,都可以叫做事件源。
        1.2 事件发布器
        事件发布器也可以称作事件发布者,主要作用是发布事件,一般用于业务逻辑完成之后进行事件发布。
        1.3 事件监听器
        主要作用就是监听是否有事件发布,如果有则执行对应的业务处理。
    三者之间的关系流程如下:在这里插入图片描述

    2.事件发布以及监听实战案例

        下面以预约课程成功之后需要发送消息提醒为例讲解一下如何利用监听器实现业务解耦。
        首先定义事件源,需要继承spring中事件的顶级父类,实现如下:

    public class NewsEvent extends ApplicationEvent {
    
    	// 消息发送具体内容
        private String newsInfo;
    
        public NewsEvent(String newsInfo) {
            super(newsInfo);
            this.newsInfo=newsInfo;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

        定义事件发布器,这里有两种实现方式,分别是使用实现ApplicationEventPublisherAware.java或是实现ApplicationContextAware.java.
        自定义事件发布器实现ApplicationEventPublisherAware.java接口:

    @Service
    @Slf4j
    public class TestServiceImpl implements TestService,ApplicationEventPublisherAware {
    
        private ApplicationEventPublisher applicationEventPublisher;
        @Override
        public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
            this.applicationEventPublisher=applicationEventPublisher;
        }
    
        @Override
        public void applyCourse() {
            log.info("课程预约成功");
    
            // 消息发送事件发布
            NewsEvent sendNewsEvent = new NewsEvent("课程预约成功发送消息事件");
            applicationEventPublisher.publishEvent(sendNewsEvent);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

        自定义事件发布器实现ApplicationContextAware .java接口:

    @Service
    @Slf4j
    public class TestServiceImpl implements TestService,ApplicationContextAware {
    
        private ApplicationContext applicationContext;
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext=applicationContext;
        }
    
        @Override
        public void applyCourse() {
            log.info("课程预约成功");
    
            // 消息发送事件发布
            NewsEvent sendNewsEvent = new NewsEvent("课程预约成功发送消息事件");
            applicationContext.publishEvent(sendNewsEvent);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

        最后定义事件监听器,实现方式也有两种,一种是实现ApplicationListener接口,实现逻辑如下:

    @Slf4j
    @Component
    public class NewsListener implements ApplicationListener<NewsEvent> {
    
        @Override
        public void onApplicationEvent(NewsEvent event) {
                log.info("消息监听器监听到消息,执行发送消息逻辑:"+event.getSource());
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

        另一种是使用@EventListener注解,使用方式是直接在方法上添加该注解即可,具体实现如下:

    @Slf4j
    @Component
    public class NewsListener  {
    
       @EventListener(NewsEvent.class)
       public void sendNews(){
           log.info("消息监听器监听到消息,执行发送消息逻辑");
       }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

        控制层实现逻辑:

    @RestController
    @RequestMapping("/test")
    public class TestController {
    
        @Autowired
        private TestServiceImpl testService;
    
        @PostMapping("/applyCourse")
        public ResultVo applyCourse(){
        	// 预约课程
            testService.applyCourse();
            return  ResultVoUtil.success();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

        约课课程接口发送成功之后实现结果显示:
    在这里插入图片描述

    3.事件发布以及监听原理
        凡事都讲究知其然知其所以然,对我们技术开发人员更是如此,思考几个问题。 事件发布者发送消息之后,监听器是如何立即接收到响应的呢?下面就从源码的角度看下执行原理: 实现类中执行发送事件逻辑,最终调用的是`AbstractApplicationContext`中的`publishEvent`,该方法的主要作用是将所给到的事件发送给所有的监听器.代码如下:
    protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    		Assert.notNull(event, "Event must not be null");
    
    		ApplicationEvent applicationEvent;
    		
    		// 省略部分代码
    
    		// 利用事件发布器进行发布事件
    		getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    
    		// 省略部分代码
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    继续看下事件发布的具体逻辑,SimpleApplicationEventMulticaster中的multicastEvent:

    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    		Executor executor = getTaskExecutor();
    		// 根据事件类型获取对应的事件监听器,根据是否配置线程池决定是异步多线程执行还是同步执行
    		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
    			if (executor != null) {
    				// 线程池异步执行
    				executor.execute(() -> invokeListener(listener, event));
    			}
    			else {
    				// 同步执行
    				invokeListener(listener, event);
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

        最终都是执行SimpleApplicationEventMulticasterdoInvokeListener,实现逻辑如下:

    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    
    	// 省略部分逻辑
    	listener.onApplicationEvent(event);
    	// 省略部分逻辑
    	
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

        看到这里应该很明确了,这里就说明了为什么自定义的监听器需要实现ApplicationListener接口.
        以上是实现业务解耦采用事件监听的处理方式并对实现原理做了必要的分析说明,看到如果感觉有收获欢迎点赞收藏,另外也可以在评论区留言说下其他的业务解耦处理方式.

  • 相关阅读:
    C Primer Plus(6) 中文版 第7章 C控制语句:分支和跳转 7.1 if语句
    MCU看门狗
    面试被问到了String相关的几道题,你能答上来吗?
    大模型prompt-文章生成
    javaweb 之 JDBC 详解
    【数据分享】2000-2020年人口栅格数据(全球/全国/省/市)
    干货分享:小技巧大用处之Bean管理类工厂多种实现方式
    scrollIntoView锚点跳转 超好用
    七夕送什么礼物最实用?贴心又实用的护眼台灯分享
    开发成本类似快递出入库寄收件成本多少
  • 原文地址:https://blog.csdn.net/weixin_43401380/article/details/127643348