使用ClassLoader加载包内的资源

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

使用CL加载资源

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

image1

如果要加载test.properties。getResourceAsStream的参数就是“classloader/getresource/deeper/test2.properties”。

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

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

使用Class加载资源文件

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

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

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

Class类也是使用CL去加载资源的。它所做的事情就是将参数修订成CL需要的格式。变化都在Class类的resolveName方法中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * Add a package name prefix if the name is not absolute Remove leading "/"
 * if name is absolute
 */
private String resolveName(String name) {
    if (name == null) {
        return name;
    }
    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;
}

方法含义很简单

  • 对于不是以“/”开头的参数,就认为这个路径是相对于当前类的路径,所以加载当前包中的资源只要写资源文件的名字就可以了。方法最大的一块代码就是为了得到当前类的路径,然后和传进来的相对路径参数拼起来,作为资源文件的绝对路径丢给CL。
  • 对于以“/”开头的参数,就认为参数是资源文件的绝对路径,将这个斜线去掉之后,丢给CL去加载就行了。

同样,这个方法的参数同样接受“..”来返回上一层目录。

例程

参照下面的图

image2

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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"));
 
    }
 
}
posted @   深夜两点  阅读(3018)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
点击右上角即可分享
微信分享提示