使用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,只要使用下面的代码就行了。

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

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

    /**
     * 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

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

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 @ 2011-06-12 13:09  深夜两点  阅读(3010)  评论(0编辑  收藏  举报