1. public class ddd {
  2. public static void main(String[] args) {
  3. ServiceLoader1<Hello> sl = ServiceLoader1.load(Hello.class);//传进去了Hello.class和线程上下文类加载器。
  4. for(Hello h : sl) {//调用sl的iterator()
  5. h.say();//com.ssss.impl.CHello@1324409e,
  6. }
  7. }
  8. }
  1. package com.ssss;
  2. /*
  3. 服务提供者加载机制。针对SPI设计出来的。
  4.  
  5. 服务是接口或抽象类。服务提供者是服务接口的实现。ServiceLoader是加载实现类的。服务提供者是jdbc数据库驱动。
  6. 不是线程安全的。
  7. 文件名是接口,文件内容是实现。
  8.  
  9. @since 1.6 1.6才开始加入,
  10. 根据META-INF/services/文件去加载相应的实现类。
  11. */
  12.  
  13. public final class ServiceLoader1<S> implements Iterable<S>{
  14. private static final String PREFIX = "META-INF/services/";//指明了路径是在META-INF/services/下。
  15. // 传进来的接口的class。正在加载的服务的类或接口。
  16. private final Class<S> service;
  17. // 线程上下文加载器。类加载器。
  18. private final ClassLoader loader;
  19. // 权限控制上下文。创建ServiceLoader时获取的访问控制上下文。
  20. private final AccessControlContext acc;
  21. // 服务提供者的缓存,服务是接口,服务提供者是接口的实现。
  22. private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
  23. // for循环遍历时候调用的是这个在遍历。用于类的懒加载,只有在迭代时加载。
  24. private LazyIterator lookupIterator;
  25.  
  26. public void reload() {//构造函数调用
  27. providers.clear();
  28. lookupIterator = new LazyIterator(service, loader);//interface com.ssss.Hello,AppClassLoader
  29. }
  30.  
  31. private ServiceLoader1(Class<S> svc, ClassLoader cl) {//service=interface com.ssss.Hello, cl=AppClassLoader。
  32. service = Objects.requireNonNull(svc, "Service interface cannot be null");//interface com.ssss.Hello
  33. loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;//AppClassLoader,getSystemClassLoader返回的也是appClassLoder,所以获取应用加载器可以线程获取也可以getSystemClassLoader()来获取。
  34. acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;//null
  35. reload();
  36. }
  37.  
  38. private static void fail(Class<?> service, String msg, Throwable cause)throws ServiceConfigurationError
  39. {
  40. throw new ServiceConfigurationError(service.getName() + ": " + msg,cause);
  41. }
  42.  
  43. private static void fail(Class<?> service, String msg) throws ServiceConfigurationError
  44. {
  45. throw new ServiceConfigurationError(service.getName() + ": " + msg);
  46. }
  47.  
  48. private static void fail(Class<?> service, URL u, int line, String msg) throws ServiceConfigurationError
  49. {
  50. fail(service, u + ":" + line + ": " + msg);
  51. }
  52.  
  53. private int parseLine(Class<?> service, URL u, BufferedReader r, int lc, List<String> names)
  54. throws IOException, ServiceConfigurationError
  55. {
  56. String ln = r.readLine();//一行
  57. if (ln == null) {
  58. return -;//-1表示解析完成
  59. }
  60. int ci = ln.indexOf('#');
  61. if (ci >= ) ln = ln.substring(, ci);//去掉注释
  62. ln = ln.trim();//去掉空格
  63. int n = ln.length();
  64. if (n != ) {
  65. if ((ln.indexOf(' ') >= ) || (ln.indexOf('\t') >= ))
  66. fail(service, u, lc, "Illegal configuration-file syntax");
  67. int cp = ln.codePointAt();
  68. if (!Character.isJavaIdentifierStart(cp))
  69. fail(service, u, lc, "Illegal provider-class name: " + ln);
  70. for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
  71. cp = ln.codePointAt(i);
  72. if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
  73. fail(service, u, lc, "Illegal provider-class name: " + ln);
  74. }
  75. if (!providers.containsKey(ln) && !names.contains(ln))
  76. names.add(ln);//添加实现类名字[com.ssss.impl.CHello, com.ssss.impl.JavaHello],
  77. }
  78. return lc + ;
  79. }
  80.  
  81. //u = file:\H:\2019326spring\蚂蚁课堂\0005-(每特教育&每特学院&蚂蚁课堂)-3期-并发编程专题-线程池原理分析\0005
  82. //-(每特教育&每特学院&蚂蚁课堂)-3期-并发编程专题-线程池原理分析\上课代码\thread_day_day06_test\target
  83. //\classes\META-INF\services\com.ssss.Hello文件
  84. private Iterator<String> parse(Class<?> service, URL u) throws ServiceConfigurationError {
  85. InputStream in = null;
  86. BufferedReader r = null;
  87. ArrayList<String> names = new ArrayList<>();
  88. try {
  89. in = u.openStream();
  90. r = new BufferedReader(new InputStreamReader(in, "utf-8"));
  91. int lc = ;
  92. while ((lc = parseLine(service, u, r, lc, names)) >= );//添加到names里面去。
  93. } catch (IOException x) {
  94. fail(service, "Error reading configuration file", x);
  95. } finally {
  96. try {
  97. if (r != null) r.close();
  98. if (in != null) in.close();
  99. } catch (IOException y) {
  100. fail(service, "Error closing configuration file", y);
  101. }
  102. }
  103. return names.iterator();
  104. }
  105.  
  106. private class LazyIterator implements Iterator<S>//遍历实现类
  107. {
  108.  
  109. Class<S> service;//接口的Class
  110. ClassLoader loader;//app应用加载器
  111. Enumeration<URL> configs = null;//配置文件的绝对路径
  112. Iterator<String> pending = null;//所有实现类的集合
  113. String nextName = null;//判断是否有下一个元素时候,就设置了下一个元素的名字了nextName
  114.  
  115. private LazyIterator(Class<S> service, ClassLoader loader) {
  116. this.service = service;//interface com.ssss.Hello
  117. this.loader = loader;//AppClassLoader
  118. }
  119.  
  120. private boolean hasNextService() {//是否有下一个实现类元素
  121. if (nextName != null) {
  122. return true;
  123. }
  124. if (configs == null) {//初始化configs
  125. try {
  126. String fullName = PREFIX + service.getName();//文件路径:META-INF/services/com.ssss.Hello
  127. if (loader == null)
  128. configs = ClassLoader.getSystemResources(fullName);
  129. else
  130. configs = loader.getResources(fullName);//loader = AppClassLoader,加载META-INF/services/com.ssss.Hello资源
  131. } catch (IOException x) {
  132. fail(service, "Error locating configuration files", x);
  133. }
  134. }
  135. while ((pending == null) || !pending.hasNext()) {//初始化pending
  136. if (!configs.hasMoreElements()) {//一个配置文件所有实现类遍历完之后,pending.hasNext()返回false,configs.hasMoreElements()返回false
  137. return false;
  138. }
  139. pending = parse(service, configs.nextElement());//pending = [com.ssss.impl.CHello, com.ssss.impl.JavaHello]集合,configs.nextElement()就是配置文件的绝对路径,
  140. }
  141. nextName = pending.next();//判断是否有下一个元素时候,就设置了下一个元素的名字了nextName,pending里面有一个游标,一直调用next方法时候游标加一,所以一直获取的是下一个元素。
  142. return true;
  143. }
  144.  
  145. private S nextService() {//下一个实现类
  146. if (!hasNextService())
  147. throw new NoSuchElementException();
  148. String cn = nextName;//实现类名字com.ssss.impl.CHello
  149. nextName = null;//下一个名字置为null,再次获取下一个的时候重新设置值。
  150. Class<?> c = null;
  151. try {
  152. c = Class.forName(cn, false, loader);//class com.ssss.impl.CHello
  153. } catch (ClassNotFoundException x) {
  154. fail(service, "Provider " + cn + " not found");
  155. }
  156. if (!service.isAssignableFrom(c)) {//service = interface com.ssss.Hello,c = class com.ssss.impl.CHello.
  157. fail(service, "Provider " + cn + " not a subtype");
  158. }
  159. try {
  160. S p = service.cast(c.newInstance());//p = com.ssss.impl.CHello@1324409e对象,
  161. providers.put(cn, p);//实现类的名字,实现类的对象放入缓存。{com.ssss.impl.CHello:com.ssss.impl.CHello@1324409e,com.ssss.impl.JavaHello:com.ssss.impl.JavaHello@246ae04d}
  162. return p;//返回实现类对象
  163. } catch (Throwable x) {
  164. fail(service,"Provider " + cn + " could not be instantiated",x);
  165. }
  166. throw new Error(); // This cannot happen
  167. }
  168.  
  169. public boolean hasNext() {//是否有下一个实现类元素
  170. if (acc == null) {//权限判断
  171. return hasNextService();
  172. } else {
  173. PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
  174. public Boolean run() { return hasNextService(); }
  175. };
  176. return AccessController.doPrivileged(action, acc);
  177. }
  178. }
  179.  
  180. public S next() {//下一个实现类
  181. if (acc == null) {
  182. return nextService();
  183. } else {
  184. PrivilegedAction<S> action = new PrivilegedAction<S>() {
  185. public S run() { return nextService(); }
  186. };
  187. return AccessController.doPrivileged(action, acc);
  188. }
  189. }
  190.  
  191. public void remove() {
  192. throw new UnsupportedOperationException();
  193. }
  194.  
  195. }
  196.  
  197. //延迟加载:首先从缓存,配置文件加载之后加入缓存。
  198. public Iterator<S> iterator() {//遍历方法。for循环时候先调用hasNext()在调用next()。
  199. return new Iterator<S>() {
  200. Iterator<Map.Entry<String,S>> knownProviders = providers.entrySet().iterator();//缓存
  201.  
  202. public boolean hasNext() {//是否有下一个元素
  203. if (knownProviders.hasNext())
  204. return true;
  205. return lookupIterator.hasNext();
  206. }
  207.  
  208. public S next() {//获取下一个元素
  209. if (knownProviders.hasNext())
  210. return knownProviders.next().getValue();
  211. return lookupIterator.next();
  212. }
  213.  
  214. public void remove() {//移除
  215. throw new UnsupportedOperationException();
  216. }
  217.  
  218. };
  219. }
  220.  
  221. public static <S> ServiceLoader1<S> load(Class<S> service,ClassLoader loader){
  222. return new ServiceLoader1<>(service, loader);
  223. }
  224.  
  225. public static <S> ServiceLoader1<S> load(Class<S> service) {//service = interface com.ssss.Hello
  226. ClassLoader cl = Thread.currentThread().getContextClassLoader();//AppClassLoader,ServiceLoader类本身是boot加载器加载的,boot加载不到应用类路径下的类,所以要用app加载器。
  227. return ServiceLoader1.load(service, cl);
  228. }
  229.  
  230. public static <S> ServiceLoader1<S> loadInstalled(Class<S> service) {
  231. ClassLoader cl = ClassLoader.getSystemClassLoader();//系统加载器,app加载器
  232. ClassLoader prev = null;
  233. while (cl != null) {//系统加载器为null,prev就是null。扩展加载器是null,prev就是系统加载器。否则prev就是扩展加载器。
  234. prev = cl;//扩展加载器
  235. cl = cl.getParent();//扩展加载器
  236. }
  237. return ServiceLoader1.load(service, prev);//目的是为了加载jvm虚拟机里面的类,不是应用类路径下的类。
  238. }
  239.  
  240. public String toString() {
  241. return "java.util.ServiceLoader[" + service.getName() + "]";
  242. }
  243. }

SPI ServiceLoader源码分析的更多相关文章

  1. 【Java】ServiceLoader源码分析

    ServiceLoader主要的功能是用来完成对SPI的provider的加载. 先看下它的成员: public final class ServiceLoader<S> implemen ...

  2. Dubbo SPI 机制源码分析(基于2.7.7)

    Dubbo SPI 机制涉及到 @SPI.@Adaptive.@Activate 三个注解,ExtensionLoader 作为 Dubbo SPI 机制的核心负责加载和管理扩展点及其实现.本文以 E ...

  3. 【Java】NIO中Selector的创建源码分析

    在使用Selector时首先需要通过静态方法open创建Selector对象 public static Selector open() throws IOException { return Sel ...

  4. dubbo源码分析02:服务引用

    一.何时创建服务引用 引用官方文档的原话,如果将Dubbo托管在Spring-IOC容器下,Dubbo服务引用的时机有两个,第一个是在Spring容器调用ReferenceBean的afterProp ...

  5. 7.源码分析---SOFARPC是如何实现故障剔除的?

    我在服务端引用那篇文章里面分析到,服务端在引用的时候会去获取服务端可用的服务,并进行心跳,维护一个可用的集合. 所以我们从客户端初始化这部分说起. 服务连接的维护 客户端初始化的时候会调用cluste ...

  6. 8.源码分析---从设计模式中看SOFARPC中的EventBus?

    我们在前面分析客户端引用的时候会看到如下这段代码: // 产生开始调用事件 if (EventBus.isEnable(ClientStartInvokeEvent.class)) { EventBu ...

  7. 9.源码分析---SOFARPC是如何实现故障剔除的?

    SOFARPC源码解析系列: 1. 源码分析---SOFARPC可扩展的机制SPI 2. 源码分析---SOFARPC客户端服务引用 3. 源码分析---SOFARPC客户端服务调用 4. 源码分析- ...

  8. 11.源码分析---SOFARPC数据透传是实现的?

    先把栗子放上,让大家方便测试用: Service端 public static void main(String[] args) { ServerConfig serverConfig = new S ...

  9. 12.源码分析—如何为SOFARPC写一个序列化?

    SOFARPC源码解析系列: 1. 源码分析---SOFARPC可扩展的机制SPI 2. 源码分析---SOFARPC客户端服务引用 3. 源码分析---SOFARPC客户端服务调用 4. 源码分析- ...

随机推荐

  1. NSURLProtocol的总结

    http://www.cnblogs.com/xiaxlsblog/archive/2013/08/09/NSURLProtocol-xiaxl.html NSURLProtocol是一个抽象类.NS ...

  2. vue cli 常见问题汇总

    以下是本人在用vue cli 开发项目里遇到的最基本的问题及解决方案汇总.没啥很多技术性的东西,各位看个乐呵就行~ 1.vue-cli 创建的项目各文件夹的含义 注意:通过vue-cli 4 创建的项 ...

  3. base64编码与解码

    var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ...

  4. LeetCode 1091. Shortest Path in Binary Matrix

    原题链接在这里:https://leetcode.com/problems/shortest-path-in-binary-matrix/ 题目: In an N by N square grid, ...

  5. JS中的let变量和var变量的区别

    let var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]]; let允许你声明一个作用域被限制在块级中的变量.语句或者表达式.在F ...

  6. Mongoose 内置 CURD 方 法、扩展 Mongoose Model 的静态方法和 实例方法

    Mongoose 内置 CURD 方 法 Mongoose 内置 CURD 方 法文档地址:https://mongoosejs.com/docs/queries.html 常用的方法如下: Mode ...

  7. 一种SpaceClaim抽取流道的方法——利用缺失的面功能

    针对不干净的几何,内部存在诸多碎面小缝隙,采用此方法可能会有较好的效果,不过需要耐心. 测试几何需要SpaceClaim19.0以上软件可以打开,下载链接: https://pan.baidu.com ...

  8. [技术博客]django连接mysql数据库的方法及部分问题的解决方法

    配置机器介绍 操作系统:Ubuntu 18.04.2 LTS 64位 python版本:Python 3.6.7 Django版本:Django 2.2 MySql版本:5.7.26 数据库选择 我们 ...

  9. Google BERT应用之《红楼梦》对话人物提取

    Google BERT应用之<红楼梦>对话人物提取 https://www.jiqizhixin.com/articles/2019-01-24-19

  10. CloudFlare上线了新的Proxy Anything选项, 支持转发TCP连接

    https://www.nicho1as.wang/articles/cf-proxy-anything.html 申请地址:https://goo.gl/forms/Oc2jyyo0kXsrMyw3 ...