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

简介: 耦合这个词在平常的开发工作中应该不陌生,简单理解就是代码中各部分关联度过高。

一、前言


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


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


1.事件监听三大组件

   关于事件监听大家都听过,现在重新认识一下事件监听的三个重要部分:

   1.1 事件源

   可以理解为事件类型。比如说我们将的发送邮件或是发送短信都算是一种事件类型,都可以叫做事件源。

   1.2 事件发布器

   事件发布器也可以称作事件发布者,主要作用是发布事件,一般用于业务逻辑完成之后进行事件发布。

   1.3 事件监听器

   主要作用就是监听是否有事件发布,如果有则执行对应的业务处理。

三者之间的关系流程如下:

bc651fcefa7eed8ee64b4b3a1cead88a_07775b8586c04a1ba647938187a173d9.png


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

   下面以预约课程成功之后需要发送消息提醒为例讲解一下如何利用监听器实现业务解耦。

   首先定义事件源,需要继承spring中事件的顶级父类,实现如下:


public class NewsEvent extends ApplicationEvent {
  // 消息发送具体内容
    private String newsInfo;
    public NewsEvent(String newsInfo) {
        super(newsInfo);
        this.newsInfo=newsInfo;
    }
}


   定义事件发布器,这里有两种实现方式,分别是使用实现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);
    }
}


   自定义事件发布器实现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);
    }
}


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


@Slf4j
@Component
public class NewsListener implements ApplicationListener<NewsEvent> {
    @Override
    public void onApplicationEvent(NewsEvent event) {
            log.info("消息监听器监听到消息,执行发送消息逻辑:"+event.getSource());
    }
}


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

@Slf4j
@Component
public class NewsListener  {
   @EventListener(NewsEvent.class)
   public void sendNews(){
       log.info("消息监听器监听到消息,执行发送消息逻辑");
   }
}


   控制层实现逻辑:

@RestController
@RequestMapping("/test")
public class TestController {
    @Autowired
    private TestServiceImpl testService;
    @PostMapping("/applyCourse")
    public ResultVo applyCourse(){
      // 预约课程
        testService.applyCourse();
        return  ResultVoUtil.success();
    }
}

约课课程接口发送成功之后实现结果显示:

1a39a9bb032885ee0d495b988aed4d86_0d09d6367e714c82992d37e3b3674089.png


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);
  // 省略部分代码
  }


继续看下事件发布的具体逻辑,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);
    }
  }
  }


   最终都是执行SimpleApplicationEventMulticaster中doInvokeListener,实现逻辑如下:

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
  // 省略部分逻辑
  listener.onApplicationEvent(event);
  // 省略部分逻辑
  }


   看到这里应该很明确了,这里就说明了为什么自定义的监听器需要实现ApplicationListener接口.

   以上是实现业务解耦采用事件监听的处理方式并对实现原理做了必要的分析说明,看到如果感觉有收获欢迎点赞收藏,另外也可以在评论区留言说下其他的业务解耦处理方式.


相关文章
|
3月前
|
消息中间件 Java 开发者
【颠覆想象】Spring Boot重构未来:解耦与隔离,打造坚不可摧的微服务帝国!
【8月更文挑战第29天】本文通过构建电子商务平台的具体案例,深入探讨了如何利用 Spring Boot 实现服务间的解耦与隔离。文章详细介绍了依赖注入、模块化设计及异步通信等关键技术,并提供了具体代码示例。通过依赖注入,对象间耦合得以降低;模块化设计使各功能域独立,降低系统复杂度;异步通信则利用消息队列提升系统吞吐量与响应速度。这些方法不仅优化了系统架构,还加快了开发进程。
67 0
|
5月前
|
Java 开发者 Spring
Spring Boot 实现解耦和隔离的技术指南
【6月更文挑战第13天】Spring Boot 作为一种流行的 Java 框架,通过其强大的依赖注入和配置管理功能,使得开发者可以轻松实现模块之间的解耦和隔离
87 3
|
1月前
|
Java Spring
Spring从入门到入土(解耦的实现过程)
这篇文章详细讲解了在Spring框架中实现解耦的多种方法,包括使用接口、配置文件、BeanFactory模式以及单例模式,旨在降低代码间的依赖关系,提高程序的可维护性和扩展性。
28 0
Spring从入门到入土(解耦的实现过程)
|
1月前
|
JSON 前端开发 Java
Spring Boot框架中的响应与分层解耦架构
在Spring Boot框架中,响应与分层解耦架构是两个核心概念,它们共同促进了应用程序的高效性、可维护性和可扩展性。
48 3
|
3月前
|
Java 开发者 Spring
Spring Boot大法好:解耦、隔离、异步,让代码‘活’起来,性能飙升的秘密武器!
【8月更文挑战第29天】解耦、隔离与异步是Spring Boot中的关键设计原则,能大幅提升软件的可维护性、扩展性和性能。本文通过示例代码详细探讨了这些原则的应用:依赖注入和面向接口编程实现解耦;模块化设计与配置文件实现隔离;`@Async`注解和`CompletableFuture`实现异步处理。综合运用这些原则,可以显著提升软件质量和性能,使系统更加健壮、灵活和高效。
36 0
|
6月前
|
XML Java 数据格式
[Spring 基础] 掌握Spring DI,轻松解耦你的应用
[Spring 基础] 掌握Spring DI,轻松解耦你的应用
|
设计模式 Java uml
彻底搞懂Spring状态机原理,实现订单与物流解耦
状态模式的UML类图如下图所示。
307 0
|
缓存 监控 Java
spring事件监听器应用场景
spring事件监听器应用场景
|
XML 人工智能 Java
Spring中基于xml的IOC解耦
Spring中基于xml的IOC解耦
|
SQL 人工智能 Java
Spring中使用工厂模式解耦详解
Spring中使用工厂模式解耦详解