V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xiaopanzi
V2EX  ›  Java

关于 Java EE 中 ClassLoader 获取资源路径问题

  •  
  •   xiaopanzi · 2021-05-23 21:44:50 +08:00 · 1574 次点击
    这是一个创建于 1315 天前的主题,其中的信息可能已经有所发展或是发生改变。

    下面均假设资源文件均在main目录下面的resources里面:

    在 Java SE 中,如果使用ClassLoader.getResource获取资源(包括ClassLoader.getResourceAsStream,下面不再重复),其路径不能以"/"开头。换言之,如果有个foo.txt的话,代码

    getClass().getClassLoader().getResource("/foo.txt")
    

    将返回null

    但是我发现,如果在 Java EE 项目中,同样的情况,加不加"/"均能正常获取资源文件,这是为什么?


    环境

    • OpenJDK 11
    • Tomcat 9
    • Servlet 4.0
    8 条回复    2021-05-24 12:14:26 +08:00
    xiaopanzi
        1
    xiaopanzi  
    OP
       2021-05-23 22:16:21 +08:00
    隐约找到了一个很可能的[解释]( https://stackoverflow.com/questions/2653322/getresourceasstream-not-loading-resource-in-webapp#comment5040719_2653353):大体的意思是 Tomcat 8 及之后,`WebAppClassloader` 能够同时处理带或者不带“/”的路径;而在 Tomcat 7 之前,仅能处理不带“/”的路径。显然,JDK 本身的`Classloader`还是只能处理不带“/”的路径。

    但是对 Java EE 中这个`WebAppClassloader`相关类加载的东西还不是很懂,也没见到靠谱资料,是否有懂行的大佬推荐点相关资料?
    israinbow
        2
    israinbow  
       2021-05-23 22:25:09 +08:00
    ide 的项目结构配置问题
    xiaopanzi
        3
    xiaopanzi  
    OP
       2021-05-23 22:28:01 +08:00
    @israinbow 能具体解释吗?我上面找到那个新版本 Tomcat 能够处理带“/”的路径的解释有问题吗?我也只是看到那个答案,不清楚具体情况?
    israinbow
        4
    israinbow  
       2021-05-23 23:18:37 +08:00
    @xiaopanzi 以前在 idea 里遇见过一次, 印象里是 javaEE 的项目结构配置把路径映射了.tomcat 的解释是正确的, 使用 tomcat 会认定你的 java/src 目录是服务器里的某一个位置, 而不是 java 源代码的资源位置, tomcat7 和 8 的区别可以在更新日志里查到. 目前我个人对路径问题的解决方案: 转义符, 或首目录不加 / ,比如 "test/subtest/file.file". 参考文章: blog.csdn.net/aitangyong/article/details/36471881 以及
    blog.csdn.net/mycomputerxiaomei/article/details/24472023
    ikas
        5
    ikas  
       2021-05-23 23:20:04 +08:00
    这个就是 tomcat 自己实现问题.你应该按照正常得写法,不带 /,具体你可以看 tomcat 源码,在 9 中,他内部实现: private String nameToPath(String name) {
    if (name.startsWith("/")) {
    return name;
    }
    StringBuilder path = new StringBuilder(
    1 + name.length());
    path.append('/');
    path.append(name);
    return path.toString();
    }
    xiaopanzi
        6
    xiaopanzi  
    OP
       2021-05-24 09:26:47 +08:00
    @ikas 是的,后来我也看了 tomcat 的代码,定位到这个函数。多谢!
    xiaopanzi
        7
    xiaopanzi  
    OP
       2021-05-24 09:32:06 +08:00
    @israinbow 我觉得你的理解有部分误区。resources 里面的文件最后还是在 WEB-INF/classes 下面。终极原因是 tomcat 重写了 JDK 的 classloader 的代码,其中关键代码之一就是下面那位同学指出的 nameToPath 。换言之,你不加 /它反倒给你加上 /,用于拼接字符串放在“WEB-INF/classes”后面构成完整合法的路径。我说的“下面均假设资源文件均在 main 目录下面的 resources 里面”是标准的 Maven 工程结构。
    israinbow
        8
    israinbow  
       2021-05-24 12:14:26 +08:00
    @xiaopanzi 的确, 我仔细看了一遍问题描述后觉得我的回答并不妥当, 但是楼下已经回答出要点了, 所以我也没有跟进( 对我的误导向你道歉
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1019 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 19:42 · PVG 03:42 · LAX 11:42 · JFK 14:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.