尝试pigeon拦截器的时候,发现加载自定义拦截器的时候是通过spi serviceloader加载的,学习一波spi。

某个接口,实现有多种,spi能够为某个接口提供具体的实现类。先看下在spi机制下怎么在pigeon中自定义拦截器:

//自定义了一个拦截器,实现了pigeon提供了拦截器接口public class BusinessProviderInterceptor implements ProviderInterceptor {    @Override    public void preInvoke(ProviderContext providerContext) {        LogTagContext.setLogTag("mobileno", "12345678");    }    @Override    public void postInvoke(ProviderContext providerContext) {    }

META-INF/services下创立一个以接口命名的文件,文件里按行排列具体的实现类;文件里内容如下:

xxx.xxx.xxx.xxx.BusinessProviderInterceptor#other selfinterceptor which implement ProviderInterceptor

以上,能够在pigeon中实现自定义拦截器。

pigeon是如何加载实例化这些拦截器的,具体如下:

//providerinterceptor的执行在BuinessProcessFilter里,ProviderProcessInterceptorFactory在废除,新的是ProviderInterceptorFactoryList<ProviderProcessInterceptor> interceptors = ProviderProcessInterceptorFactory.getInterceptors();for (ProviderProcessInterceptor interceptor : interceptors) {    interceptor.preInvoke(request);}List<ProviderInterceptor> contextInterceptors = ProviderInterceptorFactory.getInterceptors();for (ProviderInterceptor interceptor : contextInterceptors) {    interceptor
public class ProviderInterceptorFactory {   //通过ExtensionLoader来加载interceptor   private static List<ProviderInterceptor> interceptors = ExtensionLoader         .getExtensionList(ProviderInterceptor.class);   // 也能够手动调用这个办法来注册   public static boolean registerInterceptor(ProviderInterceptor providerContextInterceptor) {      if (!interceptors.contains(providerContextInterceptor)) {         return interceptors.add(providerContextInterceptor);      }      return false;   }   public static boolean unregisterInterceptor(ProviderInterceptor providerContextInterceptor) {      return interceptors.remove(providerContextInterceptor);   }   public static List<ProviderInterceptor> getInterceptors() {      return interceptors;   }}
public final class ExtensionLoader {   //应用map来存储接口对应的实现,如果map中没有,则通过serviceloader来加载   private static Map<Class<?>, Object> extensionMap = new ConcurrentHashMap<Class<?>, Object>();   private static Map<Class<?>, List<?>> extensionListMap = new ConcurrentHashMap<Class<?>, List<?>>();   private ExtensionLoader() {   }   public static <T> T getExtension(Class<T> clazz) {      T extension = (T) extensionMap.get(clazz);      if (extension == null) {         extension = newExtension(clazz);         if (extension != null) {            extensionMap.put(clazz, extension);         }      }      return extension;   }   public static <T> List<T> getExtensionList(Class<T> clazz) {      List<T> extensions = (List<T>) extensionListMap.get(clazz);      if (extensions == null) {         extensions = newExtensionList(clazz);         if (!extensions.isEmpty()) {            extensionListMap.put(clazz, extensions);         }      }      return extensions;   }   public static <T> T newExtension(Class<T> clazz) {      //  here      ServiceLoader<T> serviceLoader = ServiceLoader.load(clazz);      for (T service : serviceLoader) {         return service;      }      return null;   }   public static <T> List<T> newExtensionList(Class<T> clazz) {      ServiceLoader<T> serviceLoader = ServiceLoader.load(clazz);      List<T> extensions = new ArrayList<T>();      for (T service : serviceLoader) {         extensions.add(service);      }      return extensions;   }}

重点就是ServiceLoader.load

// ServiceLoader 实现了Iterablepublic final class ServiceLoader<S>    implements Iterable<S>{    //目录门路    private static final String PREFIX = "META-INF/services/";    // 正在加载的类或接口    private Class<S> service;    //用来实例化的classloader    private ClassLoader loader;    // 按实例化的程序缓存实现类    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();    //ServiceLoader自定义的一个外部类,次要实现了懒加载    private LazyIterator lookupIterator;        public void reload() {        providers.clear();        lookupIterator = new LazyIterator(service, loader);    }    private ServiceLoader(Class<S> svc, ClassLoader cl) {        service = svc;        loader = cl;        reload();    }    private static void fail(Class service, String msg, Throwable cause)        throws ServiceConfigurationError    {        throw new ServiceConfigurationError(service.getName() + ": " + msg,                                            cause);    }    private static void fail(Class service, String msg)        throws ServiceConfigurationError    {        throw new ServiceConfigurationError(service.getName() + ": " + msg);    }    private static void fail(Class service, URL u, int line, String msg)        throws ServiceConfigurationError    {        fail(service, u + ":" + line + ": " + msg);    }    //解析文件,将文件中的name放到list中    private int parseLine(Class service, URL u, BufferedReader r, int lc,                          List<String> names)        throws IOException, ServiceConfigurationError    {        String ln = r.readLine();        if (ln == null) {            return -1;        }        int ci = ln.indexOf('#');        if (ci >= 0) ln = ln.substring(0, ci);        ln = ln.trim();        int n = ln.length();        if (n != 0) {            if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))                fail(service, u, lc, "Illegal configuration-file syntax");            int cp = ln.codePointAt(0);            if (!Character.isJavaIdentifierStart(cp))                fail(service, u, lc, "Illegal provider-class name: " + ln);            for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {                cp = ln.codePointAt(i);                if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))                    fail(service, u, lc, "Illegal provider-class name: " + ln);            }            // 加载过的不放在这个list里            if (!providers.containsKey(ln) && !names.contains(ln))                names.add(ln);        }        return lc + 1;    }       private Iterator<String> parse(Class service, URL u)        throws ServiceConfigurationError    {        InputStream in = null;        BufferedReader r = null;        ArrayList<String> names = new ArrayList<>();        try {            in = u.openStream();            r = new BufferedReader(new InputStreamReader(in, "utf-8"));            int lc = 1;            while ((lc = parseLine(service, u, r, lc, names)) >= 0);        } catch (IOException x) {            fail(service, "Error reading configuration file", x);        } finally {            try {                if (r != null) r.close();                if (in != null) in.close();            } catch (IOException y) {                fail(service, "Error closing configuration file", y);            }        }        return names.iterator();    }    //懒加载的实现    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;        }        public boolean hasNext() {            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;        }        public S next() {            if (!hasNext()) {                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 {                //在next到某个实现类时,才真正的加载实例                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 void remove() {            throw new UnsupportedOperationException();        }    }    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();            }        };    }    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);    }    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);    }}