• Java加载资源文件时的路径问题


    今天偶然看到一篇关于tomcat加载servlet的文章,不由得想起了java加载资源文件的路径问题,资源文件可以使xml,properties,图片等,可以是任何文件。

    加载资源文件比较常用的有两种:

    一、用ClassLoader,说到这里就不得不提一下ClassLoader的分类,java内置的ClassLoader主要有三种,

    第一种是根类加载器(bootstrap class loader),用C++来编写,负责将一些关键的Java类,如java.lang.Object和其他一些运行时代码先加载进内存中。 所负责加载的包:BootStrp------>JRE/lib/rt.jar

    第二种是扩展类加载器(ExtClassLoader),由java类编写,负责将JRE中的一些类加载进内存中。所负责加载的包: ExtClassLoader---------->JRE/lib/ext/*.jar

    第三种是应用类加载器(AppClassLoader)或者叫做系统类加载器,负责将CLASSPATH中的类加载到内存中。可以通过ClassLoader.getSystemClassLoader()来获取应用类加载器;

     

    再来所说加类载器的继承,类加载器不是垂直继承的父子关系,而是一种组合关系,可以通过实例化类加载器时,将父类加载器的实例作为构造参数传到类加载器中。

    关于类加载器的详细资料,可以自行搜索。

    获取到应用类加载器之后,就是获取资源文件了,调用loader.getResource(path)可以加载相应路径下的资源文件,不能以‘/’开头,关于包内的资源可以把包当做普通的文件夹,以'/'分隔每个包。

    如:URL url2 =  ClassLoader.getSystemClassLoader().getResource("demo/names.ser");是获取demo包内的names.ser序列化文件。

    二、用需要加载的当前类的getResource方法来加载,其实这个方法也是调用的加载这个类的类加载器来获得资源文件的,只不过是获取的参数不同。

     (1)要想获取class所在包内的文件可以用相对路径直接访问包内的资源;如:Demo1.class.getResource("names.ser");获取的是Demo1的class文件所在包内的资源

     (2)要想获取包外的资源文件必须以‘/’开头,如URL url = Demo1.class.getResource("/demo/names.ser");获取的是demo包内的names.ser文件

    其实第二种方式是对第一种方式的一个封装,都是用的ClassLoader来加载的资源文件。为什么这么说呢?看一下Class类的源码就知道:

    1  public java.net.URL getResource(String name) {
    2         name = resolveName(name);
    3         ClassLoader cl = getClassLoader0();
    4         if (cl==null) {
    5             // A system class.
    6             return ClassLoader.getSystemResource(name);
    7         }
    8         return cl.getResource(name);
    9     }
     1  private String resolveName(String name) {
     2         if (name == null) {
     3             return name;
     4         }
     5         if (!name.startsWith("/")) {
     6             Class c = this;
     7             while (c.isArray()) {
     8                 c = c.getComponentType();
     9             }
    10             String baseName = c.getName();
    11             int index = baseName.lastIndexOf('.');
    12             if (index != -1) {
    13                 name = baseName.substring(0, index).replace('.', '/')
    14                     +"/"+name;
    15             }
    16         } else {
    17             name = name.substring(1);
    18         }
    19         return name;
    20     }

    getResource根据传进来的name值(即相对路径或者绝对路径的形式),我们看到经过resolveName处理之后就调用了ClassLoader c1进行了加载,ClassLoader的加载路径的形式是不以‘/’开头的相对路径,那肯定是resolveName把路径转换了一把,再看看resolveName方法,首先判断是不是以‘/’开头,如果以‘/’开头,则为相对路径,否则就是绝对路径,注意else这个代码块,它将第一个字符去除掉了,确实去除掉之后就符合了ClassLoader的加载路径,而if块中就根据把当前类的包路径截取,然后将.替换成了'/',并添加上那段相对路径,也形成了符合ClassLoader的加载路径。

    看了这些代码之后,才能在实际应用中心里有底啊。

  • 相关阅读:
    (转)三款Json查看小工具
    开源数据源
    关于异常
    java 线程池
    百度android面试及一些问题的讲解
    linux常用命令
    android activityManager
    Android ListView及其属性
    android listView与adapter
    android 反编译
  • 原文地址:https://www.cnblogs.com/lmtoo/p/2729272.html
Copyright © 2020-2023  润新知