一、自定义类加载器的一般步骤

Java的类加载器自从JDK1.2开始便引入了一条机制叫做父类委托机制。一个类需要被加载的时候,JVM先会调用他的父类加载器进行加载,父类调用父类的父类,一直到顶级类加载器。如果父类加载器加载不了,依次再使用其子类进行加载。当然这类所说的父类加载器,不一定他们之间是继承的关系,有可能仅仅是包装的关系。

Java之所以出现这条机制,因为是处于安全性考虑。害怕用户自己定义class文件然后自己写一个类加载器来加载原本应该是JVM自己加载的类。这样会是JVM虚拟机混乱或者说会影响到用户的安全。下面我们来自己实现一个类加载器,其中主要就是继承ClassLoader类。我们有必要明白:

虽然在绝大多数情况下系统默认提供的类加载器实现已经可以满足需求。但是在某些情况下,您还是需要为应用开发出自己的类加载器。比如您的应用通过网络来传输 Java 类的字节代码,为了保证安全性,这些字节码经过了加密处理。这个时候您就需要自己的类加载器来从某个网络地址上读取加密后的字节代码,接着进行解密和验证,最后定义出要在 Java 虚拟机中运行的类来。下面将通过两个具体的实例来说明类加载器的开发。

①ClassLoader加载类的顺序

1调用findLoadedClass(String) 来检查是否已经加载类

2在父类加载器上调用loadClass方法。如果父亲不能加载,一次一级一级传给子类

3调用子类findClass(String) 方法查找类。若还加载不了就返回ClassNotFoundException,不交给发起请求的加载器的子加载器

②实现自己的类加载器

1 获取类的class文件的字节数组,如loadClassData方法

2 将字节数组转换为Class类的实例,重写findClass中调用的defineClass方法

  1. package cn.M_ClassLoader2;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. public class ClassLoaderTest
  6. {
  7. public static void main(String[] args) throws InstantiationException, IllegalAccessException,  ClassNotFoundException
  8. {
  9. // 新建一个类加载器
  10. MyClassLoader cl = new MyClassLoader("myClassLoader");
  11. // 加载类,得到Class对象
  12. Class<?> clazz = cl.loadClass("cn.M_ClassLoader2.Animal");
  13. // 得到类的实例
  14. Animal animal = (Animal) clazz.newInstance();
  15. animal.say();
  16. }
  17. }
  18. class Animal
  19. {
  20. public void say()
  21. {
  22. System.out.println("hello world!");
  23. }
  24. }
  25. class MyClassLoader extends ClassLoader
  26. {
  27. // 类加载器的名称
  28. private String name;
  29. // 类存放的路径
  30. private String path = MyClassLoader.getSystemClassLoader().getResource("").getPath();;
  31. MyClassLoader(String name)
  32. {
  33. this.name = name;
  34. }
  35. MyClassLoader(ClassLoader parent, String name)
  36. {
  37. super(parent);
  38. this.name = name;
  39. }
  40. /**
  41. * 重写findClass方法
  42. */
  43. @Override
  44. public Class<?> findClass(String name)
  45. {
  46. byte[] data = loadClassData(name);
  47. return this.defineClass(name, data, 0, data.length);
  48. }
  49. public byte[] loadClassData(String name)
  50. {
  51. try
  52. {
  53. name = name.replace(".", "//");
  54. FileInputStream is = new FileInputStream(new File(path + name + ".myclass"));
  55. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  56. int b = 0;
  57. while ((b = is.read()) != -1)
  58. {
  59. baos.write(b);
  60. }
  61. System.out.println("我是自定义类加载器哦!");
  62. return baos.toByteArray();
  63. }
  64. catch (Exception e)
  65. {
  66. e.printStackTrace();
  67. }
  68. return null;
  69. }
  70. }

一般来说自己开发的类加载器只需要覆写findClass(String name)方法即可。java.lang.ClassLoader类的方法loadClass()封装了前面提到的代理模式的实现。该方法会首先调用findLoadedClass()方法来检查该类是否已经被加载过;如果没有加载过的话,会调用父类加载器的loadClass()方法来尝试加载该类;如果父类加载器无法加载该类的话,就调用findClass()方法来查找该类。因此,为了保证类加载器都正确实现代理模式,在开发自己的类加载器时,最好不要覆写loadClass()方法,而是覆写findClass()方法。

二、自定义类加载器的运行问题

由于只重写了findClass方法并没有重写loadClass方法,故没有改变父类委托机制。也就数说如果某个.class可以被父类加载,我们自定义的类加载器就不会被执行了。比如Animal.java被自动编译为Animal.class放在bin目录下,AppClassLoader完全可以加载,所以就不调用自定义的加载器了。

尝试办法1:把Animal.class放在别的目录中比如D盘的根目录下

报 Class A can not access a member of class B with modifiers ""错。Java语言中的包访问成员实际上指的是运行时包访问可见,而不是编译时。因此当你试图访问不在同一个runtime package的成员时,即便在编译时它们在同一个包内,但是却由不同的class loader加载,也同样会得到java.lang.IllegalAccessException: Class A can not access a member of class B with modifiers "" 这样的异常。

尝试办法2:把该Animal.class的后缀名为.myClass,让AppClassLoader找不到

网上有人说可以解决,但是我实验的结果是会和办法1报一样的异常。

尝试办法3:解决方案是通过扩展自定义的ClassLoader,重写loadClass方法先从当前类加载器加载再从父类加载器加载。

该解决办法是可以解决的,网址是http://blog.csdn.net/zhangxinrun/article/details/6161426

java类加载器学习2——自定义类加载器和父类委托机制带来的问题的更多相关文章

  1. Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论

    Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...

  2. JAVA类加载器一 父类委托机制

    感谢原文作者:不将就! 原文链接:https://www.cnblogs.com/byron0918/p/5770653.html 类加载器负责将.class文件加载到内存中,并为之生成对应的Clas ...

  3. (转)《深入理解java虚拟机》学习笔记6——类加载机制

    Java虚拟机类加载过程是把Class类文件加载到内存,并对Class文件中的数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型的过程. 在加载阶段,java虚拟机需要完成以下 ...

  4. java之jvm学习笔记四(安全管理器)

    java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...

  5. 《深入理解Java虚拟机》学习笔记之类加载

    之前在学习ASM时做了一篇笔记<Java字节码操纵框架ASM小试>,笔记里对类文件结构做了简介,这里我们来回顾一下. Class类文件结构 在Java发展之初设计者们发布规范文档时就刻意把 ...

  6. Struts2重新学习之自定义拦截器(判断用户是否是登录状态)

    拦截器 一:1:概念:Interceptor拦截器类似于我们学习过的过滤器,是可以再action执行前后执行的代码.是web开发时,常用的技术.比如,权限控制,日志记录. 2:多个拦截器Interce ...

  7. Struts学习之自定义拦截器

    * 所有的拦截器都需要实现Interceptor接口或者继承Interceptor接口的扩展实现类    * 要重写init().intercept().destroy()方法        * in ...

  8. java8学习之自定义收集器深度剖析与并行流陷阱

    自定义收集器深度剖析: 在上次[http://www.cnblogs.com/webor2006/p/8342427.html]中咱们自定义了一个收集器,这对如何使用收集器Collector是极有帮助 ...

  9. java8学习之自定义收集器实现

    在上次花了几个篇幅对Collector收集器的javadoc进行了详细的解读,其涉及到的文章有: http://www.cnblogs.com/webor2006/p/8311074.html htt ...

随机推荐

  1. Insist

    1.怎么自动截断文本? 如题,当数据库中的数据内容超出了要显示的长度时,如果不采取措施,会破坏页面的布局美观,所以可以采用自动截断文本,需要查看的时候再把其他的内容显示出来. 没截断的时候如下图: 再 ...

  2. Weblogic12c安装与配置详解

    Weblogic是什么Weblogic的安装Weblogic创建域Weblogic管理域Weblogic的应用Weblogic是什么 Weblogic这是我入职以后第一次接触到的词汇,我很陌生,就从我 ...

  3. c# Oracle 远程连接方式 plsql 连接oracle 11g 64位

    1.本地连接字符串:   string connect = "Data Source=orcl;user=XXX;password=XXX;Persist Security Info=Tru ...

  4. HttpWebRequest

    同步请求=====================================================================================  byte[] da ...

  5. org.hibernate.LazyInitializationException

    1.org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.c ...

  6. 分析Hibernate的事务处理机制

    Hibernate是对JDBC的轻量级对象封装,Hibernate本身是不具备Transaction处理功能的,Hibernate的 Transaction实际上是底层的JDBC Transactio ...

  7. Exploring the 7 Different Types of Data Stories

    Exploring the 7 Different Types of Data Stories What makes a story truly data-driven? For one, the n ...

  8. ADO.net--杂七杂八(一)

    private void BtnConnectDataBase_Click(object sender, RoutedEventArgs e) { string connectionString = ...

  9. CodeForces 299B Ksusha the Squirrel

    http://codeforces.com/problemset/problem/299/B 题意 :这个题挺简单的,就是说这个姑娘不喜欢走有石头的扇形,所以给你一个k的值,代表她一次可以跳多少扇形. ...

  10. eclipse连接远程Hadoop报错,Caused by: java.io.IOException: 远程主机强迫关闭了一个现有的连接。

    eclipse连接远程Hadoop报错,Caused by: java.io.IOException: 远程主机强迫关闭了一个现有的连接.全部报错信息如下: Exception in thread & ...