You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用自定义类加载器从模块层加载服务提供者并解决加载异常

自定义模块层+自定义类加载器下ServiceLoader加载服务提供者失败问题

错误信息

Exception in thread "main" java.util.ServiceConfigurationError: client.MyInterface: Provider implementation.MyInterfaceImpl not found

相关代码

ClassLoader classLoader = new CustomClassLoader();
String module = "implementation";
Path dir = Path.of("/path/to/lib.jar");
ModuleFinder finder = ModuleFinder.of(dir);
ModuleLayer parent = ModuleLayer.boot();
Configuration conf = parent.configuration().resolve(finder, ModuleFinder.of(), Set.of(module));
ModuleLayer layer = parent.defineModules(conf, (String name) -> classLoader);

//layer.findLoader(module).loadClass("implementation.MyInterfaceImpl");


ServiceLoader<MyInterface> loader = ServiceLoader.load(layer, MyInterface.class);
Iterator<MyInterface> iterator = loader.iterator();
for(MyInterface impl: loader){
    impl.doSomething();
}

问题背景

目前通过手动添加 layer.findLoader(module).loadClass("implementation.MyInterfaceImpl"); 可以绕过错误,但不想采用这种方式——因为不想在编译时硬编码实现类的全限定名。需要明确:

  1. 该错误的根本原因是什么?
  2. 为什么ServiceLoader没有自动调用模块层对应的类加载器加载提供者类?

问题原因分析

这个问题的核心是自定义类加载器逻辑与ServiceLoader的预期不匹配,具体分为两点:

  1. 自定义类加载器的实现缺陷
    你指定的CustomClassLoader如果没有正确实现类加载逻辑,比如未正确从目标JAR中查找类、委托顺序违背双亲委派模型,会导致ServiceLoader尝试加载提供者类时,类加载器无法定位到目标类。ServiceLoader依赖模块层关联的类加载器完成类加载,但如果自定义加载器的路径搜索、委托逻辑出错,自然找不到类。

  2. 模块配置与ServiceLoader懒加载的冲突
    ServiceLoader是懒加载机制,只有遍历迭代器时才会触发提供者类加载。而手动调用loadClass是直接通过模块层加载器明确触发类加载,绕过了ServiceLoader内部可能存在的类路径或模块可见性问题。另外,如果模块描述符(module-info.java)配置错误——比如服务接口模块未声明uses、提供者模块未声明provides,ServiceLoader根本无法通过模块系统发现提供者,进而触发找不到类的错误。

解决方法

  1. 修正自定义类加载器实现
    确保CustomClassLoader的findClass方法能正确从/path/to/lib.jar中读取并加载类,同时遵循双亲委派模型(特殊需求除外):先委托父类加载器尝试加载,再自行加载模块内的类。可以在加载逻辑中添加日志,验证请求加载implementation.MyInterfaceImpl时,类加载器是否能访问到目标JAR。

  2. 检查模块描述符配置

    • 服务接口所在模块(client模块)的module-info.java需声明服务:
      module client {
          exports client.MyInterface;
          uses client.MyInterface;
      }
      
    • 服务提供者所在模块(implementation模块)的module-info.java需声明提供服务:
      module implementation {
          requires client;
          provides client.MyInterface with implementation.MyInterfaceImpl;
      }
      

    模块配置错误会导致ServiceLoader无法通过模块系统发现提供者,直接引发类找不到的错误。

  3. 确认模块层与类加载器的关联
    在调用parent.defineModules(conf, (String name) -> classLoader)时,要确保返回的CustomClassLoader确实关联了目标模块的JAR路径,避免出现类加载器与模块资源脱节的情况。

内容的提问来源于stack exchange,提问作者JasonBourne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 15:17:38