• ClassLoader.getSystemResourceAsStream("a.txt")获取不到资源文件


    一、解决方案

    换成XXX.class.getClassLoader().getResourceAsStream("a.txt")即可。

    二、场景复现

    src/main/resource下存在文件a.txt,项目类中static 方法中读取该文件。ClassLoader.getSystemResourceAsStream("a.txt")获取不到资源文件

    三、原因剖析

    getResourceAsStream会先使用本类的类加载器去加载,本类没有类加载器,才会使用系统类加载器。也就是说getResourceAsStream功能覆盖了getSystemResourceAsStream,所以推荐直接使用getResourceAsStream就完事了都不需要知道具体两者有啥区别。

    下面我们来细看有啥区别....

    3.1 java类加载器

    • 1.启动类加载器Bootstrap ClassLoader):顶层的类加载器,没有父类加载器。负责加载 /lib 目录下的,或被 -Xbootclasspath 参数所指定路径中的,并被 JVM 识别的(仅按文件名识别,如 rt.jar,名字不符合的类库即使放在 lib 目录也不会被加载)类库加载到虚拟机内存中。所有被 Bootstrap classloader 加载的类,它的 Class.getClassLoader 方法返回的都是 null,所以也称作 NULL ClassLoader。
    • 2.扩展类加载器Extension CLassLoader):由 sun.misc.Launcher$ExtClassLoader 实现,负责加载 <JAVA_HOME>/lib/ext 目录下,或被 java.ext.dirs 系统变量所指定的目录下的所有类库;
    • 3.应用程序类加载器Application/System ClassLoader):由 sun.misc.Launcher$AppClassLoader 实现。它是 ClassLoader.getSystemClassLoader() 方法的默认返回值,所以也称为系统类加载器(System ClassLoader)。它负责加载 classpath 下所指定的类库,如果应用程序没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

    3.2 tomcat容器下类加载器

    Tomcat官方说明:Class Loader HOW-TO

    跟普通的java程序相比,类加载大体顺序相同。

    • 1.Bootstrap 启动类加载器: 加载JVM启动所需的类+系统扩展目录($JAVA_HOME/jre/lib/ext)里 JAR 文件中的类。
    • 2.System 系统类加载器:从 CLASSPATH 系统变量指定的目录中加载类库。该加载器加载的类对 tomcat 本身和 web 应用都可见。但是,标准的 tomcat 启动脚本($CATALINA_HOME/bin/catalina.sh or %CATALINA_HOME%incatalina.bat)都会忽略系统变量 CLASSPATH 的值,而会使用如下的类库来创建 System 类加载器:

              $CATALINA_HOME/bin/bootstrap.jar

            $CATALINA_BASE/bin/tomcat-juli.jar 或 $CATALINA_HOME/bin/tomcat-juli.jar

            $CATALINA_HOME/bin/commons-daemon.jar

    • 3.Common 通用类加载器:通过该类加载器加载的类库可被 Tomcat 和所有应用共享。该类加载器的搜索位置是通过 $CATALINA_BASE/conf/catalina.properties 文件中的 common.loader 属性指定的,默认包括如下位置:

            $CATALINA_BASE/lib 下未打包的类和资源;

            $CATALINA_BASE/lib 下的 jar 包;

            $CATALINA_HOME/lib 下未打包的类和资源;

            $CATALINA_HOME/lib 下的 jar 包。

    • 4.WebappX 应用类加载器:每个 Web 应用创建一个自己的类加载器,加载自己项目下的数据: /WEB-INF/classes 和 /WEB-INF/lib 下的类和资源。并且不使用双亲委派机制,先自己加载,加载不到才使用父类加载器。

    本来顺序是1234,但是WebappX不使用委派机制而是先自己加载,加载不了才使用父类,所以真实的顺序是:

    • Bootstrap classes of your JVM
    • /WEB-INF/classes of your web application
    • /WEB-INF/lib/*.jar of your web application
    • System class loader classes (described above)
    • Common class loader classes (described above)

    tomcat8支持委托:配置允许委派:<Loader delegate="true"/>,顺序变为:

    • Bootstrap classes of your JVM
    • System class loader classes (described above)
    • Common class loader classes (described above)
    • /WEB-INF/classes of your web application
    • /WEB-INF/lib/*.jar of your web application

    3.3 问题回归

    tomcat容器中运行的java程序,使用系统类加载器是不能获取到资源的,必须使用WebappClassLoader。使用getResourceAsStream获取当前类的类加载器,也就是WebappClassLoader,自然可以获取到资源了。


    =======参考=========

    https://blog.csdn.net/w1196726224/article/details/54428493

  • 相关阅读:
    活动的生命周期
    活动
    开始编程前的准备工作
    数组转List
    Word根据模板生成数据
    Excel根据模板生成数据
    php取年份区间
    世界 国家 省份 sql
    相册处理,php中获取一组前缀相同的元素值
    mysql添加字段
  • 原文地址:https://www.cnblogs.com/dennyzhangdd/p/11387200.html
Copyright © 2020-2023  润新知