ServiceLoader

JDK 实现的 service 装载。

A service provider is a specific implementation of a service

实例:JDBC 驱动

How to use

配置文件

  1. provider-configuration file in the resource directory META-INF/services.
  2. 注释使用 #
  3. 必须 UTF-8
  4. 配置文件和代码可以放于不同的jar
  5. 懒加载&懒获取

Example

我们有 抽象类com.example.CodecSet

public abstract class CodecSet {
    public abstract Encoder getEncoder(String encodingName);
    public abstract Decoder getDecoder(String encodingName);
}

我们还有实现com.example.impl.StandardCodecs

public class StandardCodecs extends CodecSet {
    @Override
    public Encoder getEncoder(String encodingName) {
        return null;
    }

    @Override
    public Decoder getDecoder(String encodingName) {
        return null;
    }
}

实现类注册文件

META-INF/services/com.example.CodecSet This file contains the single line:

com.example.impl.StandardCodecs

获取实例:

        ServiceLoader<CodecSet> codecSetLoader = ServiceLoader.load(CodecSet.class);
        CodecSet codecSet = null;
        for (CodecSet cp : codecSetLoader) {
            codecSet = cp;
            break;
        }
        System.out.println(codecSet.getClass().toString());

输出

class com.example.impl.StandardCodecs

fun point

懒加载 ServiceLoader.LazyIterator

ServiceLoader 实习了 Iterable接口,内部实际执行委托给LazyIterator

关键流程

hasNextService

  1. 加载相关文件
    	Class<S> service;
        ClassLoader loader;
        Enumeration<URL> configs = null;
          try {
                    String fullName = PREFIX + service.getName();
                    if (loader == null)
                        configs = ClassLoader.getSystemResources(fullName);
                    else
                        configs = loader.getResources(fullName);
                } catch (IOException x) {
                    fail(service, "Error locating configuration files", x);
                }

逐步解析

            while ((pending == null) || !pending.hasNext()) {
                if (!configs.hasMoreElements()) {
                    return false;
                }
                pending = parse(service, configs.nextElement());
            }

next

加载类

            String cn = nextName;
            nextName = null;
            Class<?> c = null;
            try {
                c = Class.forName(cn, false, loader);
            } catch (ClassNotFoundException x) {
                fail(service,
                     "Provider " + cn + " not found");
            }

放入缓存

                S p = service.cast(c.newInstance());
                providers.put(cn, p);
                return p;

缓存机制

reload 方法

    // Cached providers, in instantiation order
    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
	public void reload() {
        providers.clear();
        lookupIterator = new LazyIterator(service, loader);
    }

迭代器

        return new Iterator<S>() {

            Iterator<Map.Entry<String,S>> knownProviders
                = providers.entrySet().iterator();

            public boolean hasNext() {
                if (knownProviders.hasNext())
                    return true;
                return lookupIterator.hasNext();
            }

            public S next() {
                if (knownProviders.hasNext())
                    return knownProviders.next().getValue();
                return lookupIterator.next();
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }

        };

基本原理

knownProviders 在创建时,内容是个快照.

Last Updated:
Contributors: mcs