java类加载器学习2——自定义类加载器和父类委托机制带来的问题
一、自定义类加载器的一般步骤
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方法
- package cn.M_ClassLoader2;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- public class ClassLoaderTest
- {
- public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException
- {
- // 新建一个类加载器
- MyClassLoader cl = new MyClassLoader("myClassLoader");
- // 加载类,得到Class对象
- Class<?> clazz = cl.loadClass("cn.M_ClassLoader2.Animal");
- // 得到类的实例
- Animal animal = (Animal) clazz.newInstance();
- animal.say();
- }
- }
- class Animal
- {
- public void say()
- {
- System.out.println("hello world!");
- }
- }
- class MyClassLoader extends ClassLoader
- {
- // 类加载器的名称
- private String name;
- // 类存放的路径
- private String path = MyClassLoader.getSystemClassLoader().getResource("").getPath();;
- MyClassLoader(String name)
- {
- this.name = name;
- }
- MyClassLoader(ClassLoader parent, String name)
- {
- super(parent);
- this.name = name;
- }
- /**
- * 重写findClass方法
- */
- @Override
- public Class<?> findClass(String name)
- {
- byte[] data = loadClassData(name);
- return this.defineClass(name, data, 0, data.length);
- }
- public byte[] loadClassData(String name)
- {
- try
- {
- name = name.replace(".", "//");
- FileInputStream is = new FileInputStream(new File(path + name + ".myclass"));
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- int b = 0;
- while ((b = is.read()) != -1)
- {
- baos.write(b);
- }
- System.out.println("我是自定义类加载器哦!");
- return baos.toByteArray();
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- return null;
- }
- }
一般来说自己开发的类加载器只需要覆写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——自定义类加载器和父类委托机制带来的问题的更多相关文章
- Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论
Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...
- JAVA类加载器一 父类委托机制
感谢原文作者:不将就! 原文链接:https://www.cnblogs.com/byron0918/p/5770653.html 类加载器负责将.class文件加载到内存中,并为之生成对应的Clas ...
- (转)《深入理解java虚拟机》学习笔记6——类加载机制
Java虚拟机类加载过程是把Class类文件加载到内存,并对Class文件中的数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型的过程. 在加载阶段,java虚拟机需要完成以下 ...
- java之jvm学习笔记四(安全管理器)
java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...
- 《深入理解Java虚拟机》学习笔记之类加载
之前在学习ASM时做了一篇笔记<Java字节码操纵框架ASM小试>,笔记里对类文件结构做了简介,这里我们来回顾一下. Class类文件结构 在Java发展之初设计者们发布规范文档时就刻意把 ...
- Struts2重新学习之自定义拦截器(判断用户是否是登录状态)
拦截器 一:1:概念:Interceptor拦截器类似于我们学习过的过滤器,是可以再action执行前后执行的代码.是web开发时,常用的技术.比如,权限控制,日志记录. 2:多个拦截器Interce ...
- Struts学习之自定义拦截器
* 所有的拦截器都需要实现Interceptor接口或者继承Interceptor接口的扩展实现类 * 要重写init().intercept().destroy()方法 * in ...
- java8学习之自定义收集器深度剖析与并行流陷阱
自定义收集器深度剖析: 在上次[http://www.cnblogs.com/webor2006/p/8342427.html]中咱们自定义了一个收集器,这对如何使用收集器Collector是极有帮助 ...
- java8学习之自定义收集器实现
在上次花了几个篇幅对Collector收集器的javadoc进行了详细的解读,其涉及到的文章有: http://www.cnblogs.com/webor2006/p/8311074.html htt ...
随机推荐
- EXTJS 4.2 资料 控件之textfield文本框加事件的用法
{ xtype: "textfield", width: 100, id: "txtGroupName", name: "txtGroupName&q ...
- 一步步学习NHibernate(9)——连接查询和子查询(1)
请注明转载地址:http://www.cnblogs.com/arhat 在前几章中,我们把HQL的基本查询学习了一下,但是只有基本查询很显然不能满足我们的需求,那么就需要一下复杂查询比如" ...
- s3c2440之cache
cache高速缓冲存储器注意与块设备页高速缓存进行区别,一个是硬件的实现一个是软件的实现,块设备页高速缓存. s3c2440/s3c2410里面主要有一个arm920t的核,但同时包含几个协处理器,协 ...
- 深层解析:构建facebook应用商店推荐引擎
Under the Hood: Building the App Center recommendation engine As more apps on Facebook Platform ha ...
- C# Winform 涉及的拖放操作总结
在开发程序的时候,为了提高用户的使用体验,或满足相关用户的功能,总是离不开拖放功能.而本文是总结winform下的常用拖放操作.主要有 1.textbox接受拖放的文件2.listbox允许用户自定义 ...
- Spring MVC与表单日期提交的问题
Spring MVC与表单日期提交的问题 spring mvc 本身并不提供日期类型的解析器,需要手工绑定, 否则会出现非法参数异常. org.springframework.beans.BeanIn ...
- uva 10534
一开始WA了 参考了一下 求正反两个方向的最长上升子序列 并分别记录在两个数组中 最后求最大值 #include <iostream> #include <cstdio&g ...
- 1987-A. 集训队选拔
描述 南邮ACM暑期集训队一年一度的选拔如火如荼的开始了.按照以往的惯例,通过ACM校赛预赛和决赛的两轮选拔,成绩优异者将入选集训队,获得下半年在各大赛区现场赛上与各路神牛角逐奖牌的机会.但是,校赛的 ...
- POJ 2275 Flipping Pancake
点我看题目 题意 : 按我自己的理解就是,给你n个数,按照从上到下排列,现在让你进行一系列的操作,让你将数按照从大到小排好. 思路 : 比赛的时候以为要用记录路径的搜索,当时没什么把握,所以没做,今天 ...
- swift苹果的下一代语言
http://numbbbbb.github.io/the-swift-programming-language-in-chinese/chapter1/01_swift.html 有时间再看,bas ...