您好,登錄后才能下訂單哦!
今天小編給大家分享一下怎么使用Spring特性實現接口多類的動態調用的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
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點有多種交通方式,每種交通方式的費用不同,可以根據乘客的需要進行選擇"(好吧,我承認這是個非常蹩腳的需求,但是可以聯想一下類似的需求,比如支付方式、快遞公司,在頁面提供幾個選項,業務代碼根據選項的不同選擇不同的實現類實例進行調用)。
回到我們的例子,按照這個交通方式的需求,我們的設計如下:有一個交通方式的接口,接口有兩個方式,一個查詢費用、一個查詢該交通方式的類型,同時,我們可以用一個枚舉類型類標識交通類型。
我們還需要一個工廠類來根據交通類型標識查找該交通類型的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同樣也能實現同樣的功能啊。首先說明一下,SPI是JDK自帶的功能,雖然歷史是比較久遠的了,但是不代表它不好,而且有些場景非SPI不可(比如JDBC)。
我們明確一下SPI是什么以及它的設計是用來做什么的。SPI的全名為Service Provider Interface(服務提供接口),因為這個是針對廠商或者插件的。比較經典的用法就是JDBC,java提供了標準的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; }
關于SPI我們點到為止,這里只是要說明SPI和我們前面例子中使用的AP具有不同的適用場景。
在前面的例子里,我們用的是什么呢?Spring的API,API的全稱為Application Programming Interface(應用程序編程接口),在一個應用內部,使用API是非常便捷的方式,也是最直接的方式。
總結一下,就是編程中,我們使用API是最多的。當然我們也會使用SPI(雖然我們不是嚴格意義上的廠商或者插件),使用SPI也是在特定場景下為了解決問題的一種途徑。
關于SPI更多的內容,以后在慢慢介紹吧。
【附】關于SPI的約定:當服務的提供者,提供了服務接口的一種實現之后,在jar包的META-INF/services/目錄里同時創建一個以服務接口命名的文件。
該文件里就是實現該服務接口的具體實現類。而當外部程序裝配這個模塊的時候,就能通過該jar包META-INF/services/里的配置文件找到具體的實現類名,并裝載實例化,完成模塊的注入。
基于這樣一個約定就能很好的找到服務接口的實現類,而不需要再代碼里制定。
jdk提供服務實現查找的一個工具類:java.util.ServiceLoader,通過其load方法,傳入接口便能獲得其實現類。
以上就是“怎么使用Spring特性實現接口多類的動態調用”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。