Java SPI及Demo

FangMoreMore發表於2019-02-15
首先交代下背景,何為Java SPI?

   SPI 全稱為 (Service Provider Interface) ,是JDK內建的一種服務提供發現機制。

為什麼需要SPI? 

     我們的現代系統越來越龐大,如果設計架構有問題,就可能牽一髮而動全身,在物件導向中我們推薦基於介面程式設計,模組之間基於介面程式設計,這樣的好處顯而易見,不在程式碼中進行硬編碼,不同的實現者按照介面規範實現自己內部操作,然後在使用的時候再根據 SPI 的規範去獲取對應的服務提供者的服務實現。通過 SPI 服務載入機制進行服務的註冊和發現,可以有效的避免在程式碼中將服務提供者寫死。從而可以基於介面程式設計,實現模組間的解耦。

SPI機制約定:

   1.在 META-INF/services/ 目錄中建立以介面全限定名命名的檔案,該檔案內容為API具體實     現類的全限定名 

   2.使用 ServiceLoader 類動態載入 META-INF 中的實現類 

   3.如 SPI 的實現類為 Jar 則需要放在主程式 ClassPath 中  

   4.API 具體實現類必須有一個不帶引數的構造方法  

  如圖:

Java SPI及Demo


 現在已經被使用的案例: 

  • common-logging Apache最早提供的日誌的門面介面。只有介面,沒有實現。具體方 案由各提供商實現, 發現日誌提供商是通過掃描 META- INF/services/org.apache.commons.logging.LogFactory配置檔案,通過讀取該文 件的內容 找到日誌提工商實現類。只要我們的日誌實現裡包含了這個檔案,並在檔案裡 制定LogFactory工廠介面的實現類即可。 
  • JDBC jdbc4.0以前, 開發人員還需要基於Class.forName("xxx")的方式來裝載驅動。 建立連線: DriverManage.getConnection()中,有Connection con = aDriver.driver.connect(url, info); driver成員變數,是java.sql.Driver介面,Java對外公開的一個載入驅動介面,Java並未實現,至於實現這個介面由各個Jdbc廠商去實現。 如MySQL,mysql-connector-java-5.1.38.jar包下面META-INF.services包下有個java.sql.Driver檔案開啟檔案有下面兩行 com.mysql.jdbc.Driver com.mysql.fabric.jdbc.FabricMySQLDriver     

示例Demo:

  1.     建立maven專案
  2.    目錄如下:
      Java SPI及Demo


  3. 程式碼
    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

Java SPI及Demo


程式碼github地址:https://github.com/HuoMoreMore/demo-spi

執行main方法之前我們需要將第一個專案進行打包 jar 依賴到第二個java 專案中來,完成之後點選run,可以看到列印出了,我們在專案1 中的兩個serviceImpl方法的輸出,也就是說ServiceLoader 動態的通過jar中的配置找到了 專案1中的實現類並且把他記載到了記憶體中,我們就可以直接呼叫專案1中提供的兩個實現類,並且正確輸出。

如果有需要了解ServiceLoader原始碼的朋友可以參考:

https://www.jianshu.com/p/a6073e9f8cb4



相關文章