Java中用ClassLoader载入各种资源(类、文件、web资源)的方法
lassLoader主要对类的请求提供服务,当JVM需要某类时,它根据名称向ClassLoader要求这个类,然后由ClassLoader返回这个类的class对象。
ClassLoader负责载入系统的所有资源(Class,文件,图片,来自网络的字节流等),通过ClassLoader从而将资源载入JVM 中。每个class都有一个引用,指向自己的ClassLoader。
1. 获得ClassLoader的几种方法
可以通过如下3种方法得到ClassLoader :
- this.getClass.getClassLoader(); // 使用当前类的ClassLoader
- Thread.currentThread().getContextClassLoader(); // 使用当前线程的ClassLoader
- ClassLoader.getSystemClassLoader(); // 使用系统ClassLoader,即系统的入口点所使用的ClassLoader。
注:system ClassLoader与根ClassLoader并不一样。JVM下system ClassLoader通常为App ClassLoader。
2. 用ClassLoader载入资源的几种方法
所有资源都通过ClassLoader载入到JVM里,那么在载入资源时当然可以使用ClassLoader,只是对于不同的资源还可以使用一些别的方式载入,例如对于类可以直接new,对于文件可以直接做IO等。
2.1 类的载入方式
假设有类A和类B,A在其方法里需要实例化B,载入类可能的方法有3种。对于载入类的情况,用户需要知道B类的完整名字(包括包名,例如"com.alexia.B")
1. 使用Class静态方法 Class.forName
- Class cls = Class.forName("com.alexia.B");
- B b = (B)cls.newInstance();
2. 使用ClassLoader
- /* Step 1. Get ClassLoader */
- ClassLoader cl = this.getClass.getClassLoader();; // 如何获得ClassLoader参考1
- /* Step 2. Load the class */
- Class cls = cl.loadClass("com.alexia.B"); // 使用第一步得到的ClassLoader来载入B
- /* Step 3. new instance */
- B b = (B)cls.newInstance(); // 有B的类得到一个B的实例
3. 直接new
- B b = new B();
注:有人心里可能会想,对于类的载入方式我们都会选择最简单的第3种方式,前两种方式完全是多余。
实则不然,直接new的方式也是有局限的,举个最简单的例子:Java中有包名的类怎么引用默认包中的类?当然说这个是因为有包名的类不能直接用new引用默认包中的类,那么怎么办呢?答案是使用反射机制,即使用第一种方式来加载类(具体请看这里)。而且,用new()和用newInstance()创建类的实例是不同的,主要区别简单描述如下:
从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:
(1)这个类已经加载;
(2)这个类已经链接了(即为静态域分配存储空间,并且如果必须的话将解析这个类创建的对其他类的所有引用)。而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载javaAPI的那个加载器。
可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。
2.2 文件的载入方式(例如配置文件等)
假设在com.alexia.A类里想读取文件夹 /com/alexia/config 里的文件sys.properties,读取文件可以通过绝对路径或相对路径,绝对路径很简单,在Windows下以盘号开始,在Unix下以"/"开始。对于相对路径,其相对值是相对于ClassLoader的,因为ClassLoader是一棵树,所以这个相对路径和ClassLoader树上的任何一个ClassLoader相对比较后可以找到文件,那么文件就可以找到。文件有以下三种加载方式:
1. 直接用IO流读取
- /**
- * 假设当前位置是 "C:/test",通过执行如下命令来运行A "java com.aleixa.A"
- * 1. 在程序里可以使用绝对路径,Windows下的绝对路径以盘号开始,Unix下以"/"开始
- * 2. 也可以使用相对路径,相对路径前面没有"/"
- * 因为我们在 "C:/test" 目录下执行程序,程序入口点是"C:/test",相对路径就
- * 是 "com/alexia/config/sys.properties"
- * (例子中,当前程序的ClassLoader是App ClassLoader,system ClassLoader = 当前的
- * 程序的ClassLoader,入口点是"C:/test")
- * 对于ClassLoader树,如果文件在jdk lib下,或在jdk lib/ext下,或在环境变量里,
- * 都可以通过相对路径"sys.properties"找到,lib下的文件最先被找到
- */
- File f = new File("C:/test/com/aleixa/config/sys.properties"); // 使用绝对路径
- //File f = new File("com/alexia/config/sys.properties"); // 使用相对路径
- InputStream is = new FileInputStream(f);
2. 使用ClassLoader
- /**
- * 因为有3种方法得到ClassLoader,对应有如下3种ClassLoader方法读取文件
- * 使用的路径是相对于这个ClassLoader的那个点的相对路径,此处只能使用相对路径
- */
- InputStream is = null;
- is = this.getClass().getClassLoader().getResourceAsStream(
- "com/alexia/config/sys.properties"); //方法1
- //is = Thread.currentThread().getContextClassLoader().getResourceAsStream(
- "com/alexia/config/sys.properties"); //方法2
- //is = ClassLoader.getSystemResourceAsStream("com/alexia/config/sys.properties"); //方法3
3. 使用ResourceBundle
- ResourceBundle bundle = ResourceBundle.getBoundle("com.alexia.config.sys");
这种用法通常用来载入用户的配置文件,关于ResourceBunlde更详细的用法请参考其他文档。
注:如果是属性配置文件,也可以通过java.util.Properties.load(is)将内容读到Properties里,Properties默认认为is的编码是ISO-8859-1,如果配置文件是非英文的,可能出现乱码问题。
总结:有如下3种途径来载入文件
1. 绝对路径 ---> IO
2. 相对路径 ---> IO
---> ClassLoader
3. 资源捆绑 ---> ResourceBundle
2.3 web资源的载入方式
在web应用里当然也可以使用ClassLoader来载入资源,但更常用的情况是使用ServletContext,如下是web目录结构
ContextRoot
|- JSP、HTML、Image等各种文件
|- [WEB-INF]
|- web.xml
|- [lib] Web用到的JAR文件
|- [classes] 类文件
用户程序通常在classes目录下,如果想读取classes目录里的文件,可以使用ClassLoader,如果想读取其他的文件,一般使用ServletContext.getResource()。
如果使用ServletContext.getResource(path)方法,路径必须以"/"开始,路径被解释成相对于ContextRoot的路径,此处载入文件的方法和ClassLoader不同,举例"/WEB-INF/web.xml","/download/WebExAgent.rar"
Java中用ClassLoader载入各种资源(类、文件、web资源)的方法的更多相关文章
- Struts2 之 Action 类访问 WEB 资源
接着上次博客的内容我继续分享我所学到的知识,和自己在学习过程中所遇到问题以及解决方案.当然,如果读者发现任何问题均可以在下方评论告知我,先谢! 在 Action 中访问 WEB 资源 web 资源 所 ...
- ClassLoader载入指定的类需注意六个细节或报ClassNotFundEception异常总结
项目中,载入指定的类反射调用方法一直报类找不到,经过数百次的測试.对这样的问题有了一个又一次的认识,特总结.记录.分享例如以下: 1.路径中尽可能用"/"或者File.separa ...
- -1-4 java io java流 常用流 分类 File类 文件 字节流 字符流 缓冲流 内存操作流 合并序列流
File类 •文件和目录路径名的抽象表示形式 构造方法 •public File(String pathname) •public File(String parent,Stringchild) ...
- 【Java编译】含package的类文件编译
含package的类文件编译: package com.zhangxueliang.setdemo; public class Demo1 { public static void main(Stri ...
- java里面包的重要性-管理类文件
包的必要性 包是用来给java源文件分门别类的,java中一个包在windows下就是一个文件夹.包的全限定名是从根文件夹開始的(\src文件夹)以点号作为分隔符,包名和包名之间使用点号隔开,java ...
- .NET C#利用反射获取类文件以及其中的方法&属性 并获取类及方法上的特性
了解C#特性类并声明我们自己的特性类[AttributeTest]代码如下 using System; namespace AttributeTest { /* 特性说明 特性本质是一个继承和使用了系 ...
- PHP __autoload函数(自动载入类文件)的使用方法(转)
详细出处参考:http://www.jb51.net/article/29625.htm 在使用PHP的OO模式开发系统时,通常大家习惯上将每个类的实现都存放在一个单独的文件里,这样会很容易实现对类进 ...
- Java错误:找不到类文件或者未加载主类
使用java命令执行.class文件时,java只会查找环境变量CLASSPATH中的目录,并会不查找当前目录,所以只要把当前目录”."加入到CLASSPATH中就可以了.
- 查看ClassLoader载入了哪些类?
在执行jar时加上-verbose:class java -verbose:class -Xms1G -Xmx2G -jar xx.jar 必要时还可以使用 >log.txt 将输出输入到文本 ...
随机推荐
- IIS的配置
一.首先是安装IIS.打开控制面板,找到“程序与功能”,点进去 二.点击左侧“打开或关闭Windows功能” 三.找到“Internet 信息服务”,按照下图打勾即可 等待安装完成 四.安装完成后,再 ...
- spring 笔记1: mvn 中Controller方法的参数不能是嵌套类(内部类)。
最近做spring开发,个人认为,Controller和客户端js通讯时传递的参数类 只使用某几个方法,为了减少对其他功能的影响,想把参数类定义为Controller类的 嵌套类(内部类).但是实践发 ...
- CentOS 7 配置静态 ip
1. 需求场景: 在 CentOS7 上部署了一个 svn ,由于centOS7 默认是 dhcp 的,所以每过一段时间 ip 就会有变化,而 svn 要求 ip 是不能变的,不然没法同步. 网上找了 ...
- 今天被PHP短标签给坑了
<?=$var?><?php echo $var; ?> 上面这两种写法是等价的,但由于某些空间提供商并未开启短标记,所以还是推荐使用标准格式吧,今天被这东西坑了!!
- java static静态方法的并发性
在做一个web项目的时候需要做一个通用类去处理一些问题,想到这个类很多地方都有用到,又不想每次都new一个,因此就定义了里面的方法是静态方法,然后又因为多个静态方法都用到了同一个对象,结果定义了一个类 ...
- 关于eclipse删除servers之后,不能新建其所对应版本的Servers
无法从以下方式,添加Tomcat服务器. 其中ServerName是被置为灰色的,无法编辑. 如何解决 1. 关闭Eclipse 2. 打开WorkSpace所在的位置. {workspa ...
- 以小时候玩的贪吃蛇为例,对于Java图像界面的学习感悟
简介 正文 01.JFrame是啥? 02.JPanel 03. KeyListener 04.Runnable 05.游戏Running 06.游戏初始类编写 07.main 简介: 一直以来用代码 ...
- windows重建图标缓存(解决快捷方式图标丢失,图标加载时间长问题)
新建一个文本文档,把下边的代码输入进去,保存为.bat格式,运行即可 有快捷方式图标丢失或者觉得图标加载速度慢了,就run一下这个,很实用的小工具 rem 关闭Windows外壳程序explorer ...
- mac攻略(七) -- 环境变量PATH分析
一.首先需要了解 1>mac 一般使用bash作为默认shell 2>Mac系统的环境变量,加载顺序为: 1.系统级别的 /etc/profile /etc/bashrc /etc/p ...
- 三元运算与lambda表达式
#三元运算,就是对if else的简写 if 1 == 1: print("jasper") else: print("sb") 三元运算写法 name=&qu ...