软件编程
位置:首页>> 软件编程>> java编程>> Java Spring 事件监听详情解析

Java Spring 事件监听详情解析

作者:??下岗码农大飞????  发布时间:2021-06-05 00:02:08 

标签:Java,Spring,事件,监听

前言

前段时间因为工作的需要用到Spring事件,翻翻文档将功能实现了,但是存在少许理解不畅的地方,今天有空来梳理梳理。

需求背景

叶子同学在新入职公司,老大让他实现登陆功能,叶子随手写完,上线无bug,一切安好

//登陆伪代码
public void login(....){
   userLogin(....);
}

几天之后,老大说为维护用户的粘度,每天登陆送积分。叶子同学,二话不说,一顿操作后,上线无bug,一切安好

//登陆伪代码
public void login(....){
   //登陆
   userLogin(....);
   //送积分
   loginPoint(....)
}

又几天后,老大说,为了客户安全,每次异地登陆发送邮件。叶子同学稍微抱怨,看在钱份上又是一顿操作后,上线无bug, 一切安好

//登陆伪代码
public void login(....){
   //登陆
   userLogin(....);
   //送积分
   loginPoint(....)
   //发送邮件
   sendEmail(....)
}

又又几天后,老大说,部分客户不用邮件,用短信。叶子同学压着怒气,看着银行卡,又是一顿操作后,上线无bug, 一切安好

//登陆伪代码
public void login(....){
   //登陆
   userLogin(....);
   //送积分
   loginPoint(....)
   //发送邮件
   sendEmail(....)
   //发短信
   sendSms(...)
}

又又又几天后,老大还没开口,叶子同学就忍无可忍啦,得加钱。老大哄了好久,说不改需求了。改bug,用户抱怨登陆慢,有时还不成功。叶子二话不说,接手排查,查出问题啦

  • 1> 邮件发送耗时

  • 2>同步实现,如果邮件发送超时,登陆会出异常

代码改进:

//登陆伪代码
public void login(....){
   //登陆
   userLogin(....);

try{
       //送积分
       new Thread(()->loginPoint(....)).start();

//发送邮件
       new Thread(()->sendEmail(....)).start();

//发短信
       new Thread(()->sendSms(....)).start();
   }catch(Exception e){
      //异常处理
   }
}

问题解决,功能实现,ok~

又又又又几天之后,老大说,只需要实现登陆功能即可,其他都不要~

叶子同学一句 * ,然后是一段含母非常高的国粹。

此时,问:如果你是叶子同学,你有啥方案能优雅应对上面的需求变更呢?

一种优雅方案:事件监听机制

事件概念

定义

事件监听机制:就是对一个事件(行为动作)进行监听,当外界触发某事件时,监听程序马上被捕获该事件,并触发相应的响应,这过程称之为事件监听机制。

组成

事件监听机制有3个核心组成部分:

  • 1>事件,标记某种行为动作,比如:鼠标点击事件,鼠标移动事件等。

  • 2>事件源,被监控的对象或组件,事件发生的地方。比如:点击按钮,触发点击事件,按钮就是实现源。

  • 3>事件 * ,监听事件的操作类,一旦事件发生(被触发),则执行事件 * 预设的逻辑,进行事件响应。

Java Spring 事件监听详情解析

  • 1>定义事件,并绑定到事件源中

  • 2>定义事件 * ,监听事件源

  • 3>用户某行为触发事件

  • 4>事件 * 监控到事件发送,执行事件响应逻辑。

以上面的登录为例:

  • 事件源:login方法

  • 事件:用户login行为

  • 事件 * :此处没有,需要额外定制,但是事件响应:送积分,发邮件,发短信。

事件实现

以登录为例子实现事件监听机制

1>定义抽象事件

/**
* 抽象事件类
* 作用:定制事件逻辑
*/
public class AbstractEvent {
   //绑定的事件源
   private Object source;
   public AbstractEvent(Object source) {
       this.source = source;
   }
   public Object getSource() {
       return source;
   }
   public void setSource(Object source) {
       this.source = source;
   }
}

2>定制登陆事件


/**
* 登陆事件
*/
public class LoginEvent extends AbstractEvent{
   public LoginEvent(Object source) {
       super(source);
   }
}

3>定义事件 *

/**
* 事件 *
* 作用:当监控的事件发送时,执行预设的逻辑
*/
public interface EventListener<E extends AbstractEvent> {

/**
    * 预设逻辑方法
    * 事件被触发,马上执行
    */
   void onEvent(E event);
}

4>定制登陆事件 *

积分 *

/**
* 加积分 * 器:
* 当用户登陆事件触发后,马上执行
*/
public class PointsListener implements EventListener<LoginEvent> {
   public void onEvent(LoginEvent event) {
       System.out.println(event.getSource() + "发生后,执行积分+1操作");

System.out.println(Thread.currentThread().getName());
   }
}

短信 *

/**
* 加积分 * 器:
* 当用户登陆事件触发后,马上执行
*/
public class SmsListener implements EventListener<LoginEvent> {
   public void onEvent(LoginEvent event) {
       System.out.println(event.getSource() + "发生后,执行发送短信操作");
       System.out.println(Thread.currentThread().getName());
   }
}

邮件 *

/**
* 加积分 * 器:
* 当用户登陆事件触发后,马上执行
*/
public class EmailListener implements EventListener<LoginEvent> {
   public void onEvent(LoginEvent event) {
       try {
           //模拟10s延时
           Thread.sleep(10000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println(event.getSource() + "发生后,执行发送邮件操作");
       System.out.println(Thread.currentThread().getName());
   }
}

5>定义事件广播器

/**
* 事件广播器
* 1>注册事件 *
* 2>删除事件 *
* 3>事件触发时,广播事件
*/
public interface EventMulticaster {
   //广播事件
   void multicastEvent(AbstractEvent event);

//注册事件 *
   void registListener(EventListener listener);

//删除事件 *
   void removeListener(EventListener listener);
}

6>定制简单的事件广播器 

/**
* 事件广播器实现类
* 作用:维护事件 *
*/
public class SimpleEventMulticaster implements EventMulticaster {
   //key:事件字节码对象, value:当前事件绑定的事件 *
   private Map<Class<?>, List<EventListener>> map = new HashMap<Class<?>, List<EventListener>>();

public void multicastEvent(AbstractEvent event) {
       List<EventListener> eventListeners = map.get(event.getClass());
       if(eventListeners != null){
           ExecutorService executorService = Executors.newCachedThreadPool();
           for (EventListener eventListener : eventListeners) {
               //异步
               executorService.submit(()-> eventListener.onEvent(event));
               //同步
               //eventListener.onEvent(event);
           }
           executorService.shutdown();
       }
   }
   public void registListener(EventListener listener) {
       //获取 * 绑定的事件
       ParameterizedType getType  = (ParameterizedType)listener.getClass().getGenericInterfaces()[0];
       Type type = getType.getActualTypeArguments()[0];
       Class<?> clz = (Class<?>) type;

List<EventListener> listeners = map.get(clz);
       if(listeners == null){
           listeners = new ArrayList<EventListener>();
           map.put(clz, listeners);
       }
       listeners.add(listener);
   }
   public void removeListener(EventListener listener) {
       //获取 * 绑定的事件
       ParameterizedType getType  = (ParameterizedType)listener.getClass().getGenericInterfaces()[0];
       Type type = getType.getActualTypeArguments()[0];
       Class<?> clz = (Class<?>) type;

List<EventListener> listeners = map.get(clz);
       if(listener != null){
           listeners.remove(listener);
       }

}
}

7>综合测试

public class App {

//1:初始化事件广播器
   public static SimpleEventMulticaster multicaster = new SimpleEventMulticaster();
   static {
       //2:注册 *
       //登陆事件上绑定3个 *
       multicaster.registListener(new PointsListener());
       multicaster.registListener(new EmailListener());
       multicaster.registListener(new SmsListener());
   }
   //3:模拟登陆
   public static void login(){
       //4:用户登陆成功触发登陆事件
       System.out.println("用户执行登陆逻辑");
       System.out.println(Thread.currentThread().getName());
       //5:广播登陆事件
       multicaster.multicastEvent(new LoginEvent("用户登陆啦"));
       System.out.println("登陆成功.....");
   }
   public static void main(String[] args) {
       App.login();
       System.out.println(Thread.currentThread().getName());
   }
}

时序图

Java Spring 事件监听详情解析

来源:https://juejin.cn/post/7114669073320902669

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com