API/SPI可擴展設計原則(轉)

寫本篇主要是用來後面寫一篇可擴展性軟件設計打好基礎(苦於找不到一篇關於API/SPI的好文章,只好本身寫一個,歡迎指教)。 
概念: 
API:API(Application Programming Interface)表示應用程序編程接口 
SPI:SPI(Service Provider Interface)表示服務提供商接口 
API與SPI的關係 
框架提供API及其實現,框架在實現過程當中提供SPI回調機制。SPI是框架的擴展點。若是使用框架方要擴展框架,能夠本身實現SPI並注入框架,因而框架使用方其實也是一個服務提供商。 

SPI實現有兩種方式,一種是第三方提供實現,另外一種是應用自身本身提供實現 
看一下API/SPI關係圖1,第三方提供商實現了SPI,應用引入第三方提供商的第三方庫 

舉例 
java中JDBC是一個編程接口,而Driver是一個SPI,同時不一樣數據庫廠商會提供Driver的實現。應用中要使用JDBC編程接口時須要引入第三方數據庫廠商驅動包,第三方廠商提供的驅動包其實就是SPI的實現。 

看一下API/SPI關係圖1,應用自身爲了擴展框架本身實現了SPI,直接在本身的應用包裏實現SPI 

舉例 
我寫了一個RenderAPI用來渲染vm模板, 渲染邏輯過程當中會默認引入PullTool讓vm中能夠使用,如DateUtil,StringUtil等。應該可能想引入本身的業務PullTool,如MoneyTool等。因而我能夠在RenderAPI接口的實現裏,讀取PullToolFacotry這個SPI,從這個SPI返回的PullTool加入到渲染引擎裏。PullToolFacotry接口裏就一個方法public Map<String PullTool> getPullTools();應用端能夠寫個類叫BusinessPullToolFactoryImpl實現PullToolFactory,把本身想要加入的PullTool返回便可。 

框架如何發現SPI?
 
框架能夠使用java提供的java.util.ServiceLoader類獲得SPI的實現。 
如ServiceLoader<PullToolFactory> pullToolFactorys     = ServiceLoader.load(PullToolFactory.class); 

應用或第三方提供商如何注入SPI實現? 
應用或第三方包在jar包的META-INF/services/目錄裏同時建立一個以服務接口命名的文件。該文件裏就是實現該服務接口的具體實現類的徹底限定名。而當框架調用ServiceLoader.load(PullToolFactory.class),就能經過該jar包META-INF/services/裏的配置文件找到具體的實現類名,並裝載實例化,完成SPI實現的注入。 

總結:  能夠想象,使用SPI設計,框架能夠很容易引入擴展點,同時應用要擴展框架邏輯也很容易實現。框架可擴展設計能夠基於這個原則進行設計擴展點。 
相關文章
相關標籤/搜索