欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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)了,但是存在少許理解不暢的地方,今天有空來梳理梳理。

需求背景

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

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

幾天之后,老大說為維護(hù)用戶的粘度,每天登陸送積分。葉子同學(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,用戶抱怨登陸慢,有時(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é)一句臥槽,然后是一段含母非常高的國粹。

此時(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>定制簡單的事件廣播器 

/**
 * 事件廣播器實(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)文章

  • Eclipse+Java+Swing+Mysql實(shí)現(xiàn)工資管理系統(tǒng)

    Eclipse+Java+Swing+Mysql實(shí)現(xiàn)工資管理系統(tǒng)

    這篇文章主要介紹了Eclipse+Java+Swing+Mysql實(shí)現(xiàn)工資管理系統(tǒng),對(duì)正在工作或者學(xué)習(xí)的你有一定的參考價(jià)值,需要的朋友可以參考一下
    2022-01-01
  • java求三個(gè)數(shù)的最大值的示例分享

    java求三個(gè)數(shù)的最大值的示例分享

    這篇文章主要介紹了java求三個(gè)數(shù)的最大值的示例分享,需要的朋友可以參考下
    2014-03-03
  • SpringBoot選擇自有bean優(yōu)先加載實(shí)現(xiàn)方法

    SpringBoot選擇自有bean優(yōu)先加載實(shí)現(xiàn)方法

    在一些需求中,可能存在某些場景,比如先加載自己的bean,然后自己的bean做一些DB操作,初始化配置問題,然后后面的bean基于這個(gè)配置文件,繼續(xù)做其他的業(yè)務(wù)邏輯。因此有了本文的這個(gè)題目
    2023-03-03
  • 你真的了解java單例模式了嗎?

    你真的了解java單例模式了嗎?

    這篇文章主要介紹了你真的了解java單例模式了嗎?實(shí)際上單例模式有著好幾個(gè)變種,并且多線程中涉及到線程安全問題,,需要的朋友可以參考下
    2019-06-06
  • Gradle環(huán)境下導(dǎo)出Swagger為PDF的步驟詳解

    Gradle環(huán)境下導(dǎo)出Swagger為PDF的步驟詳解

    這篇文章主要介紹了Gradle環(huán)境下導(dǎo)出Swagger為PDF的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • 簡單了解JAVA public class與class區(qū)別

    簡單了解JAVA public class與class區(qū)別

    這篇文章主要介紹了簡單了解JAVA public class與class區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • JVM的內(nèi)存回收及常見算法小結(jié)

    JVM的內(nèi)存回收及常見算法小結(jié)

    這篇文章主要介紹了JVM的內(nèi)存回收及常見算法,需要的朋友可以參考下
    2023-05-05
  • 使用IDEA創(chuàng)建SpringBoot項(xiàng)目的方法步驟

    使用IDEA創(chuàng)建SpringBoot項(xiàng)目的方法步驟

    這篇文章主要介紹了使用IDEA創(chuàng)建SpringBoot項(xiàng)目的方法步驟,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-05-05
  • java 實(shí)現(xiàn)KMP算法

    java 實(shí)現(xiàn)KMP算法

    這篇文章主要介紹了java 如何實(shí)現(xiàn)KMP算法,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下
    2020-12-12
  • SpringCloud超詳細(xì)講解微服務(wù)網(wǎng)關(guān)Zuul

    SpringCloud超詳細(xì)講解微服務(wù)網(wǎng)關(guān)Zuul

    這篇文章主要介紹了SpringCloud Zuul微服務(wù)網(wǎng)關(guān),負(fù)載均衡,熔斷和限流,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07

最新評(píng)論