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

使用Spring特性實現接口多實現類的動態(tài)調用方式

 更新時間:2022年02月25日 11:52:20   作者:EmineWang  
這篇文章主要介紹了使用Spring特性實現接口多實現類的動態(tài)調用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

正好用到。mark一下背景

org.springframework.beans及org.springframework.context這兩個包是Spring IoC容器的基礎,其中重要的類有BeanFactory,BeanFactory是IoC容器的核心接口,其職責包括:實例化、定位、配置應用程序中的對象及建立這些對象間的依賴關系。

ApplicationContext作為BeanFactory的子類,在Bean管理的功能上得到了很大的增強,也更易于與Spring AOP集成使用。

今天我們要討論的并不是BeanFactory或者ApplicationContext的實現原理,而是對ApplicationContext的一種實際應用方式。

問題的提出

在實際工作中,我們經常會遇到一個接口及多個實現類的情況,并且在不同的條件下會使用不同的實現類。

從使用方式上看,有些類似SPI的用法,但是由于SPI的使用并不是太方便,那么怎么辦呢?我們可以借助ApplicationContext的getBeansOfType來實現我們需要的結果。

首先我們看一下這個方法的簽名

<T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException;

從上面的代碼上我們可以看出來這個方法能返回一個接口的全部實現類(前提是所有實現類都必須由Spring IoC容器管理)。

接下來看看我們遇到的問題是什么?

"假設從A點到B點有多種交通方式,每種交通方式的費用不同,可以根據乘客的需要進行選擇"(好吧,我承認這是個非常蹩腳的需求,但是可以聯想一下類似的需求,比如支付方式、快遞公司,在頁面提供幾個選項,業(yè)務代碼根據選項的不同選擇不同的實現類實例進行調用)。

實現

回到我們的例子,按照這個交通方式的需求,我們的設計如下:有一個交通方式的接口,接口有兩個方式,一個查詢費用、一個查詢該交通方式的類型,同時,我們可以用一個枚舉類型類標識交通類型。

我們還需要一個工廠類來根據交通類型標識查找該交通類型的Bean實例,從而使用該實例,獲得交通類型的詳細信息及該交通類型的操作。

代碼如下

接口:

/**
 * 交通方式
 */
public interface TrafficMode { 
    /**
     * 查詢交通方式編碼
     * @return 編碼
     */
    TrafficCode getCode();
 
    /**
     * 查詢交通方式的費用,單位:分
     * @return 費用
     */
    Integer getFee(); 
}

枚舉:

/**
 * 交通類型枚舉
 */
public enum TrafficCode { 
    TRAIN,
    BUS 
}

接口有兩個實現類:

/**
 * 汽車方式
 */
@Component
public class BusMode implements TrafficMode { 
    @Override
    public TrafficCode getCode() {
        return TrafficCode.BUS;
    }
 
    @Override
    public Integer getFee() {
        return 10000;
    } 
}
/**
 * 火車方式
 */
@Component
public class TrainMode implements TrafficMode { 
    @Override
    public TrafficCode getCode() {
        return TrafficCode.TRAIN;
    }
 
    @Override
    public Integer getFee() {
        return 9000;
    } 
}

工廠類:

/**
 * 交通方式工廠類
 */
@Component
public class TrafficModeFactory implements ApplicationContextAware { 
    private static Map<TrafficCode, TrafficMode> trafficBeanMap;
 
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, TrafficMode> map = applicationContext.getBeansOfType(TrafficMode.class);
        trafficBeanMap = new HashMap<>();
        map.forEach((key, value) -> trafficBeanMap.put(value.getCode(), value));
    }
 
    public static <T extends TrafficMode> T getTrafficMode(TrafficCode code) {
        return (T)trafficBeanMap.get(code);
    } 
}

驗證

有了上面的代碼之后,我們一起通過單元測試來看一下效果,單元測試代碼片段如下:

    @Test
    public void testGetTrafficMode() {
        TrafficMode mode = TrafficModeFactory.getTrafficMode(TrafficCode.BUS);
        Assert.assertEquals(mode.getFee().intValue(), 10000); 
        mode = TrafficModeFactory.getTrafficMode(TrafficCode.TRAIN);
        Assert.assertEquals(mode.getFee().intValue(), 9000);
    }

運行之后的結果呢?必然是通過。

關于SPI

文章到這里,有同學可能會問:這和SPI有什么區(qū)別呢?SPI同樣也能實現同樣的功能啊。首先說明一下,SPI是JDK自帶的功能,雖然歷史是比較久遠的了,但是不代表它不好,而且有些場景非SPI不可(比如JDBC)。

我們明確一下SPI是什么以及它的設計是用來做什么的。SPI的全名為Service Provider Interface(服務提供接口),因為這個是針對廠商或者插件的。比較經典的用法就是JDBC,java提供了標準的JDBC接口,每個數據庫廠商提供自己的數據庫驅動實現。

下面是JDBC驅動的接口

public interface Driver {
    Connection connect(String var1, Properties var2) throws SQLException; 
    boolean acceptsURL(String var1) throws SQLException; 
    DriverPropertyInfo[] getPropertyInfo(String var1, Properties var2) throws SQLException; 
    int getMajorVersion(); 
    int getMinorVersion(); 
    boolean jdbcCompliant(); 
    Logger getParentLogger() throws SQLFeatureNotSupportedException;
}

下面是MySQL的JDBC驅動實現的SPI配置

關于SPI我們點到為止,這里只是要說明SPI和我們前面例子中使用的AP具有不同的適用場景。

在前面的例子里,我們用的是什么呢?Spring的API,API的全稱為Application Programming Interface(應用程序編程接口),在一個應用內部,使用API是非常便捷的方式,也是最直接的方式。

總結一下,就是編程中,我們使用API是最多的。當然我們也會使用SPI(雖然我們不是嚴格意義上的廠商或者插件),使用SPI也是在特定場景下為了解決問題的一種途徑。

關于SPI更多的內容,以后在慢慢介紹吧。

【附】關于SPI的約定:當服務的提供者,提供了服務接口的一種實現之后,在jar包的META-INF/services/目錄里同時創(chuàng)建一個以服務接口命名的文件。

該文件里就是實現該服務接口的具體實現類。而當外部程序裝配這個模塊的時候,就能通過該jar包META-INF/services/里的配置文件找到具體的實現類名,并裝載實例化,完成模塊的注入。

基于這樣一個約定就能很好的找到服務接口的實現類,而不需要再代碼里制定。

jdk提供服務實現查找的一個工具類:java.util.ServiceLoader,通過其load方法,傳入接口便能獲得其實現類。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • 詳解JavaWeb過濾器 Filter問題解決

    詳解JavaWeb過濾器 Filter問題解決

    過濾器就是對事物進行過濾的,在Web中的過濾器,當然就是對請求進行過濾,我們使用過濾器,就可以對請求進行攔截,然后做相應的處理,實現許多特殊功能,今天主要給大家講解JavaWeb過濾器 Filter問題解決,感興趣的朋友一起看看吧
    2022-10-10
  • JAVA利用接口實現多繼承問題的代碼實操演示

    JAVA利用接口實現多繼承問題的代碼實操演示

    Java語言并不支持多繼承,這是由于多繼承會帶來許多復雜的問題,例如"菱形問題"等,下面這篇文章主要給大家介紹了關于JAVA利用接口實現多繼承問題的相關資料,需要的朋友可以參考下
    2024-03-03
  • Java Web基于Session的登錄實現方法

    Java Web基于Session的登錄實現方法

    這篇文章主要介紹了Java Web基于Session的登錄實現方法,涉及Java針對session的操作及表單提交與驗證技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-10-10
  • Java中的==使用方法詳解

    Java中的==使用方法詳解

    這篇文章主要介紹了Java中“==”的使用方法,,==可以使用在基本數據類型變量和引用數據類型變量中,equals()是方法,只能用于引用數據類型,需要的朋友可以參考下
    2022-09-09
  • Java設計模式之抽象工廠模式簡析

    Java設計模式之抽象工廠模式簡析

    這篇文章主要介紹了Java設計模式之抽象工廠模式簡析, 抽象工廠模式是工廠方法模式的升級版本,他用來創(chuàng)建一組相關或者相互依賴的對象,他與工廠方法模式的區(qū)別就在于,工廠方法模式針對的是一個產品等級結構,需要的朋友可以參考下
    2023-12-12
  • Java 并發(fā)編程學習筆記之核心理論基礎

    Java 并發(fā)編程學習筆記之核心理論基礎

    編寫優(yōu)質的并發(fā)代碼是一件難度極高的事情。Java語言從第一版本開始內置了對多線程的支持,這一點在當年是非常了不起的,但是當我們對并發(fā)編程有了更深刻的認識和更多的實踐后,實現并發(fā)編程就有了更多的方案和更好的選擇。本文是對并發(fā)編程的核心理論做了下小結
    2016-05-05
  • JAVA內存溢出解決方案圖解

    JAVA內存溢出解決方案圖解

    這篇文章主要介紹了JAVA內存溢出解決方案圖解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • java實現登錄驗證碼

    java實現登錄驗證碼

    這篇文章主要為大家詳細介紹了java實現登錄驗證碼,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • Java經典算法匯總之選擇排序(SelectionSort)

    Java經典算法匯總之選擇排序(SelectionSort)

    選擇排序也是比較簡單的一種排序方法,原理也比較容易理解,選擇排序在每次遍歷過程中只記錄下來最小的一個元素的下標,待全部比較結束之后,將最小的元素與未排序的那部分序列的最前面一個元素交換,這樣就降低了交換的次數,提高了排序效率。
    2016-04-04
  • Java線程池Executor用法詳解

    Java線程池Executor用法詳解

    本文主要為大家詳細介紹了Java線程池Executor的用法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08

最新評論