JavaSE(十五)架構與思想

SPI與服務發現機制

SPI

  SPI(Service Provider Interface)即服務提供者接口,是用來對服務的提供者進行規範的接口。API與SPI都是對外提供的具有某些功能的接口,提供API的目的是讓外界能夠使用這些功能,提供SPI的目的是讓外界去實現這些功能對於不同的使用者,相同的接口可能體現爲不同的意義(API或者SPI),比如在WEB編程中,會創建一個Service接口,還會創建其實現類ServiceImpl類,此時Service接口體現爲一個SPI,當其他地方需要使用該Service接口時,這時Service接口體現爲一個API。

服務發現機制

  通過服務發現機制能夠將SPI與其實現進行分離以達到解耦的目的,從而大幅度提升程序的可擴展性。服務發現機制在Java中有比較廣泛的應用,比如JDBC模塊。JDBC模塊提供的Driver接口就是一個SPI,許多廠商都實現了該SPI(如com.mysql.jdbc.Driver),JDBC模塊通過服務發現機制來獲取到相應的Driver實現類。在規劃某個實際項目的模塊框架時,也可以考慮使用服務發現機制來提高模塊的可擴展性
  Java提供了ServiceLoader類來幫助構建基於服務發現的模塊(ServiceLoader類只是進行服務發現的工具,具體實現還需要根據模塊功能進行規劃)。ServiceLoader.load(Class<S> service)方法可以返回/WEB-INF/services目錄下,以S接口的全類名爲文件名的文件中配置的,所有S接口的實現類。

// 服務發現機制
public final class ServiceLoader<S> implements Iterable<S> {
	// 加載所有ClassPath(包括jar包)下的/WEB-INF/services目錄下,名爲接口S類全名的所有文件中的,配置的所有S接口的實現類
    public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader); // 使用指定的加載器進行加載
    public static <S> ServiceLoader<S> load(Class<S> service); // 使用加載調用者的類加載器進行加載
    public static <S> ServiceLoader<S> loadInstalled(Class<S> service); // 使用擴展類加載器進行加載
    
    public Iterator<S> iterator(); // 對加載的所有實現類進行迭代的迭代器
    public void reload(); // 重新加載
}

  假設需要將Java對象與一種自定義的XO格式字符串(如同JSON格式)進行相互轉換,需要先提供框架相關的XOTool接口與XoToolManager類。各個提供方根據框架提供XOTool的實現類,最後提供方需要將實現類封裝成jar包並在其/WEB-INFO/services/com.java.test.common.XOTool文件中添加一行com.baidu.xo.BaiDuXOTool,具體示例代碼如下:

package com.java.test.common;

import java.util.Iterator;
import java.util.ServiceLoader;

// XO轉換服務的接口,對服務使用方來說是API,對服務提供方來說是SPI
interface XOTool {
    <T> T parser(String s, Class<T> clazz);

    String toXOString(Object object);
}

// XO服務的主要框架,通過服務發現機制來獲取XOTool
class XoToolManager {
    private static ServiceLoader<XOTool> xoToolServiceLoader;

    static {
        xoToolServiceLoader = ServiceLoader.load(XOTool.class);
    }

    public static XOTool getXoTool(String xoToolName) throws Exception {
        Iterator<XOTool> xoToolIterator = xoToolServiceLoader.iterator();
        while (xoToolIterator.hasNext()) {
            XOTool xoTool = xoToolIterator.next();
            if (xoTool.getClass().getName().equals(xoToolName)) {
                return xoTool;
            }
        }

        throw new Exception("沒有符合要求的XoTool實現類");
    }
}

public class SPITest {
    public static void main(String[] var) throws Exception {
        XOTool xoTool = XoToolManager.getXoTool("com.wanglang.MyXOTool");
        Object object = xoTool.parser("我是某個對象XO格式的字符串", Object.class);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章