Java的SPI機制淺析與簡單示例


一、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接口:

[html]  view plain  copy
 
  1. package org.nercita.ltxx.spiTest;  
  2. /**  
  3.  * this is a Interface for two data   
  4.  * @author zhangwenchao  
  5.  *  
  6.  */  
  7. public interface IOperation {  
  8.      public int operation(int numberA, int numberB);  
  9. }  

SPI接口的實現類:PlusOperationImpl

[html]  view plain  copy
 
  1. package org.nercita.ltxx.spiTest;  
  2.   
  3. public class PlusOperationImpl implements IOperation {  
  4.     public int operation(int numberA, int numberB) {  
  5.   
  6.         return numberA + numberB;  
  7.   
  8.     }  
  9.   
  10. }  

SPI接口的實現類:DivisionOperationImpl

[html]  view plain  copy
 
  1. package org.nercita.ltxx.spiTest;  
  2.   
  3. public class DivisionOperationImpl implements IOperation{  
  4.     public int operation(int numberA, int numberB) {  
  5.   
  6.         return numberA / numberB;  
  7.   
  8.     }  
  9. }  

META-INF/Services目錄中的文件:

文件名:org.nercita.ltxx.spiTest.IOperation

內容:

       org.nercita.ltxx.spiTest.DivisionOperationImpl
       org.nercita.ltxx.spiTest.PlusOperationImpl

 

測試工程引入上述jar包,測試Main類如下:

[html]  view plain  copy
 
  1. package org.nercita.itxx.spiClient;  
  2.   
  3. import java.util.Iterator;  
  4. import java.util.ServiceLoader;  
  5.   
  6. import org.nercita.ltxx.spiTest.DivisionOperationImpl;  
  7. import org.nercita.ltxx.spiTest.IOperation;  
  8. import org.nercita.ltxx.spiTest.PlusOperationImpl;  
  9.   
  10. public class Main {  
  11.       
  12.     public static void main(String[] args) {  
  13.         IOperation plus = new PlusOperationImpl();  
  14.   
  15.         IOperation division = new DivisionOperationImpl();  
  16.   
  17.         System.out.println(plus.operation(6, 3));  
  18.   
  19.         System.out.println(division.operation(6, 3));  
  20.   
  21.         ServiceLoader<IOperationoperations = ServiceLoader.load(IOperation.class);  
  22.   
  23.         Iterator<IOperationoperationIterator = operations.iterator();  
  24.   
  25.         System.out.println("classPath:"+System.getProperty("java.class.path"));  
  26.   
  27.         while (operationIterator.hasNext()) {  
  28.   
  29.             IOperation operation = operationIterator.next();  
  30.   
  31.             System.out.println(operation.operation(6, 3));  
  32.   
  33.         }  
  34.     }  
  35.   
  36. }  

運行結果:

9
2
classPath:D:\Workspaces\projects\spiClient\bin;D:\Workspaces\projects\spiClient\lib\spiTest-0.0.1-SNAPSHOT.jar
2
9


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM