JDK SPI机制ServiceLoader源码浅析

短命女 2022-10-22 04:12 280阅读 0赞

1.load

返回创建的ServiceLoader对象

清理providers

lookupIterator指向创建的LazyIterator对象

  1. public static <S> ServiceLoader<S> load(Class<S> service) {
  2. // 获取当前线程的上下文类加载器
  3. ClassLoader cl = Thread.currentThread().getContextClassLoader();
  4. return ServiceLoader.load(service, cl);
  5. public static <S> ServiceLoader<S> load(Class<S> service,
  6. ClassLoader loader)
  7. {
  8. return new ServiceLoader<>(service, loader);
  9. }
  10. private ServiceLoader(Class<S> svc, ClassLoader cl) {
  11. // ServiceLoader的字段 private final Class<S> service; private final ClassLoader loader;
  12. service = Objects.requireNonNull(svc, "Service interface cannot be null");
  13. loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
  14. // acc为null,不用关注
  15. acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
  16. // 每次创建ServiceLoader对象都会清除缓存
  17. reload();
  18. }
  19. public void reload() {
  20. // private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
  21. // 清理缓存的实现类
  22. providers.clear();
  23. // 实例化LazyIterator
  24. lookupIterator = new LazyIterator(service, loader);
  25. }
  26. private LazyIterator(Class<S> service, ClassLoader loader) {
  27. this.service = service;
  28. this.loader = loader;
  29. }

2.iterator

通过iterator()获取所有的实现类

  1. public Iterator<S> iterator() {
  2. return new Iterator<S>() {
  3. // 获取已有的缓存,如果有的话,会先遍历这些
  4. Iterator<Map.Entry<String,S>> knownProviders
  5. = providers.entrySet().iterator();
  6. public boolean hasNext() {
  7. if (knownProviders.hasNext())
  8. return true;
  9. return lookupIterator.hasNext();
  10. }
  11. public S next() {
  12. if (knownProviders.hasNext())
  13. return knownProviders.next().getValue();
  14. return lookupIterator.next();
  15. }
  16. public void remove() {
  17. throw new UnsupportedOperationException();
  18. }
  19. };
  20. }

3.hasNext

是否有下一个实现类

  1. // hasNext()调用hasNextServcie
  2. private boolean hasNextService() {
  3. // 如果有下一个要加载的实现类,返回ture
  4. // String nextName是LazyIterator的字段
  5. if (nextName != null) {
  6. return true;
  7. }
  8. // LazyIterator字段 Enumeration<URL> configs = null;
  9. if (configs == null) {
  10. try {
  11. // ServiceLoader的字段 private static final String PREFIX = "META-INF/services/"
  12. // 接口名和services下的文件名一样
  13. String fullName = PREFIX + service.getName();
  14. if (loader == null)
  15. configs = ClassLoader.getSystemResources(fullName);
  16. else
  17. // LazyIterator的字段 Enumeration<URL> configs = null;
  18. // 获取文件资源
  19. configs = loader.getResources(fullName);
  20. } catch (IOException x) {
  21. fail(service, "Error locating configuration files", x);
  22. }
  23. }
  24. // LazyIterator的字段 Iterator<String> pending = null;
  25. // 解析文件内容
  26. while ((pending == null) || !pending.hasNext()) {
  27. if (!configs.hasMoreElements()) {
  28. return false;
  29. }
  30. pending = parse(service, configs.nextElement());
  31. }
  32. // 取出一个实现类
  33. nextName = pending.next();
  34. return true;
  35. }
  36. // 解析文件内容,返回实现类名List的迭代器
  37. private Iterator<String> parse(Class<?> service, URL u)
  38. throws ServiceConfigurationError
  39. {
  40. InputStream in = null;
  41. BufferedReader r = null;
  42. ArrayList<String> names = new ArrayList<>();
  43. try {
  44. in = u.openStream();
  45. r = new BufferedReader(new InputStreamReader(in, "utf-8"));
  46. int lc = 1;
  47. // 一行一行解析
  48. while ((lc = parseLine(service, u, r, lc, names)) >= 0);
  49. } catch (IOException x) {
  50. fail(service, "Error reading configuration file", x);
  51. } finally {
  52. try {
  53. if (r != null) r.close();
  54. if (in != null) in.close();
  55. } catch (IOException y) {
  56. fail(service, "Error closing configuration file", y);
  57. }
  58. }
  59. return names.iterator();
  60. }
  61. // 解析一行,将实现类的名字加到List中,并且返回加一的lc
  62. private int parseLine(Class<?> service, URL u, BufferedReader r, int lc,
  63. List<String> names)
  64. throws IOException, ServiceConfigurationError
  65. {
  66. String ln = r.readLine();
  67. if (ln == null) {
  68. return -1;
  69. }
  70. int ci = ln.indexOf('#');
  71. // 截取#之前的内容并且去除前后空格
  72. if (ci >= 0) ln = ln.substring(0, ci);
  73. ln = ln.trim();
  74. int n = ln.length();
  75. if (n != 0) {
  76. if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
  77. fail(service, u, lc, "Illegal configuration-file syntax");
  78. int cp = ln.codePointAt(0);
  79. if (!Character.isJavaIdentifierStart(cp))
  80. fail(service, u, lc, "Illegal provider-class name: " + ln);
  81. for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
  82. cp = ln.codePointAt(i);
  83. if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
  84. fail(service, u, lc, "Illegal provider-class name: " + ln);
  85. }
  86. // 主要是这里,将实现类名加到List中
  87. if (!providers.containsKey(ln) && !names.contains(ln))
  88. names.add(ln);
  89. }
  90. return lc + 1;
  91. }

4.next

加载实现类

  1. // next()调用nextService()
  2. public S next() {
  3. if (acc == null) {
  4. return nextService();
  5. } else {
  6. PrivilegedAction<S> action = new PrivilegedAction<S>() {
  7. public S run() { return nextService(); }
  8. };
  9. return AccessController.doPrivileged(action, acc);
  10. }
  11. }
  12. private S nextService() {
  13. if (!hasNextService())
  14. throw new NoSuchElementException();
  15. // 获取hasNextServcie()取出的实现类
  16. String cn = nextName;
  17. nextName = null;
  18. Class<?> c = null;
  19. try {
  20. // 加载实现类
  21. c = Class.forName(cn, false, loader);
  22. } catch (ClassNotFoundException x) {
  23. fail(service,
  24. "Provider " + cn + " not found");
  25. }
  26. if (!service.isAssignableFrom(c)) {
  27. fail(service,
  28. "Provider " + cn + " not a subtype");
  29. }
  30. try {
  31. S p = service.cast(c.newInstance());
  32. // 放到提供者列表中并返回加载的实现类
  33. providers.put(cn, p);
  34. return p;
  35. } catch (Throwable x) {
  36. fail(service,
  37. "Provider " + cn + " could not be instantiated",
  38. x);
  39. }
  40. throw new Error(); // This cannot happen
  41. }

发表评论

表情:
评论列表 (有 0 条评论,280人围观)

还没有评论,来说两句吧...

相关阅读

    相关 dubbo解析-SPI机制

     架构体系   框架介绍   概述   Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spri