`
扫地僧
  • 浏览: 29226 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

Java加载资源文件的方法

阅读更多

一、通过Class:getResource()加载资源

通过Class类的public java.net.URL getResource(String name)

public java.net.URL getResource(String name) {

        name = resolveName(name);

        ClassLoader cl = getClassLoader0();

        if (cl==null) {

            // A system class.

            return ClassLoader.getSystemResource(name);

        }

        returncl.getResource(name);

    }

通过Class类的getResource和通过ClassLoader的类加载资源的主要区别在于resolveName这个方法,我们来看下它的实现:

private String resolveName(String name) {

        if (name == null) {

            returnname;

        }

        if (!name.startsWith("/")) {

            Class<?> c = this;

            while (c.isArray()) {

                c = c.getComponentType();

            }

            String baseName = c.getName();

            intindex = baseName.lastIndexOf('.');

            if (index != -1) {

                name = baseName.substring(0, index).replace('.', '/')

                    +"/"+name;

            }

        } else {

            name = name.substring(1);

        }

        returnname;

    }

resolveName方法,如果是资源名是以/开头的绝对路径,例如/a/b/c,则返回a/b/cClassLoader调用;

如果资源名不是以/开头的绝对路径,例如a/b/c,则返回当前类grucee.test.Main的包路径grucee/test加上/+a/b/c,最后的结果就是grucee/test/a/b/c

我们来看两个示例:

资源文件如下图:



 
代码

publicstaticvoid main(String[] args) throws IOException {

       String absolutePath = "/test.properties";

       String relativePath = "test.properties";

      

       InputStream absoluteIn = Main.class.getResourceAsStream(absolutePath);

       InputStream relativeIn = Main.class.getResourceAsStream(relativePath);

      

       //假设编译后的文件按照包结构放置在bin目录(eclipse默认)

       //传绝对路径加载的是相对于bin目录的文件:bin/test.properties

       Properties absoluteProp = new Properties();

       absoluteProp.load(absoluteIn);

       System.out.println(absoluteProp.getProperty("path"));

      

       //传相对路径加载的是相对于Main.class所在目录的文件:bin/grucee/test/test.properties

       Properties relativeProp = new Properties();

       relativeProp.load(relativeIn);

       System.out.println(relativeProp.getProperty("path"));

    }

二、通过ClassLoader:getResource()加载资源

系统有哪些ClassLoader

1).Bootstrap Loader(引导类加载器):加载System.getProperty("sun.boot.class.path")所指定的路径或jar

2).Extended Loader(标准扩展类加载器ExtClassLoader):加载System.getProperty("java.ext.dirs")所指定的路径或jar。在使用Java运行程序时,也可以指定其搜索路径,例如:java -Djava.ext.dirs=d:\projects\testproj\classes HelloWorld

3).AppClass Loader(系统类加载器AppClassLoader):加载System.getProperty("java.class.path")所指定的路径或jar。在使用Java运行程序时,也可以加上-cp来覆盖原有的Classpath设置,例如: java -cp ./lavasoft/classes HelloWorld

4).自定义类加载器

ExtClassLoaderAppClassLoaderJVM启动后,会在JVM中保存一份,并且在程序运行中无法改变其搜索路径。如果想在运行时从其他搜索路径加载类,就要产生新的类加载器。

线程上下文类加载器

线程上下文类加载器(context class loader)是从 JDK 1.2 开始引入的。类 java.lang.Thread中的方法 getContextClassLoader()setContextClassLoader(ClassLoader cl)用来获取和设置线程的上下文类加载器。如果没有通过 setContextClassLoader(ClassLoader cl)方法进行设置的话,线程将继承其父线程的上下文类加载器。Java 应用运行的初始线程的上下文类加载器是系统类加载器。在线程中运行的代码可以通过此类加载器来加载类和资源。

前面提到的类加载器的代理模式并不能解决 Java 应用开发中会遇到的类加载器的全部问题。Java 提供了很多服务提供者接口(Service Provider InterfaceSPI),允许第三方为这些接口提供实现。常见的 SPI JDBCJCEJNDIJAXP JBI 等。这些 SPI 的接口由 Java 核心库来提供,如 JAXP SPI 接口定义包含在 javax.xml.parsers包中。这些 SPI 的实现代码很可能是作为 Java 应用所依赖的 jar 包被包含进来,可以通过类路径(CLASSPATH)来找到,如实现了 JAXP SPI  Apache Xerces所包含的 jar 包。SPI 接口中的代码经常需要加载具体的实现类。如 JAXP 中的 javax.xml.parsers.DocumentBuilderFactory类中的 newInstance()方法用来生成一个新的 DocumentBuilderFactory的实例。这里的实例的真正的类是继承自 javax.xml.parsers.DocumentBuilderFactory,由 SPI 的实现所提供的。如在 Apache Xerces 中,实现的类是 org.apache.xerces.jaxp.DocumentBuilderFactoryImpl。而问题在于,SPI 的接口是 Java 核心库的一部分,是由引导类加载器来加载的;SPI 实现的 Java 类一般是由系统类加载器来加载的。引导类加载器是无法找到 SPI 的实现类的,因为它只加载 Java 的核心库。它也不能代理给系统类加载器,因为它是系统类加载器的祖先类加载器。也就是说,类加载器的代理模式无法解决这个问题。

线程上下文类加载器正好解决了这个问题。如果不做任何的设置,Java 应用的线程的上下文类加载器默认就是系统上下文类加载器。在 SPI 接口的代码中使用线程上下文类加载器,就可以成功的加载到 SPI 实现的类。线程上下文类加载器在很多 SPI 的实现中都会用到。

加载资源的流程

ClassLoader加载配置文件时,路径均不能以"/"开头,在查找时直接在classpath下进行查找。

查看源代码:

public URL getResource(String name) {

        URL url;

        if (parent != null) {

            url = parent.getResource(name);

        } else {

            url = getBootstrapResource(name);

        }

        if (url == null) {

            url = findResource(name);

        }

        returnurl;

    }

假设我们没有自定义类加载器,并且我们调用的是系统类加载器的getResource,那么该ClassLoader就是AppClassLoader的实例,并且通过上述方法,依次会调用:

AppClassLoader:getResource->ExtClassLoader:getResource->getBootstrapResource()。也就是分别在加载启动类、扩展类、系统类的路径下寻找资源文件,和类加载采用相同的双亲委派机制。

并不是所有的类加载都符合双亲委派机制,因此类中加载的资源文件也不是都符合双亲委派机制。所以加载资源的时候,也需要用到线程上下文类加载器。我们通常使用下面的代码加载资源文件(通常使用ClassLoadergetResource(),它和类加载思路一致,因此更好理解):

privatestatic InputStream loadConfigFile() {

       //先使用当前类的类加载器查找资源

       InputStream in = FileLogReader.class.getClassLoader().getResourceAsStream(LoggerConstants.FILE_LOG_PATH);

       if (in == null) {

           //查找不到资源时,使用线程上下文的类加载器查找资源

           in = Thread.currentThread().getContextClassLoader()

                  .getResourceAsStream(LoggerConstants.FILE_LOG_PATH);

       }

       returnin;

    }

 

  • 大小: 6.8 KB
分享到:
评论

相关推荐

    java 静态代码块通过类加载器获取资源文件例子

    本案例是一个通过静态代码块获取资源属性文件的代码块,从而来提高应用性能。。

    加载文件资源的三种方式

    加载文件资源的三种方式 ~1.从classpath根目录下加载指定名称的文件 2.从classpath根目录下加载指定名称的文件 3. 从classpath根目录下加载指定名称的文件 4. 获取当前文件的绝对路径

    解决java打包之后无法加载静态资源的问题SWTResourceManager.java源码

    利用swt中的一个获取图片的类SwingResourceManager 来解决将程序打为使用java打包之后,生成的jar包中图片找不着的。这是因为通过class.getResource()方法在IDEA中运行的路径和生成jar包获取的的路径是不同的。打成...

    Java加载资源文件的两种方法

    处理配置文件对于Java程序员来说再常见不过了,不管是Servlet,Spring,抑或是Structs,都...  在了解了Java加载资源文件的机制后,以上这两个问题便迎刃而解了。  对于第一个问题,答案是:请将你的资源文件放在c

    java加载obj,stl模型资源,html页面展示

    java加载obj,stl模型资源,html页面展示。 部署即可运行,提供基础数据样例展示

    Java加载properties文件实现方式详解

    主要介绍了Java加载properties文件实现方式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    web开发自动加载修改后的java文件

    web开发时,修改java文件后,无须重启服务器便可自动加载修改之后的java文件。本资源包含jrebel.jar及其使用说明。

    Jar包中如何正确地加载资源文件博文中用到的测试项目源码

    Jar包中如何正确地加载资源文件博文中用到的测试项目源码 http://codepub.cn/

    Java加载资源文件时的路径问题的解决办法

    今天偶然看到一篇关于tomcat加载servlet的文章,不由得想起了java加载资源文件的路径问题,资源文件可以使xml,properties,图片等,可以是任何文件

    深入理解java类加载机制

    我们将详细讲解字节码文件的结构、语法和格式,以及字节码指令的定义和应用,并通过大量实例进行编程详解,帮助开发人员深入了解Java字节码的使用方法和技巧。 在类加载方面,我们将深入探讨Java程序的类加载原理和...

    java-loadresource.rar

    Java加载资源文件的两种方法getResource与getResourceAsStream

    java源码包---java 源码 大量 实例

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...

    Java URLClassLoader动态加载jar包1

    该类加载器用于从指向 JAR 文件和目录的 URL 的搜索路径加载类和资源。如果不是以该字符结束,则认为该 URL 指向一个将根据需要打开的 JAR 文件pac

    JAVA上百实例源码以及开源项目

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...

    Geoserver在安装时所用到的加载资源

    压缩包里面包含三个文件: cors-filter-2.4.jar java-property-utils-1.9.1.jar 必看文档.txt 在安装好Geoserver后可以看一下“必看文档.txt”,修改相应配置

    Qt加载字体文件删除字体文件

    Qt加载自己的字体,不用系统提供的QFontComboBox

    java源码包4

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java...

    java源码包3

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java...

    Java资源包01

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    JAVA 单个或多个下载服务器上带超链接的文件 并压缩后下载

    JAVA 中单个或多个下载服务器上带超链接的文件 并压缩后下载, 如:http://172.16.10.24/recordwav/20150625/48/20150625140223_48_8003_8002_to_18064000047.wav http://www.baidu.com/img/test.png 此资源中还...

Global site tag (gtag.js) - Google Analytics