Spring之event

一、背景

为什么大佬的代码总是那么容易扩展,无论未来产品的需求怎么变化,大佬的代码稍作修改即可满足;为什么我们的代码那么多的if else,每次改动都是刮骨疗伤似的变动。其实我们的代码需要做到的是低耦合、高内聚,每个方法只做一件事,每个类职责独立,今天给大家分享的Spring event就是一种低耦合神器。

假设有这么一个需求,当收到用户下单成功的请求之后,需要触发短信服务给用户推送一条下单成功的短信。这看起来很容易实现,你也许会这么设计:

@Service
public class OrderService {
    
    public void order() {
        System.out.println("下单成功");
        System.out.println("调用短信服务、推送短信给用户");
    }
}

这样确实简单粗暴的实现了产品需求,但是这样就将短信相关逻辑放在了订单逻辑中,之后不管是订单逻辑的修改还是通知逻辑的修改都要动这段代码,这违背了单一职责原则。如果在二期迭代中、产品觉得短信通知还不够,还需要调用微信服务通知用户,这时候你还会继续这样写吗?

@Service
public class OrderService {

    public void order() {
        System.out.println("下单成功");
        System.out.println("调用短信服务、推送短信给用户");
        System.out.println("调用微信服务、推送微信消息给用户");
    }
}

讲道理,这样确实能达到产品需求的效果,但是并不利于后续需求的扩展,如果我们最开始没有考虑好系统设计和架构模式,那么在需求迭代、流量暴增下,最后你开发的需求极有可能出现不可预期的事故。

二、Spring事件监听实现

Spring提供了事件机制,可以通过事件的定义、发布以及监听事件来实现一些自定义的逻辑。比如下单后推送短信、推送微信消息这个需求,我们可以先定义一个下单成功的消息,然后在下单成功后发布下单成功的消息出来,在消息监听器中去实现推送短信和微信消息的功能。这样就可以将不属于下单的逻辑解耦合出来,大大提升系统的可扩展性。

  • 项目基于Spring 4.3.12.RELEASE 版本,具体pom如下
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.12.RELEASE</version>
    </dependency>
    
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>
  • 采用自动扫描包、自动维护Spring Bean的形式
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.mright.spring.framework")
public class ApplicationConfiguration {

}
  • 首先定义下单成功的消息
import org.springframework.context.ApplicationEvent;

public class OrderEvent extends ApplicationEvent {

    public OrderEvent(Object source) {
        super(source);
    }
}
  • 在下单服务中发布消息出来

调用 ApplicationContext 的 publishEvent 方法

import com.mright.spring.framework.bean.OrderEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @Autowired
    private ApplicationContext applicationContext;

    public void order() {
        System.out.println("下单成功");
        applicationContext.publishEvent(new OrderEvent(this));
    }
}
  • 定义发送短信的事件监听器

事件监听器需要实现 ApplicationListener 接口,这样在每一次 publishEvent 发布事件的时候都会执行事件监听器

import com.mright.spring.framework.bean.OrderEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Service;

@Service
public class SmsService implements ApplicationListener<OrderEvent> {

    @Override
    public void onApplicationEvent(OrderEvent orderEvent) {
        System.out.println("发送短信消息给用户");
    }
}
  • 定义发送微信消息的事件监听器
import com.mright.spring.framework.bean.OrderEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Service;

@Service
public class WechatService implements ApplicationListener<OrderEvent> {

    @Override
    public void onApplicationEvent(OrderEvent orderEvent) {
        System.out.println("发送微信消息给用户");
    }
}
  • 单元测试验证
import com.mright.spring.framework.service.OrderService;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test1 {

    @Test
    public void test() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
        OrderService orderService = context.getBean(OrderService.class);
        orderService.order();
    }
}
  • 运行结果
下单成功
发送短信消息给用户
发送微信消息给用户

Process finished with exit code 0

如果此时需求变更为:下单成功后、推送短信和微信给用户、并且通知仓进行生产,那么我们只需要实现一个仓生产的监听器即可。

import com.mright.spring.framework.bean.OrderEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Service;

@Service
public class ProductionService implements ApplicationListener<OrderEvent> {
    @Override
    public void onApplicationEvent(OrderEvent orderEvent) {
        System.out.println("通知仓生产");
    }
}
  • 执行单元测试
下单成功
通知仓生产
发送短信消息给用户
发送微信消息给用户

Process finished with exit code 0

实际上这种监听器模式是同步执行的,下单服务需要等待短信服务微信服务仓服务都执行完成才算结束。这时候我们可能有两个相对立的诉求,如果实际场景要求同步执行,那么是否要指定执行顺序;如果实际场景不要求同步执行,那么应该怎么实现异步多线程执行,以此提升执行效率

首先针对第一个诉求,我们可以通过指定Spring bean的加载顺序来实现。比如最后一个通知仓的监听器,我们可以这样改造,只需要一行即可:

import com.mright.spring.framework.bean.OrderEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Service;

@Service
@Order(0)
public class ProductionService implements ApplicationListener<OrderEvent> {
    @Override
    public void onApplicationEvent(OrderEvent orderEvent) {
        System.out.println("通知仓生产");
    }
}

@Order(0)数字从0开始,数字越小越先执行,以此保证执行顺序。

关于第二个诉求,我们可以改写下系统默认的多播器,只要我们的多播器支持多线程即可。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.task.SimpleAsyncTaskExecutor;

@Configuration
public class AsyncEventConfig {

    @Bean(name = "applicationEventMulticaster")
    public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
        SimpleApplicationEventMulticaster eventMulticaster
                = new SimpleApplicationEventMulticaster();

        eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
        return eventMulticaster;
    }
}

这种设计实际上是使用到了观察者模式,具备高内聚、低耦合的优点,在需求变更的情况下这种设计模式非常容易扩展。

在这里插入图片描述

三、源码分析

四、总结

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值