Java命名模块项目中getResource两种调用方式差异及返回null原因分析
核心原因:Java 9+ 命名模块的资源访问封装规则限制
注意:本项目为Java命名模块(named-module)项目
两种调用的底层逻辑差异如下:
第一种调用成功的原因
ClassNameOne.class.getResource("/resPath/tmp.txt") 是用mod-one模块自身的类ClassNameOne,访问同属于mod-one模块下的资源,不受模块封装规则限制,只要路径正确就能正常返回对应URL。
第二种调用返回null的原因
虽然你传入了mod-one的ClassNameOne.class作为参数,但getCustomRes方法是定义在mod-two模块中,属于跨模块访问mod-one的资源。
Java命名模块的资源访问规则明确要求:跨模块访问其他模块的资源时,被访问的模块必须主动开放对应资源目录的访问权限给调用方模块,否则JVM会直接拦截访问请求返回null,和资源路径是否正确无关。
两种常用修复方案
- 方案一:在mod-one的
module-info.java中开放对应资源目录给mod-two,添加如下配置即可:// mod.two替换为你mod-two模块的实际声明名称 opens resPath to mod.two; - 方案二:调整资源获取逻辑,改用类加载器绕开模块资源访问限制,修改
getCustomRes的逻辑:
类加载器是在整个模块路径下全局搜索资源,不受模块封装规则限制,只要资源在类路径/模块路径下存在就能正常返回。// 类加载器的getResource方法无需加开头的斜杠,直接传相对类路径的路径即可 url = sourceClass.getClassLoader().getResource(sourcePath);
补充命名模块资源访问通用规则
- 模块内类访问自身模块的资源:无任何限制
- 跨模块访问其他模块的资源:被访问模块必须通过
opens指令开放对应目录给调用方模块 - 用
ClassLoader.getResource/getResourceAsStream获取资源:不受模块封装规则限制,全局搜索所有可加载的资源
内容的提问来源于stack exchange,提问作者Liveon Phoenix
相关产品推荐
相关产品推荐

