Java SPI-ServiceLoader

要写个 ServiceLoader 的简单实现: 1. 读取配置文件,获取实现类的全名称字符串; 2. 使用 Java 反射机制来构造服务实现类的实例。可以使用泛型方法,避免获取的时候做类型转换。不过 JDK 自带的 java.util.ServiceLoader 实现得更加严谨一些,使用了 ClassLoader 来加载类,并使用迭代器来获取服务实现类。思路大体相同。

复制代码

package autocomplete;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by lovesqcc on 16-2-29.
 * A very Simple JavaSPI implementation using java reflection
 */
public class SimpleServiceLoader {

    private static final String PREFIX = "/META-INF/services/";

    public static <T> List<T> load(Class<T> cls) {
        List<String> implClasses = readServiceFile(cls);
        List<T> implList = new ArrayList<T>();
        for (String implClass : implClasses) {
            Class<T> c = null;
            try {
                c = (Class<T>) Class.forName(implClass);
                implList.add(c.newInstance());
            } catch (Exception e) {
                return new ArrayList<T>();
            }
        }
        return implList;
    }

    private static List<String> readServiceFile(Class<?> cls) {
        String infName = cls.getCanonicalName();
        String fileName = cls.getResource(PREFIX+infName).getPath();
        try {
            BufferedReader br = new BufferedReader(new FileReader(new File(fileName)));
            String line = "";
            List<String> implClasses = new ArrayList<String>();
            while ((line = br.readLine()) != null) {
                implClasses.add(line);
            }
            return implClasses;
        } catch (FileNotFoundException fnfe) {
            System.out.println("File not found: " + fileName);
            return new ArrayList<String>();
        } catch (IOException ioe) {
            System.out.println("Read file failed: " + fileName);
            return new ArrayList<String>();
        }
    }

    public static void main(String[] args) {
        List<PrefixMatcher> implList = load(PrefixMatcher.class);
        if (implList != null && implList.size() >0) {
            for (PrefixMatcher matcher: implList) {
                System.out.println(matcher.obtainMatchedWords("sh"));
            }
        }
    }
}

复制代码

 

  ServiceLoader 的实现涉及到如下概念: 指向对象类型的 Class<S> 对象; 类加载器 ClassLoader; 服务实现类的资源抽象; 服务实现类的全名字符串。结合类加载器和资源抽象获得服务实现类的全名字符串,再通过类加载器获取 Class<S> 对象, 最后通过 Class<S> 对象来构造服务实现类 S 的实例 s 。

 

  ServiceLoader 的成员为 <Class<S> service, ClassLoader loader, LinkedHashMap<String,S> providers, LazyIterator lookupIterator>, 其中 service 是服务接口,loader 是类加载器, providers 是服务实现类的缓存, lookupIterator 是获取服务实现类的迭代器,是 ServiceLoader 的内部类。 LazyIterator 的成员是 <Class<S> service, ClassLoader loader, Enumeration<URL> configs, Iterator<String> pending, String nextName>, configs 存放服务实现类的资源配置抽象, pending 存放服务实现类的全名字符串, nextName 是下一个可获取的服务实现类的全名字符串。加载资源使用到 classLoader 的 getSystemResources 和 getResources 方法。Java里的资源抽象使用类 URL 来唯一标识,无论是本地文件 ( file:/// ) 还是网络文件 (http(s):// )。由于要从文件或网络读取文本字符串,因此要使用 BufferedReader 。

 

  在 Java 中,Class<T> 和 ClassLoader 是造物之始。万物皆是“某类T” 的存在物,而“某类T” 是“万类之类 Class<T>” 的存在物,类别也是一种存在物,存在物即 Object。实例 t -> 类别 T -> 所有类别的抽象 Class<T> -> Object。要创造类别 T 的实例,先通过某种方式(ClassLoader)找到该物的“种子”(Class<T> 对象),然后通过该种子来创造具体的物 t。要生成一个 Integer 对象,先找到 Class<Integer> , 然后 newInstance 出 Integer 的实例。而造物也要有个规则,“女娲造物”和“凡人造物”,如果要造一模一样的物种,必须先经由女娲造物,否则就会造成混乱(至少软件中会出现问题)。在 Java 里就有 BootstrapClassLoader -> ExtClassLoader -> AppClassLoader -> CustomClassLoader 的先后规则。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值