<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
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方法,傳入介面便能獲得其實現類。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45