博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SPI ServiceLoader源码分析
阅读量:5249 次
发布时间:2019-06-14

本文共 8243 字,大约阅读时间需要 27 分钟。

 

public class ddd {    public static void main(String[] args) {        ServiceLoader1
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 implements Iterable{    private static final String PREFIX = "META-INF/services/";//指明了路径是在META-INF/services/下。    // 传进来的接口的class。正在加载的服务的类或接口。    private final Class service;    // 线程上下文加载器。类加载器。    private final ClassLoader loader;    // 权限控制上下文。创建ServiceLoader时获取的访问控制上下文。    private final AccessControlContext acc;    // 服务提供者的缓存,服务是接口,服务提供者是接口的实现。    private LinkedHashMap
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
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
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('\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); } 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\蚂蚁课堂\0005-(每特教育&每特学院&蚂蚁课堂)-3期-并发编程专题-线程池原理分析\0005 //-(每特教育&每特学院&蚂蚁课堂)-3期-并发编程专题-线程池原理分析\上课代码\thread_day_day06_test\target //\classes\META-INF\services\com.ssss.Hello文件 private Iterator
parse(Class
service, URL u) throws ServiceConfigurationError { InputStream in = null; BufferedReader r = null; ArrayList
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
//遍历实现类 { Class service;//接口的Class ClassLoader loader;//app应用加载器 Enumeration
configs = null;//配置文件的绝对路径 Iterator
pending = null;//所有实现类的集合 String nextName = null;//判断是否有下一个元素时候,就设置了下一个元素的名字了nextName private LazyIterator(Class
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
action = new PrivilegedAction
() { public Boolean run() { return hasNextService(); } }; return AccessController.doPrivileged(action, acc); } } public S next() { //下一个实现类 if (acc == null) { return nextService(); } else { PrivilegedAction
action = new PrivilegedAction() { public S run() { return nextService(); } }; return AccessController.doPrivileged(action, acc); } } public void remove() { throw new UnsupportedOperationException(); } } //延迟加载:首先从缓存,配置文件加载之后加入缓存。 public Iterator iterator() { //遍历方法。for循环时候先调用hasNext()在调用next()。 return new Iterator() { Iterator
> 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
ServiceLoader1 load(Class service,ClassLoader loader){ return new ServiceLoader1<>(service, loader); } public static ServiceLoader1 load(Class service) { //service = interface com.ssss.Hello ClassLoader cl = Thread.currentThread().getContextClassLoader();//AppClassLoader,ServiceLoader类本身是boot加载器加载的,boot加载不到应用类路径下的类,所以要用app加载器。 return ServiceLoader1.load(service, cl); } public static ServiceLoader1 loadInstalled(Class 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() + "]"; }}

 

转载于:https://www.cnblogs.com/yaowen/p/10839507.html

你可能感兴趣的文章
javascript之Style物
查看>>
JSON跨域解决方案收集
查看>>
图的深度优先遍历
查看>>
C# 之 提高WebService性能大数据量网络传输处理
查看>>
[bzoj1004] [HNOI2008] Cards
查看>>
原生HttpClient详细使用示例
查看>>
几道面试题
查看>>
Factory Design Pattern
查看>>
python中贪婪与非贪婪
查看>>
guava API整理
查看>>
无锁编程笔记
查看>>
jquery mobile
查看>>
如何在vue单页应用中使用百度地图
查看>>
Springboot使用步骤
查看>>
Spring属性注入
查看>>
Springboot-配置文件
查看>>
Springboot-日志框架
查看>>
P1192-台阶问题
查看>>
一、使用pip安装Python包
查看>>
spring与quartz整合
查看>>