zoukankan      html  css  js  c++  java
  • SPI ServiceLoader源码分析

    public class ddd {
        public static void main(String[] args) {
            ServiceLoader1<Hello> sl = ServiceLoader1.load(Hello.class);//传进去了Hello.class和线程上下文类加载器。
            for(Hello h : sl) {//调用sl的iterator()
                h.say();//com.ssss.impl.CHello@1324409e,
            }
        }
    }
    package com.ssss;
    /*
     服务提供者加载机制。针对SPI设计出来的。
     
     服务是接口或抽象类。服务提供者是服务接口的实现。ServiceLoader是加载实现类的。服务提供者是jdbc数据库驱动。
    不是线程安全的。
    文件名是接口,文件内容是实现。
     
    @since 1.6   1.6才开始加入,
     根据META-INF/services/文件去加载相应的实现类。
    */
    
    public final class ServiceLoader1<S> implements Iterable<S>{
        private static final String PREFIX = "META-INF/services/";//指明了路径是在META-INF/services/下。
        // 传进来的接口的class。正在加载的服务的类或接口。
        private final Class<S> service;
        // 线程上下文加载器。类加载器。
        private final ClassLoader loader;
        // 权限控制上下文。创建ServiceLoader时获取的访问控制上下文。
        private final AccessControlContext acc;
        // 服务提供者的缓存,服务是接口,服务提供者是接口的实现。
        private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
        // for循环遍历时候调用的是这个在遍历。用于类的懒加载,只有在迭代时加载。
        private LazyIterator lookupIterator;
    
        public void reload() {//构造函数调用
            providers.clear();
            lookupIterator = new LazyIterator(service, loader);//interface com.ssss.Hello,AppClassLoader
        }
    
        private ServiceLoader1(Class<S> svc, ClassLoader cl) {//service=interface com.ssss.Hello,     cl=AppClassLoader。
            service = Objects.requireNonNull(svc, "Service interface cannot be null");//interface com.ssss.Hello
            loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;//AppClassLoader,getSystemClassLoader返回的也是appClassLoder,所以获取应用加载器可以线程获取也可以getSystemClassLoader()来获取。
            acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;//null
            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);
        }
    
        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;//-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('	') >= 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);
                }
                if (!providers.containsKey(ln) && !names.contains(ln))
                    names.add(ln);//添加实现类名字[com.ssss.impl.CHello, com.ssss.impl.JavaHello],
            }
            return lc + 1;
        }
    
        //u = file:H:2019326spring蚂蚁课堂005-(每特教育&每特学院&蚂蚁课堂)-3期-并发编程专题-线程池原理分析005
        //-(每特教育&每特学院&蚂蚁课堂)-3期-并发编程专题-线程池原理分析上课代码	hread_day_day06_test	arget
        //classesMETA-INFservicescom.ssss.Hello文件
        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);//添加到names里面去。
            } 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;//接口的Class
            ClassLoader loader;//app应用加载器
            Enumeration<URL> configs = null;//配置文件的绝对路径
            Iterator<String> pending = null;//所有实现类的集合
            String nextName = null;//判断是否有下一个元素时候,就设置了下一个元素的名字了nextName
    
            private LazyIterator(Class<S> service, ClassLoader loader) {
                this.service = service;//interface com.ssss.Hello
                this.loader = loader;//AppClassLoader
            }
    
            private boolean hasNextService() {//是否有下一个实现类元素
                if (nextName != null) {
                    return true;
                }
                if (configs == null) {//初始化configs
                    try {
                        String fullName = PREFIX + service.getName();//文件路径:META-INF/services/com.ssss.Hello
                        if (loader == null)
                            configs = ClassLoader.getSystemResources(fullName);
                        else
                            configs = loader.getResources(fullName);//loader = AppClassLoader,加载META-INF/services/com.ssss.Hello资源
                    } catch (IOException x) {
                        fail(service, "Error locating configuration files", x);
                    }
                }
                while ((pending == null) || !pending.hasNext()) {//初始化pending
                    if (!configs.hasMoreElements()) {//一个配置文件所有实现类遍历完之后,pending.hasNext()返回false,configs.hasMoreElements()返回false
                        return false;
                    }
                    pending = parse(service, configs.nextElement());//pending = [com.ssss.impl.CHello, com.ssss.impl.JavaHello]集合,configs.nextElement()就是配置文件的绝对路径,
                }
                nextName = pending.next();//判断是否有下一个元素时候,就设置了下一个元素的名字了nextName,pending里面有一个游标,一直调用next方法时候游标加一,所以一直获取的是下一个元素。
                return true;
            }
    
            private S nextService() {//下一个实现类
                if (!hasNextService())
                    throw new NoSuchElementException();
                String cn = nextName;//实现类名字com.ssss.impl.CHello
                nextName = null;//下一个名字置为null,再次获取下一个的时候重新设置值。
                Class<?> c = null;
                try {
                    c = Class.forName(cn, false, loader);//class com.ssss.impl.CHello
                } catch (ClassNotFoundException x) {
                    fail(service, "Provider " + cn + " not found");
                }
                if (!service.isAssignableFrom(c)) {//service = interface com.ssss.Hello,c = class com.ssss.impl.CHello.
                    fail(service, "Provider " + cn  + " not a subtype");
                }
                try {
                    S p = service.cast(c.newInstance());//p = com.ssss.impl.CHello@1324409e对象,
                    providers.put(cn, p);//实现类的名字,实现类的对象放入缓存。{com.ssss.impl.CHello:com.ssss.impl.CHello@1324409e,com.ssss.impl.JavaHello:com.ssss.impl.JavaHello@246ae04d}
                    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();
            }
    
        }
    
        //延迟加载:首先从缓存,配置文件加载之后加入缓存。 
        public Iterator<S> iterator() {//遍历方法。for循环时候先调用hasNext()在调用next()。
            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> ServiceLoader1<S> load(Class<S> service,ClassLoader loader){
            return new ServiceLoader1<>(service, loader);
        }
    
        public static <S> ServiceLoader1<S> load(Class<S> service) {//service = interface com.ssss.Hello
            ClassLoader cl = Thread.currentThread().getContextClassLoader();//AppClassLoader,ServiceLoader类本身是boot加载器加载的,boot加载不到应用类路径下的类,所以要用app加载器。
            return ServiceLoader1.load(service, cl);
        }
    
        public static <S> ServiceLoader1<S> loadInstalled(Class<S> service) {
            ClassLoader cl = ClassLoader.getSystemClassLoader();//系统加载器,app加载器
            ClassLoader prev = null;
            while (cl != null) {//系统加载器为null,prev就是null。扩展加载器是null,prev就是系统加载器。否则prev就是扩展加载器。
                prev = cl;//扩展加载器
                cl = cl.getParent();//扩展加载器
            }
            return ServiceLoader1.load(service, prev);//目的是为了加载jvm虚拟机里面的类,不是应用类路径下的类。
        }
    
        public String toString() {
            return "java.util.ServiceLoader[" + service.getName() + "]";
        }
    }

     

  • 相关阅读:
    java通过commons-fileupload实现多张图片的上传(jsp页面)
    java通过commons-fileupload实现多张图片的上传(jsp页面)
    java通过commons-fileupload实现多张图片的上传(servlet)
    java通过commons-fileupload实现多张图片的上传(servlet)
    java通过commons-fileupload实现多张图片的上传(servlet)
    myeclipse 2016 ci3破解教程(含软件下载)
    myeclipse 2016 ci3破解教程(含软件下载)
    sql server 2012远程链接的方法及步骤
    sql server 2012远程链接的方法及步骤
    sql server 2012远程链接的方法及步骤
  • 原文地址:https://www.cnblogs.com/yaowen/p/10839507.html
Copyright © 2011-2022 走看看