ClassLoader学习笔记
来源:互联网 发布:广东篮球队球员数据 编辑:程序博客网 时间:2024/05/07 08:24
一、什么是ClassLoader
大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用该程序的一个入口函数来调用系统的相关功能,而这些功能都被封装在不同的class文件当中,所以经常要从这个class文件中要调用另外一个class文件中的方法,如果另外一个文件不存在的,则会引发系统异常。而程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需要,通过Java的类加载机制(ClassLoader)来动态加载某个class文件到内存当中的,从而只有class文件被载入到了内存之后,才能被其它class所引用。所以ClassLoader就是用来动态加载class文件到内存当中用的。
二、双亲委托机制
知道了什么是ClassLoader,那么JAVA是如何加载Class的呢,Java有一套双亲委托机制来动态加载class,请见下图:
当一个装载器被要求加载一个class的时候,会首先委托自己的parent ClassLoader去加载,如果parent能加载,则由parent返回class的对象,如上图的图1箭头所示,当所有的parent ClassLoader无法返回的时候,则由当前的ClassLoader加载class
三、运行时包
由同一个ClasLoader加载的属于同一个包的类,组成了运行时包,属于同一个包但不属于同一个ClassLoader的类不能访问相同包内可见的成员和方法。
Jvm这么做是出于安全考虑,假设我们写一个java.lang.String类,并自己自定义一个ClassLoader,那么可以访问由Bootstrap ClassLoader加载的java.lang.XXX的包内可见的方法和成员,这样显然是不可取也很不安全的。
总结:双亲委托机制增加了Jvm的安全,运行时包增加了对包内可见成员的保护
四、定义自己的类加载器
参考API,我们知道Classloader位于java.lang包下,通常使用 loadclass方法加载一个class,一个class可以是文件系统,也可以是网络上的一个文件,甚至是一个二进制数据流。如
ClassLoader loader = new NetworkClassLoader(host, port); Object main = loader.loadClass("Main", true).newInstance();
NetworkClassLoader 继承了ClassLoader,所以需要覆盖重写findClass方法(请参考API文档findClass方法说明),同时要定义加载loadClassData方法从网络上加载二进制数据,加载完成后我们可以得到Class的引用对象,调用newInstance()方法我们就完成了一个类加载以及实例化的过程。
class NetworkClassLoader extends ClassLoader { String host; int port; public Class findClass(String name) { byte[] b = loadClassData(name); return defineClass(name, b, 0, b.length); } private byte[] loadClassData(String name) { // load the class data from the connection . . . }}
五、完整示例
我们以第四点说明的例子为入口,完整写完这个示例。
ClassLoadInstance :这个类比较简单,Transform强制类型转换为自己类型,用来判断是否是同一个class,我们从不同的classloader加载的class虽然包名和类名一致,但是不同的classloader,运行时会报出 java.lang.ClassCastException,由此证明我们实验成功
public class ClassLoadInstance { public ClassLoadInstance instance; public void Transform(Object obj) { instance = (ClassLoadInstance) obj; }}
NetworkClassLoader :这个是我们自定义的classloader,负责从网络加载class,实现一个classloader需要继承自classloader,并重写findclass方法,重要的是实现getClzData()
package com.demo.test;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.net.MalformedURLException;import java.net.URL;public class NetworkClassLoader extends ClassLoader{ private String rootUrl; public NetworkClassLoader(String url){ //super(null); this.rootUrl = url; } @Override protected Class<?> findClass(String clzName) throws ClassNotFoundException { // TODO Auto-generated method stub byte[] clzDate = null; clzDate = getClzData(clzName); return defineClass(clzName, clzDate, 0, clzDate.length); } private byte[] getClzData(String clzName){ String path = getClzPath(clzName); ByteArrayOutputStream outputStream = null; try { URL url = new URL(path); InputStream inputStream = url.openStream(); int len = -1; byte[] buff = new byte[1024*4]; outputStream = new ByteArrayOutputStream(); while((len = inputStream.read(buff))!= -1){ outputStream.write(buff, 0, len); } } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return outputStream.toByteArray(); } private String getClzPath(String clzName){ return rootUrl + clzName.replace(".", "/")+".class"; }}
NetClassLoadTest :测试实践类,证明不同的classloader加载的相同包名和类名的class,会出现类型转换异常
注意:需要先建立一个web项目,并把ClassLoadInstance.class文件放在和JSP目录同级别目录下,不是放在/WEB-INF/classes,/WEB-INF目录是不可以访问的
/** * */package com.demo.test;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;/** * @author Administrator * */public class NetClassLoadTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub String clzName = "com.demo.web.ClassLoadInstance"; String url = "http://localhost:8080/web/classes/"; NetworkClassLoader loader1 = new NetworkClassLoader(url); NetworkClassLoader loader2 = new NetworkClassLoader(url); try { Class clz1 = loader1.loadClass(clzName); Class clz2 = loader2.loadClass(clzName); Object obj1 = clz1.newInstance(); Object obj2 = clz2.newInstance(); System.out.println(clz1.getClassLoader()); System.out.println(clz1.getClassLoader().getParent()); System.out.println(clz1.getClassLoader().getParent().getParent()); try { clz1.getMethod("Transform", Object.class).invoke(obj1, obj2); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); }catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
- ClassLoader 学习笔记
- ClassLoader学习笔记
- 学习笔记---ClassLoader
- ClassLoader学习笔记
- jetty学习笔记-jetty classloader
- ClassLoader与System学习笔记
- java中Class和ClassLoader学习笔记
- JVM学习笔记一 之 ClassLoader
- ClassLoader笔记
- Classloader笔记
- ClassLoader笔记
- classLoader学习
- ClassLoader学习
- ClassLoader 学习
- JVM学习笔记5—类加载器(classloader)
- Java中ClassLoader笔记
- 读classloader笔记
- android classloader 笔记
- 粘性广播,粘性事件的区别?
- 循环队列
- leetcode经验
- sphinx中文分词搜索coreseek windows下安装与基本使用简介
- ctrl+s实现提交数据到后端
- ClassLoader学习笔记
- nginx安装
- 【奔跑的FPGA】part six VerilogHDL语言规范
- 调试技巧 在方法中打印完整的响应者链
- genymotion模拟器安装出现问题收藏
- 二进制补码
- 欢迎使用CSDN-markdown编辑器
- spirng 中禁用后缀的url访问,类似REST方式 ,spirng 4.x 之后的版本有@RestController支持
- OpenCV 图像的载入,显示,初级图像混合与输出