跟踪load()
方法发现其本质是创建了一个ServiceLoader
对象,其共有两个参数,分别是代加载的类父类(接口)Class
类对象和类加载器 。在构造方法中完成了两件事,一个是变量赋值,一个是调用reload()
方法 。reload()
方法则根据接口类型(父类)和类加载器初始化LazyIterator
当执行ServiceLoader#iterator()
时,会创建java.util.Iterator
匿名内部类实现:
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(); } }; }当执行hasNext()
方法时,会先去providers
查找已经加载的缓存实现,如果不存在,则会继续调用LazyIterator#hasNext()
用于发现尚未加载的实现,最后的实现在LazyIterator#hasNextService()
中
LazyIterator
的关键属性
// 缓存所有需要查找jar包(文件)路径,Enumeration<URL> configs = null;// 缓存所有被查找到的实现类全限定名Iterator<String> pending = null;// 迭代器使用,下一个需要被加载的类全限定名String nextName = null;hasNextService()
实现核心如下:
// 获取所由需要扫描的包路径configs = loader.getResources(fullName);// 循环扫描configs中所有的包路径,解析META-INF/services中的指定文件(上例中的cn.bmilk.chat.spi.Registry文件)//while ((pending == null) || !pending.hasNext()) { if (!configs.hasMoreElements()) { return false; } // pending缓存了所有查找到的类全限定名 pending = parse(service, configs.nextElement());}在知道是否存在接口的实现后,就是通过next()
方法获取实现,核心功能由nextService()
经验总结扩展阅读
- 九 Istio:istio安全之授权
- 分布式ID生成方案总结整理
- GCC 指令详解及动态库、静态库的使用
- 五 Istio:使用服务网格Istio进行流量路由
- pta第二次博客
- java中GC的日志认识详解
- 2023年摩羯座财运1月运程详解如何提高
- 即兴小探华为开源行业领先大数据虚拟化引擎openLooKeng
- JUC中的AQS底层详细超详解
- 图文详解 微服务 Zipkin 链路追踪原理