自定义ClassLoader加载模块后,模块间类访问抛出ClassNotFoundException
模块间类加载失败(ClassNotFoundException)的原因与解决方案
核心原因分析
- 类加载器的隔离特性:每个自定义
MyModuleClassLoader实例默认相互隔离。模块A的类由专属类加载器加载,模块B的类加载器无法直接访问同级的模块A类加载器加载的类——类加载器可见性遵循父→子层级,同级加载器间默认无访问权限。 - 未处理模块间依赖加载关系:加载模块B时,未将模块A的类加载器纳入委托链,导致模块B查找类时,仅从自身类路径和父加载器(核心应用类加载器)搜索,无法定位模块A的类。
- 模块类路径缺失依赖项:模块B的
classpath未包含模块A的Jar路径,自身类加载器自然找不到对应类。
可行解决方案
1. 构建类加载器层级依赖
加载模块B时,将模块A的类加载器作为模块B类加载器的父加载器,让模块B的类加载器优先委托父加载器查找类:
// 假设已加载模块A的类加载器 moduleAClassLoader MyModule moduleB = new MyModuleClassLoader(moduleAClassLoader).loadClass( f.getPath(), moduleConfig.classpath, MyModule.class );
2. 实现类加载器协作查找机制
自定义MyModuleClassLoader,重写findClass方法,自身无法加载类时,主动遍历其他已加载模块的类加载器尝试查找:
public class MyModuleClassLoader extends ClassLoader { private final List<ClassLoader> dependentLoaders = new ArrayList<>(); // 添加依赖的模块类加载器 public void addDependentLoader(ClassLoader loader) { dependentLoaders.add(loader); } @Override protected Class<?> findClass(String className) throws ClassNotFoundException { try { // 优先尝试自身加载 return super.findClass(className); } catch (ClassNotFoundException e) { // 遍历依赖加载器尝试加载 for (ClassLoader loader : dependentLoaders) { try { return loader.loadClass(className); } catch (ClassNotFoundException ignored) {} } throw e; } } }
使用时先加载模块A,再将其类加载器添加到模块B的类加载器依赖列表:
MyModuleClassLoader moduleBLoader = new MyModuleClassLoader(); moduleBLoader.addDependentLoader(moduleALoader); MyModule moduleB = moduleBLoader.loadClass( f.getPath(), moduleConfig.classpath, MyModule.class );
3. 统一模块类路径
若模块依赖关系明确,加载模块B时将模块A的Jar路径加入moduleConfig.classpath,让模块B的类加载器直接从自身类路径找到模块A的类。
内容的提问来源于stack exchange,提问作者BrokenStudio
相关产品推荐
相关产品推荐

