標籤:ges lsp 必須 ret asn number hack string util
一、SPI機制
這裡先說下SPI的一個概念,SPI英文為Service Provider Interface單從字面可以理解為Service提供者介面,正如從SPI的名字去理解SPI就是Service提供者介面;我對SPI的定義:提供給服務提供廠商與擴充架構功能的開發人員使用的介面。
在我們日常開發的時候都是對問題進行抽象成Api然後就提供各種Api的實現,這些Api的實現都是封裝與我們的Jar中或架構中的雖然當我們想要提供一種Api新實現時可以不修改原來代碼只需實現該Api就可以提供Api的新實現,但我們還是產生新Jar或架構(雖然可以通過在代碼裡掃描某個目錄已載入Api的新實現,但這不是Java的機制,只是hack方法),而通過Java SPI機制我們就可以在不修改Jar包或架構的時候為Api提供新實現。
很多架構都使用了java的SPI機制,如java.sql.Driver的SPI實現(mysql驅動、oracle驅動等)、common-logging的日誌介面實現、dubbo的擴充實現等等架構;
SPI機制的約定:
1) 在META-INF/services/目錄中建立以介面全限定名命名的檔案該檔案內容為Api具體實作類別的全限定名
2) 使用ServiceLoader類動態載入META-INF中的實作類別
3) 如SPI的實作類別為Jar則需要放在主程式classPath中
4) Api具體實作類別必須有一個不帶參數的構造方法
SPI機制結構圖
二、SPI機制樣本
執行個體結構圖
IOperation介面:
| 12345678 |
/** * Created by LX on 2015/3/8. */public interface IOperation { public int operation(int numberA, int numberB); } |
PlusOperationImpl實現:
| 123456789101112 |
import co.solinx.demo.api.IOperation; /** * Created by LX on 2015/3/8. */public class PlusOperationImpl implements IOperation { @Override public int operation(int numberA, int numberB) { return numberA + numberB; }} |
SPI介面的實作類別:DivisionOperationImpl
| 123456789101112 |
import co.solinx.demo.api.IOperation; /** * Created by LX on 2015/3/8. */public class DivisionOperationImpl implements IOperation { @Override public int operation(int numberA, int numberB) { return numberA / numberB; }} |
META-INF/Services目錄中的檔案:
檔案名稱:co.solinx.demo.api.IOperation,內容:co.solinx.demo.spi.DivisionOperationImpl
Main類:
| 1234567891011121314151617181920212223242526272829 |
import co.solinx.demo.api.IOperation;import co.solinx.demo.impl.PlusOperationImpl;import co.solinx.demo.spi.DivisionOperationImpl; import java.util.Iterator;import java.util.ServiceLoader; /** * Created by LX on 2015/3/8. */public class main { public static void main(String[] args) { IOperation plus = new PlusOperationImpl(); IOperation division = new DivisionOperationImpl(); System.out.println(plus.operation(5, 3)); System.out.println(division.operation(9, 3)); ServiceLoader<IOperation> operations = ServiceLoader.load(IOperation.class); Iterator<IOperation> operationIterator = operations.iterator(); System.out.println("classPath:"+System.getProperty("java.class.path")); while (operationIterator.hasNext()) { IOperation operation = operationIterator.next(); System.out.println(operation.operation(6, 3)); } }} |
運行結果:
如把SPI實現打包為jar需要把jar放在classpath目錄中,SPI jar包運行結果:
Java的SPI機制與簡單的樣本