SPI 全稱爲 (Service Provider Interface) ,是JDK內置的一種服務提供發現機制。java
爲何須要SPI? mysql
咱們的現代系統愈來愈龐大,若是設計架構有問題,就可能牽一髮而動全身,在面向對象中咱們推薦基於接口編程,模塊之間基於接口編程,這樣的好處顯而易見,不在代碼中進行硬編碼,不一樣的實現者按照接口規範實現本身內部操做,而後在使用的時候再根據 SPI 的規範去獲取對應的服務提供者的服務實現。經過 SPI 服務加載機制進行服務的註冊和發現,能夠有效的避免在代碼中將服務提供者寫死。從而能夠基於接口編程,實現模塊間的解耦。git
SPI機制約定:github
1.在 META-INF/services/ 目錄中建立以接口全限定名命名的文件,該文件內容爲API具體實 現類的全限定名 sql
2.使用 ServiceLoader 類動態加載 META-INF 中的實現類 apache
3.如 SPI 的實現類爲 Jar 則須要放在主程序 ClassPath 中 編程
4.API 具體實現類必須有一個不帶參數的構造方法 bash
如圖:架構
如今已經被使用的案例: maven
示例Demo:
代碼
OrderService.java
package com.demo.spi.service;
public interface OrderService {
int getOrderCountById(int id);
}
複製代碼
CustomerOrderServiceImpl.java
package com.demo.spi.impl;
import com.demo.spi.service.OrderService;
public class CustomerOrderServiceImpl implements OrderService {
public int getOrderCountById(int id) {
System.out.println("cutomer order count is 10");
return 10;
}
}
複製代碼
AgencyOrderServiceImpl.java
package com.demo.spi.impl;
import com.demo.spi.service.OrderService;
public class AgencyOrderServiceImpl implements OrderService {
public int getOrderCountById(int id) {
System.out.println("agency order count is 20");
return 20;
}
}
複製代碼
META-INF下文件名:com.demo.spi.service.OrderService,文件內容:
com.demo.spi.impl.AgencyOrderServiceImpl
com.demo.spi.impl.CustomerOrderServiceImpl複製代碼
4.新建測試項目java project
代碼github地址:https://github.com/HuoMoreMore/demo-spi
運行main方法以前咱們須要將第一個項目進行打包 jar 依賴到第二個java 項目中來,完成以後點擊run,能夠看到打印出了,咱們在項目1 中的兩個serviceImpl方法的輸出,也就是說ServiceLoader 動態的經過jar中的配置找到了 項目1中的實現類而且把他記載到了內存中,咱們就能夠直接調用項目1中提供的兩個實現類,而且正確輸出。
若是有須要瞭解ServiceLoader源碼的朋友能夠參考:
https://www.jianshu.com/p/a6073e9f8cb4