Java类加载器深入讲解
2015-08-05 22:45
351 查看
Java类加载器深入讲解
标签(空格分隔): Java1. 什么是类加载器?
加载类的工具。2. 类加载器有什么作用?
当程序需要的某个类,那么需要通过类加载器把类的二进制加载到内存中,类加载器也是Java类。3. 类加载器之间的父子关系和管辖范围。
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader(); while (classLoader != null) { System.out.println(classLoader.getClass().getName()); classLoader = classLoader.getParent(); } System.out.println(classLoader);
结果:
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
null
4. 类加载器的委托机制:
当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?①首先当前线程的类加载器去加载线程中的第一个类.
②如果类A中引用了类B,Java虚拟机将使用加载类A的类加载器加载类B
③还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类.
每个类加载器加载类时,又先委托给其上级类加载器
当所有祖宗类加载器没有加载到类,回到发起者类加载器,如果还加载不了,则抛出ClassNotFoundException异常,它不会去找发起者类加载器的儿子,因为没有getChild()方法,即使有,有那么多的儿子交给那一个呢?所以干错就不叫给儿子处理了。
委托机制有什么好处?
集中管理,如果我们写了几个类加载器,都去加载某个类,那么内存中就有多份这个类的字节码。
能不能自己写一个类叫java.lang.System?
为了不让我们写System类,类加载采用委托机制,这样可以保证爸爸优先,也就是使用的永远是爸爸的(系统的)System类,而不是我们写的System类.
5. 编写自己的类加载器
public static void main(String[] args) throws Exception { String srcPath = args[0]; String destDir = args[1]; FileInputStream fis = new FileInputStream(srcPath); String destFileName = srcPath.substring(srcPath.lastIndexOf('\\')+1); String destPath = destDir + "\\" + destFileName; FileOutputStream fos = new FileOutputStream(destPath); cypher(fis,fos); fis.close(); fos.close(); } /** * 加密方法,同时也是解密方法 * @param ips * @param ops * @throws Exception */ private static void cypher(InputStream ips ,OutputStream ops) throws Exception{ int b = -1; while((b=ips.read())!=-1){ ops.write(b ^ 0xff);//如果是1就变成0,如果是0就变成1 } }
然后在新建一个类,通过上面的方法将新建的类的字节码进行加密:
public class ClassLoaderAttachment extends Date { //为什么要继承Date待会再说? public String toString(){ return "hello,itcast"; } }
并在工程里新建一个文件夹,用来保存加密后的class文件.
那么这就需要使用我们自己的类加载器来进行解密了.
public class MyClassLoader extends ClassLoader{
public static void main(String[] args) throws Exception { String srcPath = args[0]; String destDir = args[1]; FileInputStream fis = new FileInputStream(srcPath); String destFileName = srcPath.substring(srcPath.lastIndexOf('\\')+1); String destPath = destDir + "\\" + destFileName; FileOutputStream fos = new FileOutputStream(destPath); cypher(fis,fos); fis.close(); fos.close(); } /** * 加密方法,同时也是解密方法 * @param ips * @param ops * @throws Exception */ private static void cypher(InputStream ips ,OutputStream ops) throws Exception{ int b = -1; while((b=ips.read())!=-1){ ops.write(b ^ 0xff);//如果是1就变成0,如果是0就变成1 } }
private String classDir;
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String classFileName = classDir + "\\" + name.substring(name.lastIndexOf('.')+1) + ".class";
try {
FileInputStream fis = new FileInputStream(classFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cypher(fis,bos);
fis.close();
System.out.println("aaa");
byte[] bytes = bos.toByteArray();
return defineClass(bytes, 0, bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public MyClassLoader(){
}
public MyClassLoader(String classDir){
this.classDir = classDir;
}
}
测试运行代码:
Class clazz = new MyClassLoader("myClass").loadClass("ClassLoaderAttachment"); //此处不能在使用ClassLoaderAttachment因为一旦用了之后, //系统的类加载器就会去加载,导致失败,所以该类就继承了Date类了. Date date = (Date)clazz.newInstance(); System.out.println(date);
运行结果:
6. 一个类加载器的高级问题:
我们知道tomcat服务器,是一个大大的java程序,那么它就必须在JVM上运行.这个大大的java程序内部也写了很多类加载器,它用这些类加载器去加载一些特定的类.注入servlet类.下面我们新建一个javaweb工程,新建一个servlet程序.
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); ClassLoader classload = this.getClass().getClassLoader(); while (classload != null) { out.println(classload.getClass().getName()+"<br>"); classload = classload.getParent(); } out.println(); out.close(); }
然后配置服务器,部署应用程序,启动tomcat服务器.在页面访问我们这个servlet,在页面打印的
结果如下图所示:
这是从小到大排序的.
现在呢?我想把该servlet打成jar包,放在ExtClassLoad类加载器加载的路径.
通过Eclipse即可完成
相关文章推荐
- 新版 Spring下载方法
- Java线程(3)Timer和TimerTask
- Java工具 - 带图片的二维码
- [leetcode-78]subsets(java)
- 【java】--多线程原理
- Java线程(2)线程协作-生产者/消费者模式
- Java 控制台读取输入并过滤特定字符
- struts2+spring的两种整合方式
- Java线程-----------线程安全与不安全与线程同步synchronized和volatile
- 增加eclipse的内存
- 黑马程序员---struts2学习笔记之三通配符与动态方法调用
- 黑马程序员——struts2学习笔记二(结果类型)
- 给出现el表达式异常,但自我检查没有发现任何问题的朋友的忠告
- Java—Lambda基础
- JAVA _IO流(1)
- Java当中数组和容器之间的相互转换
- Struts2.3.4.1+Spring3.2.3+Hibernate4.1.9整合教程并测试成功
- spring mvc框架中创建验证码
- spring-resource
- Elasticsearch Java API之清空索引