java的spi(Service Provider Interface)机制及源码(java8)

1.什么是java的spi

 spi 全称为 service provider interface 即 服务提供接口,用来作为服务的扩展发现。在运行时动态添加接口的实现,是对接口的实现类的创建管理。 

2.运用场景

类似于spring dubbo都有基于java自带的spi模式实现的自有spi管理的机制。

3.如何使用

  •     java 自带的spi

        核心类是:java.util.ServiceLoader 该类是一个被final修饰的类
        使用:
        1.在jar包的"src/META-INF/services"目录下建立一个文件,该文件的文件名是对应接口的全限定名,文件的内容可以有多行,每行是该接口对应的具体实现类的全限定名。
        
private static final String PREFIX = "META-INF/services/";
 
        2.在代码中使用java.util.ServiceLoader加载对应的接口类
//指定类加载器
public static <S> ServiceLoader<S> load(Class<S> service,
                                        ClassLoader loader)
{
    return new ServiceLoader<>(service, loader);
}
//使用当前线程的类加载器
public static <S> ServiceLoader<S> load(Class<S> service) {
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    return ServiceLoader.load(service, cl);
}

//使用extension class loader
public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
    ClassLoader cl = ClassLoader.getSystemClassLoader();
    ClassLoader prev = null;
    while (cl != null) {
        prev = cl;
        cl = cl.getParent();
    }
    return ServiceLoader.load(service, prev);
}

 3.  调用ServiceLoader.load()方法后会new 一个 ServiceLoader<>(Class service, loader);

private ServiceLoader(Class<S> svc, ClassLoader cl) {
        // 这里的service 是对应的接口
    service = Objects.requireNonNull(svc, "Service interface cannot be null");
        // 类加载器
    loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
    //获取当前的AccessControlContext 默认为空
    acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
    reload();
}

  这里的acc 是 java的安全管理器

// The access control context taken when the ServiceLoader is created
private final AccessControlContext acc; 
  对应的System.getSecurityManager() 获取当前的安全SecurityManager
java.lang.System类中

private static volatile SecurityManager security = null;

public static SecurityManager getSecurityManager() {
    return security;
}

4.接着调用reload方法

public void reload() {
    providers.clear();
    lookupIterator = new LazyIterator(service, loader);
}

  providers 同lookupInterator

// Cached providers, in instantiation order
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();


// The current lazy-lookup iterator
private LazyIterator lookupIterator;

5.new 一个内部类 懒加载类LazyInterator

private class LazyIterator
    implements Iterator<S>
{


    Class<S> service;
    ClassLoader loader;
    Enumeration<URL> configs = null;
    Iterator<String> pending = null;
    String nextName = null;


    private LazyIterator(Class<S> service, ClassLoader loader) {
        this.service = service;
        this.loader = loader;
    }


    private boolean hasNextService() {
        if (nextName != null) {
            return true;
        }
        if (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());
        }
        nextName = pending.next();
        return true;
    }


    private S nextService() {
        if (!hasNextService())
            throw new NoSuchElementException();
        String cn = nextName;
        nextName = null;
        Class<?> c = null;
        try {
            c = Class.forName(cn, false, loader);
        } catch (ClassNotFoundException x) {
            fail(service,
                 "Provider " + cn + " not found");
        }
        if (!service.isAssignableFrom(c)) {
            fail(service,
                 "Provider " + cn  + " not a subtype");
        }
        try {
            S p = service.cast(c.newInstance());
            providers.put(cn, p);
            return p;
        } catch (Throwable x) {
            fail(service,
                 "Provider " + cn + " could not be instantiated",
                 x);
        }
        throw new Error();          // This cannot happen
    }


    public boolean hasNext() {
        if (acc == null) {
            return hasNextService();
        } else {
            PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
                public Boolean run() { return hasNextService(); }
            };
            return AccessController.doPrivileged(action, acc);
        }
    }


    public S next() {
        if (acc == null) {
            return nextService();
        } else {
            PrivilegedAction<S> action = new PrivilegedAction<S>() {
                public S run() { return nextService(); }
            };
            return AccessController.doPrivileged(action, acc);
        }
    }


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


}

 6.使用迭代器Interator取出接口的实现对象

public Iterator<S> iterator() {
    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();
        }


    };
}

 

posted @ 2019-03-14 17:08  西罗(斗筲小人)  阅读(518)  评论(0编辑  收藏  举报