项目中, 有时候要读取当前classpath下的一些配置文件. 之前用的读取配置文件的代码如下

    public static Properties loadPropertiesFile(String fileName){
Properties prop = new Properties(); InputStream inStream = ClassLoader.getSystemResourceAsStream(fileName);
if(null!=inStream){
try {
prop.load(inStream);
} catch (IOException e) {
e.printStackTrace();
}
}
return prop;
}

使用的方式是 ClassLoader.getSystemResourceAsStream(fileName)获取这个fileName对应的properties文件的输入流, 然后用prop对象的load方法. 用在生产环境的jstorm中一切正常, 但是切换到测试环境的jstorm后发现inStream总是null.

后来改使用如下方式, 在不同环境下都能正常使用了:

    public static Properties loadPropertiesFile(String fileName){
Properties prop = new Properties(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream inStream = classLoader.getResourceAsStream(fileName);
if(null!=inStream){
try {
prop.load(inStream);
} catch (IOException e) {
e.printStackTrace();
}
}
return prop;
}

从当前线程获取到载入这个类的classloader, 然后再通过这个classloader来获取配置文件的InputStream. 到这里还是很不解,为啥会有这样的问题.于是从网上众多方法中选出几个来分析一下.

下面是测试代码,尝试读取程序跟目录的一个叫business.properties文件. 这个类是放在tomcat里运行的Restlet, 可以看成是一个简单restful接口. 除此之外我还加了个main方法, 用来不是在tomcat的环境里运行,而是直接运行常规Java程序那样运行的.

@Path(value = "/test")
public class TestCode {
public static void main(String[] args){
TestCode tc = new TestCode();
tc.testcode(); } @GET
@Produces(MediaType.TEXT_PLAIN)
@Path(value = "getPath")
public String testcode(){
     //方法1
URL url1 = ClassLoader.getSystemResource("business.properties");
System.out.println("url1:\t" + (url1 == null ? "null" : url1.getPath())); URL url1withSlash = ClassLoader.getSystemResource("/business.properties");
System.out.println("url1/:\t" + (url1withSlash == null ? "null" : url1withSlash.getPath()));
     //方法2
ClassLoader classLoader2 = this.getClass().getClassLoader();
URL url2 = classLoader2.getResource("business.properties");
System.out.println("url2:\t" + (url2 == null ? "null" : url2.getPath())+";classLoader is:"+classLoader2.toString()); URL url2withSlash = classLoader2.getResource("/business.properties");
System.out.println("url2/:\t" + (url2withSlash == null ? "null" : url2withSlash.getPath()));

//方法3
URL url3 = this.getClass().getResource("business.properties");
System.out.println("url3:\t" + (url3 == null ? "null" : url3.getPath())); URL url3withSlash = this.getClass().getResource("/business.properties");
System.out.println("url3/:\t" + (url3withSlash == null ? "null" : url3withSlash.getPath()));

//方法4
ClassLoader classLoader4 = Thread.currentThread().getContextClassLoader();
URL url4 = classLoader4.getResource("business.properties");
System.out.println("url4:\t" + (url4 == null ? "null" : url4.getPath())+";classLoader is:"+classLoader4.toString()); URL url4withSlash = classLoader4.getResource("/business.properties");
System.out.println("url4/:\t" + (url4withSlash == null ? "null" : url4withSlash.getPath()));
return "OK";
}
}

下面看下通过tomcat运行和直接运行main方法输出内容的区别.

通过main方法,直接运行程序,输出结果是:

url1: /D:/thomas-dev/Team-Building-master/target/classes/business.properties
url1/: null
url2: /D:/thomas-dev/Team-Building-master/target/classes/business.properties;classLoader is:sun.misc.Launcher$AppClassLoader@7d05e560
url2/: null
url3: null
url3/: /D:/thomas-dev/Team-Building-master/target/classes/business.properties
url4: /D:/thomas-dev/Team-Building-master/target/classes/business.properties;classLoader is:sun.misc.Launcher$AppClassLoader@7d05e560
url4/: null

通过tomcat运行, 然后访问这个restful接口, 执行的结果是:

url1: null
url1/: null
url2: /D:/apache-tomcat-8.0.33/webapps/ROOT/WEB-INF/classes/business.properties;classLoader is:WebappClassLoader
context: ROOT
delegate: false
----------> Parent Classloader:
java.net.URLClassLoader@1ae8873a

url2/: /D:/apache-tomcat-8.0.33/webapps/ROOT/WEB-INF/classes/business.properties
url3: null
url3/: /D:/apache-tomcat-8.0.33/webapps/ROOT/WEB-INF/classes/business.properties
url4: /D:/apache-tomcat-8.0.33/webapps/ROOT/WEB-INF/classes/business.properties;classLoader is:WebappClassLoader
context: ROOT
delegate: false
----------> Parent Classloader:
java.net.URLClassLoader@1ae8873a

url4/: /D:/apache-tomcat-8.0.33/webapps/ROOT/WEB-INF/classes/business.properties

经过查询资料得知:

方法1:使用的是jvm的ClassLoader, 如果是直接运行的Java程序, 那么的确是调用jvm的ClassLoader, 于是调用的程序的根目录是可以获取这个文件的. 而在tomcat中,这个类并不是由系统自带的ClassLoader装载的, tomcat中而是由一个叫WebappClassLoader来装载的, jvm的ClassLoader取到的这文件是null

方法2: 获取加载当前类的ClassLoader, 这个ClassLoader会随着环境的变化而变化, 可以看到第一次直接运行的ClassLoader是jvm自带的classLoader is:sun.misc.Launcher$AppClassLoader@7d05e560, 而在tomcat中是WebappClassLoader,它的父级是java.net.URLClassLoader@1ae8873a, 都能获取到properties文件, 所以方法2是可行的.

方法3:直接从当前对象的类调用getResource方法, 刚进去就调用了resolveName方法, 这个resolveName方法,判断文件路径是以/ 开头还是./开头, 来确定是相对与当前class文件目录还是相对于程序根目录, 然后也会像方法2那样获取加载当前类的ClassLoader, 如果获取不到则使用系统自带的ClassLoader.. 这个方法比较智能,可以使用,但是跟其他方法相比, 需要加一个 /表示程序根目录.

方法4: 获取加载当前线程的ClassLoader,当前类是在当前线程调用的,则他们的ClassLoader对象是一样的, 可以看他们输出的ClassLoader的内存地址是一样的.

本次了解得也还是比较浅显,有一些深入问题没搞清楚, 以后深入了解ClassLoader之后再补充..

关于getSystemResource, getResource 的总结的更多相关文章

  1. getResource()和getSystemResource()分析

    1. getClass().getResource() 第一步,getClass().getResource(path)是有一个路径参数的,这个路径会先被转换成"类所在的包名称+path&q ...

  2. getResource(String name)用法及源码分析

    Project获取资源需要一个启点,加载资源的动作是由ClassLoader来完成的.Class对象和当前线程对象可以找到当前加载资源的ClassLoader,通过ClassLoader的getRes ...

  3. Class.getResource和ClassLoader.getResource的区别分析

    原文:http://swiftlet.net/archives/868 在Java中获取资源的时候,经常用到Class.getResource和ClassLoader.getResource,本文给大 ...

  4. 【知识碎片】getResource和getResourceAsStream

    1. 前言 在Java中获取资源的时候,经常用到getResource和getResourceAsStream,本文总结一下这两种获取资源文件的路径差异. 2.Class.getResource(St ...

  5. java: 关于从jar中读取资源遇到的问题getClass().getResource(...)

    在Java的程序发布中,很多人会选择采用二进制的jar的格式进行发布,怎么样读取Jar里面的资源呢?主要是采用ClassLoader的下面几个方法来实现:public URL getResource( ...

  6. Java获取路径(getResource)

    package com.zhi.test; public class PathTest { public static void main(String[] args) { System.out.pr ...

  7. getResource和getResourceAsStream

    1. 前言 在Java中获取资源的时候,经常用到getResource和getResourceAsStream,本文总结一下这两种获取资源文件的路径差异. 2.Class.getResource(St ...

  8. Class和ClassLoader的getResource方法对比

    最近在看写Spring的源代码,里面有好多地方都用到了Class和ClassLoader类的getResource方法来加载资源文件.之前对这两个类的这个方法一知半解,概念也很模糊,这边做下整理,加深 ...

  9. getResourceAsStream和getResource的用法及Demo实例

    用JAVA获取文件,听似简单,但对于很多像我这样的新人来说,还是掌握颇浅,用起来感觉颇深,大家最经常用的,就是用JAVA的File类,如要取得 D:/test.txt文件,就会这样用File file ...

随机推荐

  1. python3 练习题100例 (十四)

    今天逛贴吧,看到有人求助,做了一下.请大家指正! #!/usr/bin/env python3 # -*- coding: utf-8 -*- __author__ = 'Fan Lijun' imp ...

  2. A1083 List Grades (25)(25 分)

    A1083 List Grades (25)(25 分) Given a list of N student records with name, ID and grade. You are supp ...

  3. 关于IDEA 单元测试时 【empty test suite】异常的分析!!

    IDEA功能很强大,配置很操蛋,自从用了之后掉了很多坑!!! 这几天要用单元测试,方法完好但是就是一直报empty test suite ,WTF,类找不到 在网上反复的找答案都没有合适 静下心想想, ...

  4. Redis实现之对象(三)

    集合对象 集合对象的编码可以是intset或者hashtable,intset编码的集合对象使用整数集合作为底层实现,集合对象包含的所有元素都被保存在整数集合里面.举个栗子,以下代码将创建一个图1-1 ...

  5. 赢友网络通用框架V10.0.0(WinuAppSoft) 基础框架设计表

    /* * 版权所有:赢友网络(http://www.winu.net/) * 开发人员:新生帝(JsonLei) * 设计名称:赢友网络通用框架V10.0.0(WinuAppSoft) * 设计时间: ...

  6. 设计模式之第13章-职责链模式(Java实现)

    设计模式之第13章-职责链模式(Java实现) “请假都那么麻烦,至于么.”“咋的了?”“这不快过年了么,所以我想早两天回去,准备一下,买买东西什么的,然后去给项目经理请假,但是他说快过年了,所以这个 ...

  7. 图说不为人知的IT传奇故事-2-IBM咬不动的胡桃

    此系列文章为“图说不为人知的IT传奇故事”,各位大忙人可以在一分钟甚至几秒内了解把握整个内容,真可谓“大忙人的福利”呀!!希望各位IT界的朋友在钻研技术的同时,也能在文学.历史上有所把握.了解这些故事 ...

  8. Leetcode 517.超级洗衣机

    超级洗衣机 假设有 n 台超级洗衣机放在同一排上.开始的时候,每台洗衣机内可能有一定量的衣服,也可能是空的. 在每一步操作中,你可以选择任意 m (1 ≤ m ≤ n) 台洗衣机,与此同时将每台洗衣机 ...

  9. 常用JS整理

    目录 1 事件 a addEventListener--绑定事件b removeEventListener--解绑事件,只能解开addEventListener绑定的事件 2 JS获取节点信息a by ...

  10. 【转】Unity3d中制作Loading场景进度条所遇到的问题 LoadLevelAsync,AsyncOperation

    背景 通常游戏的主场景包含的资源较多,这会导致加载场景的时间较长.为了避免这个问题,可以首先加载Loading场景,然后再通过Loading场景来加载主场景.因为Loading场景包含的资源较少,所以 ...