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

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

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

前言

前段時(shí)間因?yàn)楣ぷ鞯男枰玫絊pring事件,翻翻文檔將功能實(shí)現(xiàn)了,但是存在少許理解不暢的地方,今天有空來(lái)梳理梳理。

需求背景

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

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

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

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

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

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

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

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

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

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

代碼改進(jìn):

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

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

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

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

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

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

事件概念

定義

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

組成

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

  • 1>事件,標(biāo)記某種行為動(dòng)作,比如:鼠標(biāo)點(diǎn)擊事件,鼠標(biāo)移動(dòng)事件等。
  • 2>事件源,被監(jiān)控的對(duì)象或組件,事件發(fā)生的地方。比如:點(diǎn)擊按鈕,觸發(fā)點(diǎn)擊事件,按鈕就是實(shí)現(xiàn)源。
  • 3>事件監(jiān)聽器,監(jiān)聽事件的操作類,一旦事件發(fā)生(被觸發(fā)),則執(zhí)行事件監(jiān)聽器預(yù)設(shè)的邏輯,進(jìn)行事件響應(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ā)短信。

事件實(shí)現(xiàn)

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

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

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

積分監(jiān)聽器

/**
 * 加積分監(jiān)聽器器:
 * 當(dāng)用戶登陸事件觸發(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)聽器器:
 * 當(dāng)用戶登陸事件觸發(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)聽器器:
 * 當(dāng)用戶登陸事件觸發(fā)后,馬上執(zhí)行
 */
public class EmailListener implements EventListener<LoginEvent> {
    public void onEvent(LoginEvent event) {
        try {
            //模擬10s延時(shí)
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(event.getSource() + "發(fā)生后,執(zhí)行發(fā)送郵件操作");
        System.out.println(Thread.currentThread().getName());
    }
}

5>定義事件廣播器

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

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

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

6>定制簡(jiǎn)單的事件廣播器 

/**
 * 事件廣播器實(shí)現(xiàn)類
 * 作用:維護(hù)事件監(jiān)聽器
 */
public class SimpleEventMulticaster implements EventMulticaster {
    //key:事件字節(jié)碼對(duì)象, value:當(dāng)前事件綁定的事件監(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>綜合測(cè)試

public class App {
 
    //1:初始化事件廣播器
    public static SimpleEventMulticaster multicaster = new SimpleEventMulticaster();
    static {
        //2:注冊(cè)監(jiān)聽器
        //登陸事件上綁定3個(gè)監(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());
    }
}

時(shí)序圖

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

相關(guān)文章

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

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

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

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

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

    Java連接MongoDB的常用方法詳解

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

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

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

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

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

    springboot 整合 seata的配置過程

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

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

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

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

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

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

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

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

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

最新評(píng)論

美姑县| 台东县| 鸡东县| 双流县| 南宁市| 龙山县| 冀州市| 六盘水市| 吴忠市| 玉山县| 宜宾县| 临朐县| 湄潭县| 讷河市| 贵州省| 上虞市| 古蔺县| 新竹县| 明光市| 从化市| 永济市| 梓潼县| 林西县| 福鼎市| 永昌县| 常熟市| 枝江市| 南川市| 尼木县| 武乡县| 新干县| 金秀| 邓州市| 南昌县| 凤阳县| 望奎县| 宁阳县| 松阳县| 黑龙江省| 沙河市| 延边|