【IO】getResourceAsStream小记

    J2SE中资源的加载,隶属IO的范畴,这是一个老生常谈的问题。

    1. 先看一个相关测试的小demo,其资源和项目结构如下图。


    2. 测试源码及注释如下,这一部分请集合下文分析来看。

package cn.wxy.res.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.junit.Before;
import org.junit.Test;

/**
 * @Title ResLoader.java
 * @Package cn.wxy.res.test
 * @Description
 * @author wxy51
 * @date 2016年8月2日 下午4:56:59
 * @version V1.0
 */
public class ResLoader {
	/**
	 * 打印JVM启动时设置的CLASSPATH值
	 */
	@Before
	public void setUp() {
		String classpath = (String) System.getProperties().get("java.class.path");
		// 输出结果:D:\dev_code\workspace_luna3\res\bin;
		System.out.println(classpath);
	}

	/**
	 * Class相对路径资源加载测试
	 */
	@Test
	public void testClass() {
		// ResLoader.class的package是cn.wxy.res.test
		// 对于a文件而言,其最终的资源名是package+name
		// 对于b文件而言,如果资源加载目录不往上跳,则最终b资源名为cn/wxy/res/test/b.propertes
		// 所以为了得到正确的资源名,应该把自动添加的ResLoader.class的package名去掉
		// cn/wxy/res/test/../../../../b.propertes
		InputStream aIS = ResLoader.class.getResourceAsStream("a.properties");
		InputStream bIS = ResLoader.class.getResourceAsStream("../../../../b.properties");

		printResult(aIS, bIS);
	}
	/**
	 * Class资源加载绝对路径测试
	 */
	@Test
	public void testClassAbsolutePath(){
		InputStream aIS = ResLoader.class.getResourceAsStream("/cn/wxy/res/test/a.properties");
		InputStream bIS = ResLoader.class.getResourceAsStream("/b.properties");
		
		printResult(aIS, bIS);
	}
	/**
	 * ClassLoader资源加载相对路径测试
	 */
	@Test
	public void testClassLoader() {
		// 对于这一部分的内容,参看setUp中System.getProperties().get("java.class.path");
		// JVM启动的时候,会设置一些系统环境变量,其中CLASSPATH可以通过“java.lang.path”获取到
		// 对于本例中ClassLoader的工作目录即是java.class.path的value
		// java.class.path = D:\dev_code\workspace_luna3\res\bin;
		// 因此对于a文件需要补充包名,对于b文件直接写即可
		InputStream aIS = ResLoader.class.getClassLoader().getResourceAsStream("cn/wxy/res/test/a.properties");
		InputStream bIS = ResLoader.class.getClassLoader().getResourceAsStream("b.properties");
		
		printResult(aIS, bIS);
	}
	
	private void printResult(InputStream aIS, InputStream bIS) {
		Properties p = new Properties();
		// 测试a
		try {
			p.load(aIS);
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println(p.get("res")); // 输出a_file
		// 测试b
		try {
			p.load(bIS);
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println(p.get("res")); // 输出b_file
	}
}


一、java.lang.Class的getResourceAsStream

    其实java.lang.Class.getResourceAsStream(String name)方法加载资源的实现就是依靠java.lang.ClassLoader,只不过是稍微包装了一下(使得该方法支持绝对路径加载资源,即以“/”开头,因为ClassLoader只支持相对路径而不支持绝对路径),主要关注的是resolveName方法。



    这一部分的逻辑大概两个步骤:

    1. 如果入参name不是以"/"开头(即相对路径),那么在resolveName的时候,把Class的包名取出来加上入参name作为资源名,然后通过类加载器加载资源;

    2. 如果入参name是以"/"开头(即绝对路径),那么在resolveName的时候去掉开头的"/"作为资源名,然后通过类加载器加载资源;

    这两种方法,最终得到的都是相对路径的资源名(即不以“/”开头),因为其底层实现ClassLoader不支持绝对路径。


二、java.lang.ClassLoader的getResourceAsStream

    这一部分在源码中并没有太多可以看的地方,主要关注点在JVM启动时会设置环境变量CLASSPATH,可以通过System.getProperties().get("java.class.path")方法来获取,一般情况下,这个值就是当前应用的bin目录,参见上文测试的小demo中setUp方法。

    ClassLoader资源加载的原理也比较简单,最主要要关注的是该方式是不支持绝对路径的,因为ClassLoader会直接定位到CLASSPATH所在目录,然后在该目录的基础上进行资源的加载,因此该方式不支持绝对路径,即不支持以“/”开头。



三、Tomcat环境

    对于tomcat服务器环境,最主要的变化是classpath为"/WEB-INF/classes/"目录,因此Class和ClassLoader在web环境下的加载,除了classpath不一样之外,其他并无不同,和一般J2SE应用保持一致。

四、未提及

    后续抽时间把Tomcat中的资源加载捋一捋,主要是ServletContext的两个方法getRealPath和getResourceAsStream。


附注:

    本文如有错漏,烦请不吝指正,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值