java ClassLoader 类加载资源详解

     ClassLoader可以把包(jar包,war包)内的class文件加载到JVM中,第一步就是将class文件以stream的方式读取出来。ClassLoader也将这个加载资源的方法getResourceAsStream暴露了出来。编程时可以使用这个方法来加载包内的任何资源,比如properties文件,图片等。

使用ClassLoader加载资源

当使用ClassLoader加载资源的时候,参数应该是资源文件在包内的路径,不以“/”开头,即使用绝对路径这里的绝对路径是classpath。对于下面的package结构:

image2

如果要加载test2.properties这个文件,getResourceAsStream的参数就是“classloader/getresource/deeper/test2.properties”。

ClassLoader可以加载任何一个在classpath上存在的资源文件,可以不是一个package内,也可以不在一个包内。简单来说,只要把资源文件也当作一个类来看待,把类的全路径名中的“.”换成“/”就可以了。

getResourceAsStream的参数也可以有“..”,用来回到上一层目录。

使用Class加载资源

Class类也有一个getResourceAsStream方法。对于同一个包中的资源文件,使用Class加载资源文件会更简单。

比如上图中,如果GetResourceInCurrentPkg类想加载test.properties,只要使用下面的代码就行了。

GetResourceInCurrentPkg.class.getResourceAsStream("test.properties")

实际上Class类的getResourceAsStream方法内部调用了,ClassLoader类的getResourceAsStream方法。Class类的getResourceAsStream方法

源码如下:

 public InputStream getResourceAsStream(String name) {

        //调用resolveName方法对资源名进行解析
        name = resolveName(name);

        //返回当前类的ClassLoader
        ClassLoader cl = getClassLoader0();
        if (cl==null) {
            // A system class.
            return ClassLoader.getSystemResourceAsStream(name);
        }

       //调用当前类的ClassLoader的getResourceAsStream方法
        return cl.getResourceAsStream(name);
   }

再来看看 Class类resolveName方法的源码

 /**
     * Add a package name prefix if the name is not absolute Remove leading "/"
     * if name is absolute
     */
    private String resolveName(String name) {

        //当资源名为null时直接返回null
        if (name == null) {
            return name;
        }

   /*

       ***

          当资源名不以"/"开始时,对资源名进行解析,上例中的name="test.properties",经解析结果为

          name="classloader/getresource/test.properties",即在前面加上了类所在包的路径。
       ***

  */

  if (!name.startsWith("/")) {
            Class c = this;
            while (c.isArray()) {
                c = c.getComponentType();
            }
            String baseName = c.getName();
            int index = baseName.lastIndexOf('.');
            if (index != -1) {
                name = baseName.substring(0, index).replace('.', '/')
                    +"/"+name;
            }

      //当资源名以"/"开始时,将"/"去掉,返回其后面的部分。
        } else {
            name = name.substring(1);
        }
        return name;
    }

参照下面的图

image2

下面的示例代码可以成功加载资源

package classloader.getresource;
 
import java.io.IOException;
import java.util.Properties;
public class GetResourceInCurrentPkg {
 
    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        // using Class.getResourceAsStream, the default location is the package
        // of current class. It is an instance method, so every instance know
        // that where is the class, and which package it is, and which class
        // loader to
        // use. It is a relative path.
        Properties props = new Properties();
 
        props.load(GetResourceInCurrentPkg.class
                .getResourceAsStream("../getresource/test.properties"));
        System.out.println(props.get("test"));
         
        props = new Properties();
 
        props.load(GetResourceInCurrentPkg.class
                .getResourceAsStream("test.properties"));
        System.out.println(props.get("test"));
 
        props = new Properties();
        props.load(GetResourceInCurrentPkg.class
                .getResourceAsStream("deeper/test2.properties"));
        System.out.println(props.get("test2"));
 
        // if the path start with /, then it means the path is absolute path.
        props = new Properties();
        props.load(GetResourceInCurrentPkg.class
                .getResourceAsStream("/classloader/getresource/deeper/test2.properties"));
        System.out.println(props.get("test2"));
 
        // Using class loader, it is always the absolute path.
        props = new Properties();
        props.load(GetResourceInCurrentPkg.class.getClassLoader()
                .getResourceAsStream(
                        "classloader/getresource/deeper/test2.properties"));
        System.out.println(props.get("test2"));
 
    }
 
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值