一、自定义类加载器的一般步骤
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虚拟机》学习笔记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 ...
-
SpringMVC拦截器与SpringBoot自定义拦截器
首先我们先回顾一下传统拦截器的写法: 第一步创建一个类实现HandlerInterceptor接口,重写接口的方法. 第二步在XML中进行如下配置,就可以实现自定义拦截器了 SpringBoot实现自 ...
随机推荐
-
Ubuntu14.04_64位使用过程
1. vmware10 下安装 ubuntu(ps:安装过程中还是将磁盘整的更大一些的好,我最开始20G,不够用啊不够用[典型安装就行]) 2. 右上角的圆圈设置--选择system setting- ...
-
Shell 语法之函数
函数是被赋予名称的脚本代码块,可以在代码的任意位置重用.每当需要在脚本中使用这样的代码块时,只需引用该代码块被赋予的函数名称. 创建函数 格式 function name { commands } n ...
-
iOS - UITableViewController
前言 NS_CLASS_AVAILABLE_IOS(2_0) @interface UITableView : UIScrollView <NSCoding> @available(iOS ...
-
ZendStudio中设置SVN:ignore
使用ZendStudio开发SVN中的代码时,经常容易将 .project..settings..buildpath 这类的zend的工程文件提交上去,非常麻烦,有几种方法可以去掉这个麻烦. 1.在Z ...
-
关于ArrayList线程安全解决方案
一:使用synchronized关键字 二:使用Collections.synchronizedList();使用方法如下: 假如你创建的代码如下:List<Map<String,Obje ...
-
Chapter 2 Open Book——2
It was worse because I was tired; 更糟糕的是因为我疲惫了. I still couldn't sleep with the wind echoing around t ...
-
SSM-SpringMVC-26:SpringMVC异常骇级之自定义异常注解版
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 注解的方法实现异常解析,话不多说,直接搞起,和以前一样的习惯,和上篇博客一样的代码放后面,不一样的在前面 案 ...
-
build/temp.linux-x86_64-2.7/_openssl.c:493:30: fatal error: openssl/opensslv.h: No such file or directory
解决:apt-get install libssl-dev apt install python-dev(这个可能和那个错误关系不大)
-
[转]Howto: 使用ImageBrush替换PictureMarkerSymbol以加强graphic显示性能
原文地址:http://support.esrichina-bj.cn/2009/0728/1007.html 文章编号 : 37033 软件: ArcGIS API for Microsoft Si ...
-
asp.net Ajax调用Aspx后台方法
Ajax调用的前提(以aspx文件为例:) 1.首先需要在aspx文件后台中引用using System.Web.Services; 2.需要调用的方法必须是公共的(public).静态的(stati ...