JDK-SPI-服务提供者接口

归档

SPI 源码说明

  • java.util.ServiceLoader
java 复制代码
/*** 服务加载器:给定接口,查找实现类。实现可迭代接口 */
public final class ServiceLoader<S> implements Iterable<S> {

    /*** 返回 ServiceLoader 实例 */
    public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader) {
        return 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;
        ...
        reload(); // (重新)加载
    }

    /*** 重新加载 */
    public void reload() {
        providers.clear(); // 清空
        lookupIterator = new LazyIterator(service, loader); // 创建懒加载迭代器
    }

    /*** 实现可迭代接口:返回迭代器 */
    @Override
    public Iterator<S> iterator() {
        /*** 一个新的迭代器实现。对懒加载迭代器 lookupIterator 进行封装 */
        return new Iterator<S>() {
            Iterator<Map.Entry<String, S>> knownProviders = providers.entrySet().iterator();
            ...
            public S next() { // 先从已加载的里面选
                if (knownProviders.hasNext())
                    return knownProviders.next().getValue();
                return lookupIterator.next(); // 最后才开始加载
            }
            ...
        };
    }

}
  • java.util.ServiceLoader.LazyIterator
java 复制代码
    /*** 懒加载-迭代器。实现迭代器接口 */
    private class LazyIterator implements Iterator<S> {

        /*** 构造器 */
        private LazyIterator(Class<S> service, ClassLoader loader) {
            this.service = service;
            this.loader = loader;
        }

        /*** 获取下一个服务实现对象 */
        public S next() {
            if (acc == null) {
                return nextService(); // 获取下一个服务实现对象
            } 
            ...
        }

        /*** 获取下一个服务实现对象 */
        private S nextService() {
            ...
            String cn = nextName; // 下一个服务实现类的类名。nextName 在 hasNextService() 方法里面设置
            Class<?> c = null;
            try {
                c = Class.forName(cn, false, loader); // 初始化类
            } catch (ClassNotFoundException x) {
                ...
            }
            ...
            try {
                S p = service.cast(c.newInstance()); // 实例化一个对象
                providers.put(cn, p); // 添加到提供者(providers)Map 里,方便上面的判断
                return p;
            }
            ...
        }

        /*** 判断是否有下一个服务 */
        private boolean hasNextService() {
            ...
            if (configs == null) {
                try {
                    // String PREFIX = "META-INF/services/";
                    String fullName = PREFIX + service.getName();
                    ...
                    configs = loader.getResources(fullName); // 加载所有的文件
                } 
                ...
            }
            while ((pending == null) || !pending.hasNext()) {
                if (!configs.hasMoreElements()) {
                    return false;
                }
                pending = parse(service, configs.nextElement()); // 逐个文件加载填充 pending
            }
            nextName = pending.next(); // 设置下一个要加载的类的类名
            return true;
        }
    }
相关推荐
TechLee24 分钟前
跨语言加解密总对不上?这个纯 Go 神库让 AES/RSA 与 PHP、Java 100% 互通
java·后端·算法
LINgZone228 分钟前
系统架构与分支规范
java·数据库·架构
AC赳赳老秦35 分钟前
企业级合规审计体系:用 OpenClaw 落地采集全链路留痕,自动生成合规审计报告
java·python·django·beautifulsoup·php·deepseek·openclaw
吃杠碰小鸡1 小时前
VsCode中开发Java项目
java·vscode
宠友信息2 小时前
内容社区源码开发实践解析,用Spring Boot打造1:1仿小红书源码平台
java·spring boot·redis·websocket·mysql·spring·uni-app
行百里er2 小时前
加个依赖就生效?一行搞定 Spring Boot Starter 自动装配
java·后端·监控
月华路2 小时前
G1 新生代对象晋升老年代:实现机制与 GC 日志
java·jvm·算法
AI人工智能+电脑小能手2 小时前
大白话说Java设计模式-34-命令模式(业务实战篇)
java·spring·设计模式·命令模式·异步任务·撤销重做·事务封装
净重21克3 小时前
万字长文!TLS协议升级避坑手册:JDK老项目适配TLS1.2/1.3全流程拆解
java·springboot·java安全