从运行结果中可以看到EurekaRegistry
和ZookeeperRegistry
都被实例化并且生成相应的对象 。但是我们全程并没有显示的加载和生成EurekaRegistry
和ZookeeperRegistry
类对象,那么是怎么来的呢?
SPI机制的实现SPI
机制的核心就是ServiceLoader
类 。其主要的属性如下:
// 指出接口配置文件的位置,也就是为什么要在META-INF/services/下创建接口的全限定名文件的原因 private static final String PREFIX = "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<>(); // The current lazy-lookup iterator private LazyIterator lookupIterator;load()
方法的实现如下:
public static <S> ServiceLoader<S> load(Class<S> service) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); // 使用当前线程的ClassLoader进行加载待加载的实现类 return ServiceLoader.load(service, cl); } public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader) { // load 方法本质是创建一个ServiceLoader对象 return new ServiceLoader<>(service, loader); } // new ServiceLoader<>(service, loader)的实现 private ServiceLoader(Class<S> svc, ClassLoader cl) { service = Objects.requireNonNull(svc, "Service interface cannot be null"); loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl; acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null; reload(); } public void reload() { providers.clear(); // 根据接口类型(父类)和类加载器初始化LazyIterator lookupIterator = new LazyIterator(service, loader); } private LazyIterator(Class<S> service, ClassLoader loader) { this.service = service; this.loader = loader; }跟踪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(); } }; }
推荐阅读
- 九 Istio:istio安全之授权
- 分布式ID生成方案总结整理
- GCC 指令详解及动态库、静态库的使用
- 五 Istio:使用服务网格Istio进行流量路由
- pta第二次博客
- java中GC的日志认识详解
- 即兴小探华为开源行业领先大数据虚拟化引擎openLooKeng
- JUC中的AQS底层详细超详解
- 图文详解 微服务 Zipkin 链路追踪原理
- JDK中自带的JVM分析工具