最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java?Spring?事件監(jiān)聽詳情解析

 更新時間:2022年07月01日 09:44:18   作者:??下崗碼農(nóng)大飛????  
這篇文章主要介紹了Java?Spring?事件監(jiān)聽詳情解析,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下

前言

前段時間因為工作的需要用到Spring事件,翻翻文檔將功能實現(xiàn)了,但是存在少許理解不暢的地方,今天有空來梳理梳理。

需求背景

葉子同學(xué)在新入職公司,老大讓他實現(xiàn)登陸功能,葉子隨手寫完,上線無bug,一切安好

//登陸偽代碼
public void login(....){
    userLogin(....);
}

幾天之后,老大說為維護用戶的粘度,每天登陸送積分。葉子同學(xué),二話不說,一頓操作后,上線無bug,一切安好

//登陸偽代碼
public void login(....){
    //登陸
    userLogin(....);
    //送積分
    loginPoint(....)
}

又幾天后,老大說,為了客戶安全,每次異地登陸發(fā)送郵件。葉子同學(xué)稍微抱怨,看在錢份上又是一頓操作后,上線無bug, 一切安好

//登陸偽代碼
public void login(....){
    //登陸
    userLogin(....);
    //送積分
    loginPoint(....)
    //發(fā)送郵件
    sendEmail(....)
}

又又幾天后,老大說,部分客戶不用郵件,用短信。葉子同學(xué)壓著怒氣,看著銀行卡,又是一頓操作后,上線無bug, 一切安好

//登陸偽代碼
public void login(....){
    //登陸
    userLogin(....);
    //送積分
    loginPoint(....)
    //發(fā)送郵件
    sendEmail(....)
    //發(fā)短信
    sendSms(...)
}

又又又幾天后,老大還沒開口,葉子同學(xué)就忍無可忍啦,得加錢。老大哄了好久,說不改需求了。改bug,用戶抱怨登陸慢,有時還不成功。葉子二話不說,接手排查,查出問題啦

  • 1> 郵件發(fā)送耗時
  • 2>同步實現(xiàn),如果郵件發(fā)送超時,登陸會出異常

代碼改進:

//登陸偽代碼
public void login(....){
    //登陸
    userLogin(....);
 
    try{
        //送積分
        new Thread(()->loginPoint(....)).start();
    
        //發(fā)送郵件
        new Thread(()->sendEmail(....)).start();
 
        //發(fā)短信
        new Thread(()->sendSms(....)).start();
    }catch(Exception e){
       //異常處理
    }
}

問題解決,功能實現(xiàn),ok~

又又又又幾天之后,老大說,只需要實現(xiàn)登陸功能即可,其他都不要~

葉子同學(xué)一句臥槽,然后是一段含母非常高的國粹。

此時,問:如果你是葉子同學(xué),你有啥方案能優(yōu)雅應(yīng)對上面的需求變更呢?

一種優(yōu)雅方案:事件監(jiān)聽機制

事件概念

定義

事件監(jiān)聽機制:就是對一個事件(行為動作)進行監(jiān)聽,當外界觸發(fā)某事件時,監(jiān)聽程序馬上被捕獲該事件,并觸發(fā)相應(yīng)的響應(yīng),這過程稱之為事件監(jiān)聽機制。

組成

事件監(jiān)聽機制有3個核心組成部分:

  • 1>事件,標記某種行為動作,比如:鼠標點擊事件,鼠標移動事件等。
  • 2>事件源,被監(jiān)控的對象或組件,事件發(fā)生的地方。比如:點擊按鈕,觸發(fā)點擊事件,按鈕就是實現(xiàn)源。
  • 3>事件監(jiān)聽器,監(jiān)聽事件的操作類,一旦事件發(fā)生(被觸發(fā)),則執(zhí)行事件監(jiān)聽器預(yù)設(shè)的邏輯,進行事件響應(yīng)。

  • 1>定義事件,并綁定到事件源中
  • 2>定義事件監(jiān)聽器,監(jiān)聽事件源
  • 3>用戶某行為觸發(fā)事件
  • 4>事件監(jiān)聽器監(jiān)控到事件發(fā)送,執(zhí)行事件響應(yīng)邏輯。

以上面的登錄為例:

  • 事件源:login方法
  • 事件:用戶login行為
  • 事件監(jiān)聽器:此處沒有,需要額外定制,但是事件響應(yīng):送積分,發(fā)郵件,發(fā)短信。

事件實現(xiàn)

以登錄為例子實現(xiàn)事件監(jiān)聽機制

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>定義事件監(jiān)聽器

/**
 * 事件監(jiān)聽器
 * 作用:當監(jiān)控的事件發(fā)送時,執(zhí)行預(yù)設(shè)的邏輯
 */
public interface EventListener<E extends AbstractEvent> {
 
    /**
     * 預(yù)設(shè)邏輯方法
     * 事件被觸發(fā),馬上執(zhí)行
     */
    void onEvent(E event);
}

4>定制登陸事件監(jiān)聽器

積分監(jiān)聽器

/**
 * 加積分監(jiān)聽器器:
 * 當用戶登陸事件觸發(fā)后,馬上執(zhí)行
 */
public class PointsListener implements EventListener<LoginEvent> {
    public void onEvent(LoginEvent event) {
        System.out.println(event.getSource() + "發(fā)生后,執(zhí)行積分+1操作");
 
        System.out.println(Thread.currentThread().getName());
    }
}

短信監(jiān)聽器

/**
 * 加積分監(jiān)聽器器:
 * 當用戶登陸事件觸發(fā)后,馬上執(zhí)行
 */
public class SmsListener implements EventListener<LoginEvent> {
    public void onEvent(LoginEvent event) {
        System.out.println(event.getSource() + "發(fā)生后,執(zhí)行發(fā)送短信操作");
        System.out.println(Thread.currentThread().getName());
    }
}

郵件監(jiān)聽器

/**
 * 加積分監(jiān)聽器器:
 * 當用戶登陸事件觸發(fā)后,馬上執(zhí)行
 */
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() + "發(fā)生后,執(zhí)行發(fā)送郵件操作");
        System.out.println(Thread.currentThread().getName());
    }
}

5>定義事件廣播器

/**
 * 事件廣播器
 * 1>注冊事件監(jiān)聽器
 * 2>刪除事件監(jiān)聽器
 * 3>事件觸發(fā)時,廣播事件
 */
public interface EventMulticaster {
    //廣播事件
    void multicastEvent(AbstractEvent event);

    //注冊事件監(jiān)聽器
    void registListener(EventListener listener);

    //刪除事件監(jiān)聽器
    void removeListener(EventListener listener);
}

6>定制簡單的事件廣播器 

/**
 * 事件廣播器實現(xiàn)類
 * 作用:維護事件監(jiān)聽器
 */
public class SimpleEventMulticaster implements EventMulticaster {
    //key:事件字節(jié)碼對象, value:當前事件綁定的事件監(jiān)聽器
    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) {
        //獲取監(jiān)聽器綁定的事件
        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) {
        //獲取監(jiān)聽器綁定的事件
        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:注冊監(jiān)聽器
        //登陸事件上綁定3個監(jiān)聽器
        multicaster.registListener(new PointsListener());
        multicaster.registListener(new EmailListener());
        multicaster.registListener(new SmsListener());
    }
    //3:模擬登陸
    public static void login(){
        //4:用戶登陸成功觸發(fā)登陸事件
        System.out.println("用戶執(zhí)行登陸邏輯");
        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());
    }
}

時序圖

到此這篇關(guān)于Java Spring 事件監(jiān)聽詳情解析的文章就介紹到這了,更多相關(guān)Java 事件監(jiān)聽內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring如何動態(tài)自定義logback日志目錄詳解

    Spring如何動態(tài)自定義logback日志目錄詳解

    這篇文章主要給大家介紹了關(guān)于Spring如何動態(tài)自定義logback日志目錄的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-10-10
  • 詳述IntelliJ IDEA遠程調(diào)試Tomcat的方法(圖文)

    詳述IntelliJ IDEA遠程調(diào)試Tomcat的方法(圖文)

    本篇文章主要介紹了詳述IntelliJ IDEA遠程調(diào)試Tomcat的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • Java連接MongoDB的常用方法詳解

    Java連接MongoDB的常用方法詳解

    這篇文章主要為大家詳細介紹一下Java語言連接MongoDB的常用方法以及實現(xiàn)增刪改查功能的示例代碼,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-07-07
  • Spring中@Value注解的三種使用方式詳解

    Spring中@Value注解的三種使用方式詳解

    這篇文章主要介紹了Spring中@Value注解的三種使用方式詳解,文章通過示例代碼非常詳細地介紹,對于每個人的學(xué)習(xí)或工作都有一定的學(xué)習(xí)價值,需要的朋友可以參考下
    2023-08-08
  • Java程序的邏輯控制和方法詳解

    Java程序的邏輯控制和方法詳解

    這篇文章主要介紹了Java程序的邏輯控制和方法詳解,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • springboot 整合 seata的配置過程

    springboot 整合 seata的配置過程

    本文給大家介紹springboot 整合 seata的配置過程,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-08-08
  • spring cloud如何修復(fù)zuul跨域配置異常的問題

    spring cloud如何修復(fù)zuul跨域配置異常的問題

    最近的開發(fā)過程中,使用spring集成了spring-cloud-zuul,在配置zuul跨域的時候遇到了問題,下面這篇文章主要給大家介紹了關(guān)于spring cloud如何修復(fù)zuul跨域配置異常的問題,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-09-09
  • 淺談java中異步多線程超時導(dǎo)致的服務(wù)異常

    淺談java中異步多線程超時導(dǎo)致的服務(wù)異常

    下面小編就為大家?guī)硪黄獪\談java中異步多線程超時導(dǎo)致的服務(wù)異常。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06
  • Java實現(xiàn)JDBC向數(shù)據(jù)庫批量插入

    Java實現(xiàn)JDBC向數(shù)據(jù)庫批量插入

    在Java項目中可能會出現(xiàn)大量向數(shù)據(jù)庫中插入的情況,本文主要介紹了Java實現(xiàn)JDBC向數(shù)據(jù)庫批量插入,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • SpringBoot靜態(tài)視頻實時播放的實現(xiàn)代碼

    SpringBoot靜態(tài)視頻實時播放的實現(xiàn)代碼

    這篇文章主要介紹了SpringBoot靜態(tài)視頻實時播放的實現(xiàn)代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01

最新評論

雷州市| 河西区| 桦南县| 永年县| 吉安县| 龙泉市| 杭锦后旗| 怀化市| 郯城县| 贵州省| 柳州市| 丰台区| 四会市| 名山县| 梁山县| 灵台县| 锡林浩特市| 岱山县| 墨玉县| 桐柏县| 晋城| 潢川县| 西贡区| 伊宁县| 榆社县| 吉水县| 汝南县| 安西县| 尼木县| 苗栗市| 如东县| 武夷山市| 陇西县| 蒲城县| 淮滨县| 淳安县| 岑溪市| 万载县| 诸暨市| 洪洞县| 紫阳县|