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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章