运行结果
class cn.bmilk.chat.spi.EurekaRegistrycn.bmilk.chat.spi.EurekaRegistry@12a3a380registry , host = 127.0.0.1 port = 10086class cn.bmilk.chat.spi.ZookeeperRegistrycn.bmilk.chat.spi.ZookeeperRegistry@29453f44registry , host = 127.0.0.1 port = 10086从运行结果中可以看到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; }
经验总结扩展阅读
- 九 Istio:istio安全之授权
- 分布式ID生成方案总结整理
- GCC 指令详解及动态库、静态库的使用
- 五 Istio:使用服务网格Istio进行流量路由
- pta第二次博客
- java中GC的日志认识详解
- 2023年摩羯座财运1月运程详解如何提高
- 即兴小探华为开源行业领先大数据虚拟化引擎openLooKeng
- JUC中的AQS底层详细超详解
- 图文详解 微服务 Zipkin 链路追踪原理