从spring框架中的事件驱动模型出发,优化实际应用开发代码

一、事件起源

  相信很多人在使用spring框架进行开发时,都会遇到这样的需求:在spring启动后,立即加载部分资源(例如:spring启动后立刻加载资源初始化到redis中)。当我去解决这个问题时发现,springboot启动过程中会有事件驱动模型的具体实现,共有两种实现:

  1)第一种实现,具体代码如下:

import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component  //将监听者交由spring管理
public class StartedListener implements ApplicationListener<ApplicationStartedEvent> {
  //实现了ApplicationListener接口并监听ApplicationStartedEvent事件 覆盖当事件发生的方法 @Override public void onApplicationEvent(ApplicationStartedEvent applicationStartedEvent) { System.out.println("i am started is ready ...");//只需改为调用具体的业务方法即可 } }

  2)第二种实现,具体代码如下:

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component  //将监听者交由spring管理
public class CommandListener implements CommandLineRunner {
  //实现了CommandLineRunner接口并覆盖run()方法 @Override public void run(String... args) throws Exception { System.out.println("i am commandline runner is ready ...");//将输出改为调用具体的业务方法即可 } }

  第一种和第二种之间存在联系,稍后会介绍两者之间的联系和区别,我们更加直观的可以看到第一种方法中的具体实现。

  发现,1、只需要实现ApplicationListener这个接口,2、并声明泛型-监听的具体事件,3、然后覆盖onApplicationEvent()方法三步走战略即可。

  还发现一个优势:如果一个将一个具体业务形象化为一个“事件”,例如:用户注册或者是用户下订单,这种具体的业务如果改造成事件的话,就可以实现解耦,方便以后添加用户注册或者下订单后的操作,举个栗子:

  买家用户下订单 -> 1、扣去商品表中的库存数量 -> 2、短信通知买家用户下单成功 -> 3、通知商家用户物流发货 -> 4、微信通知买家下单成功 等 后续操作

  如果现在,我们需要对该业务代码进行变化,我们需要增加一个需求变化:需要在买家用户下订单成功后,给买家用户进行:小程序通知,当你面对这个需求时,很直观的感觉应该是去直接在具体的业务代码下,加上一个小程序通知即可,可是忽略了之前可能有对应的逻辑操作,这个时候可能还需要花费一些时间,把之前的代码给看清楚,避免自己维护代码时出现问题。

  这个时候如果我们直接去用事件驱动模型这种方?#21073;此?#32771;我们的业务,完全可?#22253;?#20080;家用户下订单这个作为一个事件存在,这样其他的操作就是并行的操作,可以独立存在,如果需要直接添加就可以了。

 

  我们先来看一下原来未改造之前的代码:

import com.shuwen.demo.service.OrderService;
import org.springframework.stereotype.Service;

@Service
public class OrderServiceImpl2 implements OrderService {
    
    @Override
    public void saveOder() {
        //1、创建订单
        System.out.println("订单创建成功");
        //2、发送短信通知
        System.out.println("用户您好,恭喜您抢购成功~来自短信");
        //3、发送微信通知
        System.out.println("用户您好,恭喜您抢购成功~来自微信");
        //4、发送小程序通知
        System.out.println("用户您好,恭喜您抢购成功~来自小程序");
    }
}

 

  再来对比一下改造之后的代码:

    a)首先声明一个事件:OrderCreateEvent

import org.springframework.context.ApplicationEvent;
//继承ApplicationEvent即可
public class OrderCreateEvent extends ApplicationEvent {
   //默认覆盖 
  public OrderCreateEvent(Object source) { super(source); } }

      b)当买家下订单成功后,就需要创建并发布一个事件

import com.shuwen.demo.event.OrderCreateEvent;
import com.shuwen.demo.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    ApplicationContext applicationContext;
    @Override
    public void saveOder() {
        //1、创建订单
        System.out.println("订单创建成功");
        //创建订单创建的事件
        OrderCreateEvent orderCreateEvent = new OrderCreateEvent("order create is success");
        //利用applicationContext将事件发布
        applicationContext.publishEvent(orderCreateEvent);
        //2、发送短信通知
        //3、发送微信通知
        //4、发送小程序通知
    }
}

    c)我们就可以模仿spring进行监听事件发生,然后完成后续操作

      1、进行短信通知

import com.shuwen.demo.event.OrderCreateEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component  //交给spring管理 实现接口并监听事件源
public class MessageListener implements ApplicationListener<OrderCreateEvent> {
    @Async  //可以异步执行
    @Override  //覆盖方法 即可实现具体的业务操作
    public void onApplicationEvent(OrderCreateEvent orderCreateEvent) {
        System.out.println(orderCreateEvent.getSource()+",message is sending");
    }
}

      2、进行微信通知

import com.shuwen.demo.event.OrderCreateEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class WeixinListener implements ApplicationListener<OrderCreateEvent> {
    @Async
    @Override
    public void onApplicationEvent(OrderCreateEvent orderCreateEvent) {
        System.out.println(orderCreateEvent.getSource()+",weixin is sending");
    }
}

      3、这时候如果新需求是增加:小程序通知,我们直接添加一个监听者 即可。

import com.shuwen.demo.event.OrderCreateEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class LittleProListener implements ApplicationListener<OrderCreateEvent> {
    @Async
    @Override
    public void onApplicationEvent(OrderCreateEvent orderCreateEvent) {
        System.out.println(orderCreateEvent.getSource()+",xiao cheng xu is sending ...");
    }
}

  能够写出这样代码的人,你要珍惜他,因为当你维护他的项目时,很轻松,不用担心出现问题,也不必费时看原来的逻辑。

  这时候,可能就有人有这样的问题,这如果存在逻辑顺序怎?#21019;?#29702;这个问题呢?

  如果存在这种逻辑顺序,我们又该如?#26410;?#29702;,spring自然给我们提供了方法,哈哈,这就是spring的魅力~

  它的名字很有意思:SmartApplicationListener  smart是不是一下就聪明、伶俐了很多~

  我们先看?#27492;?#26159;如何实现具体的业务的,方便大家更好的理解:

    a)微信通知

import com.shuwen.demo.event.OrderCreateEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;

@Component  //实现smart接口
public class SmsListener implements SmartApplicationListener {
    @Override  //声明支持的事件类型
    public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
        return aClass == OrderCreateEvent.class;
    }

    @Override  //?#38382;?#30340;类型
    public boolean supportsSourceType(Class<?> sourceType) {
        return sourceType == String.class;
    }
    //order 确定优先级的顺序 数值越小 优先?#23545;?#39640;
    @Override  //优先级数值
    public int getOrder() {
        return 5;
    }

    @Override  //具体的业务实现
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        System.out.println(applicationEvent.getSource()+",sms is sending smart");
    }
}

    b)微信通知

import com.shuwen.demo.event.OrderCreateEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Async
@Component  //实现smart接口
public class WeixinListenerSmart implements SmartApplicationListener {
    @Override  //声明支持的事件类型
    public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
        return aClass == OrderCreateEvent.class;
    }

    @Override  //声明支持的?#38382;?#31867;型
    public boolean supportsSourceType(Class<?> sourceType) {
        return sourceType == String.class;
    }

    @Override  //声明优先级的大小 越小越高
    public int getOrder() {
        return 2;
    }

    @Override  //覆盖方法 实现具体的业务方法
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        System.out.println(applicationEvent.getSource()+",weixin is sending smart");
    }
}

    c)小程序通知

import com.shuwen.demo.event.OrderCreateEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;

@Component  //实现smart接口
public class LittleProListenerSmart implements SmartApplicationListener {
    @Override  //声明支持的事件类型
    public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
        return aClass == OrderCreateEvent.class;
    }

    @Override  //声明支持的?#38382;?#31867;型
    public boolean supportsSourceType(Class<?> sourceType) {
        return sourceType == String.class;
    }

    @Override  //声明该监听者的优先级
    public int getOrder() {
        return 6;
    }

    @Override  //具体的业务实现
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        System.out.println(applicationEvent.getSource()+",xiao cheng xu is sending smart");
    }
}

  大家一定要记?#20204;?#26970;哟,order值越小,优先?#23545;?#39640;。

  那么下面,我们要去追根溯源一下,看看spring的事件驱动模式的具体实现及相关的原理,让我们有一个更加深入的理解。

  二、spring提供的事件驱动模型/观察者抽象

  我们首先需要了解一下spring的体?#21040;?#26500;图:

    1)事件的具体代表者是: ApplicationEvent,其继承自JDK的EventObject,JDK要求所有事件将继承它,并通过source得到事件源;
    系统默认提供了如下ApplicationEvent事件实现:
    
    只有一个ApplicationContextEvent,表示ApplicationContext容器事件,且其又有如下实现:
      a)ContextStartedEvent:ApplicationContext启动后触发的事件;(目前版本没有任何作用)
      b)ContextStoppedEvent:ApplicationContext停止后触发的事件;(目前版本没有任何作用)
      c)ContextRefreshedEvent:ApplicationContext初始化或刷新完成后触发的事件;(容器初始化完成后调用)
      d)ContextClosedEvent:ApplicationContext关闭后触发的事件;(如web容器关闭时自动会触发spring容器的关闭,如果是普通java应用,需要调用ctx.registerShutdownHook();注册虚拟机关闭时的钩子才行)
      注:org.springframework.context.support.AbstractApplicationContext抽象类实现了LifeCycle的start和stop回调并发布ContextStartedEvent和ContextStoppedEvent事件;但是无任何实现调用它,所?#38405;?#21069;无任何作用。
    2)事件发布者,具体代表者: ApplicationEventPublisher及ApplicationEventMulticaster,
    系统默认提供了如下实现:
      a) ApplicationContext接口继承了ApplicationEventPublisher,并在AbstractApplicationContext实现了具体代码,实际执行是委托给ApplicationEventMulticaster(可以认为是多播):
 public void publishEvent(ApplicationEvent event) {
        //省略部分代码
        }
        getApplicationEventMulticaster().multicastEvent(event);
        if (this.parent != null) {
            this.parent.publishEvent(event);
        }
}

     我们常用的ApplicationContext都继承自AbstractApplicationContext,如ClassPathXmlApplicationContext、XmlWebApplicationContext等。所以自动拥有这个功能。

      b) ApplicationContext自动到本地容器里找一个名字为”“的ApplicationEventMulticaster实现,如果没有自己new一个SimpleApplicationEventMulticaster。其中SimpleApplicationEventMulticaster发布事件的代码如下:

public void multicastEvent(final ApplicationEvent event) {
        for (final ApplicationListener listener : getApplicationListeners(event)) {
            Executor executor = getTaskExecutor();
            if (executor != null) {
                executor.execute(new Runnable() {
                    public void run() {
                        listener.onApplicationEvent(event);
                    }
                });
            }
            else {
                listener.onApplicationEvent(event);
            }
        }
}

   大家可以看到如果给它一个executor(java.util.concurrent.Executor),它就可以异步支持发布事件了。否则就是通过发送。

   所以我们发送事件只需要通过ApplicationContext.publishEvent即可,没必要再创建自己的实现了。除非有必要。

  3)监听者,具体实现者: ApplicationListener, 其继承自JDK的EventListener,JDK要求所有监听器将继承它;

 ApplicationListener接口:

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E event);
}

   其只提供了onApplicationEvent方法,我们需要在该方法实现内部判断事件类型来处理,也没有提供?#27492;?#24207;触发监听器的语义,所以Spring提供了另一个接口,SmartApplicationListener:

public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
   //支持的事件类型 
  boolean supportsEventType(Class<? extends ApplicationEvent> var1);   //支持的?#38382;?#31867;型 default boolean supportsSourceType(@Nullable Class<?> sourceType) { return true; }   //优先级的大小 default int getOrder() { return 2147483647; } }

  时光匆匆不留人,望你我皆有所收获。

posted @ 2019-04-24 10:46 _小西瓜 阅读(...) 评论(...) 编辑 收藏
耐克篮球多少钱