博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ClassLoader类加载机制
阅读量:4202 次
发布时间:2019-05-26

本文共 7091 字,大约阅读时间需要 23 分钟。

类加载流程

Class1,Class2-> MyClassLoader1, MyClassLoader2, MyThreadClassLoader1,MyThreadClassLoader2 -> AppClassLoader -> ExtClassLoader -> BootStrap

 

每个类加载器方法流程

loadClass-> findClass -> defineClass(C++)

 

名称

描述

实现

Bootstrap

JVM内核,加载Jre/lib/rt.jar

C++,BootStrap

Extension

加载Jre/lib/ext/*.jar

Java,ExtClassLoader

Application

加载classpath指定位置,系统或应用类加载

Java,AppClassLoader

Custom

自定义类的加载器,加载自定义位置class

Java

Custom Thread

自定义线程类加载器

Java

 

Launcher$ExtClassLoader和Launcher$AppClassLoader都是URLClassLoader的子类。

父类委托机制:一个类需要被加载的时候,JVM先会调用他的父类加载器进行加载(父类加载器,不一定他们之间是继承的关系,有可能仅仅是包装的关系)。如果父类加载器加载不了,再使用其子类进行加载。如果所有父类加载器都无法加载,再通过用户自定义的findClass方法进行加载。

JVM中类用全名和ClassLoader的实例作为唯一标识(包名,类名,ClassLoader实例名).

注:不要重写loadClass方法,如果重写了loadClass方法,就会导致jvm使用MyClassLoader来加载Object、String等等一些类。

<例子>

Animal.java

package com.test;public class Animal {	public void say(){        System.out.println("hello world 2~~~");    }	}
ClassLoaderTest02.java

package com.test;import java.io.BufferedInputStream;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.Method;import java.net.URL;import java.net.URLClassLoader;public class ClassLoaderTest02 extends ClassLoader {	private String path; // 加载类的路径	private final String fileType = ".class"; // .class文件扩展名	public ClassLoaderTest02(){	}	public ClassLoaderTest02(ClassLoader parent){		super(parent);	}	public void setPath(String path) {		this.path = path;	}	/**	 * 读取class文件作为二进制流放入到byte数组中去	 * 	 * @param name	 * @return	 */	private byte[] loadClassData(String name) {		System.out.println("loadClassData~~~");		InputStream in = null;		byte[] data = null;		ByteArrayOutputStream baos = null;		try {			name = name.replace(".", "\\");			in = new BufferedInputStream(new FileInputStream(new File(path					+ name + fileType)));			baos = new ByteArrayOutputStream();			int ch = 0;			while (-1 != (ch = in.read())) {				baos.write(ch);			}			data = baos.toByteArray();		} catch (Exception e) {			e.printStackTrace();		} finally {			try {				in.close();			} catch (IOException e) {				e.printStackTrace();			} finally {				try {					baos.close();				} catch (IOException e) {					e.printStackTrace();				}			}		}		return data;	}	/**	 * 定义class对应的命名空间	 */	@Override	protected Class
findClass(String name) throws ClassNotFoundException { System.out.println("findClass~~~"); byte[] data = this.loadClassData(name); return this.defineClass(name, data, 0, data.length); } public static void main(String[] args) throws Exception { ClassLoaderTest02 loader1 = new ClassLoaderTest02(); ClassLoaderTest02 loader2 = new ClassLoaderTest02(loader1); // test01(loader1); // getParent~~~:com.test.AppClassLoader // test01(loader2); // getParent~~~:com.test.ClassLoaderTest02 // test02(loader1); // 自定義, loadClass > findClass > defineClass // test03(loader1); // 自定義, findClass > defineClass // test04(loader1); // 加载不同版本同名jar包 test05(loader1); // web环境 } /** * 正常使用AppClassLoader */ public static void test01(ClassLoaderTest02 loader) throws Exception { loader.setPath("D://workspace//java//javaTest" + "//bin//"); System.out.println("classLoader~~~:" + ClassLoaderTest02.class.getClassLoader().getClass().getName()); System.out.println("getParent~~~:" + loader.getParent().getClass().getName()); Class
clazz = loader.loadClass("com.test.Animal"); // AppClassLoader System.out.println("clazz~~~:" + clazz.getClassLoader().getClass().getName()); // System.out.println("Animal~~~:" + Animal.class.getClassLoader()); // Animal animal=(Animal) clazz.newInstance(); // animal.say(); Object animalObj = clazz.newInstance(); Method animalSay = clazz.getMethod("say"); animalSay.invoke(animalObj); } /** * 使用自定義ClassLoader * 注:(1)需要先屏蔽classpath下的Animal.class(如重命名);(2)copy .class到其它目錄(如D:\temp1) */ public static void test02(ClassLoaderTest02 loader) throws Exception { loader.setPath("D://temp1//"); System.out.println("classLoader~~~:" + ClassLoaderTest02.class.getClassLoader().getClass().getName()); System.out.println("getParent~~~:" + loader.getParent().getClass().getName()); Class
clazz = loader.loadClass("com.test.Animal"); // ClassLoaderTest02 System.out.println("clazz~~~:" + clazz.getClassLoader().getClass().getName()); Object animalObj = clazz.newInstance(); // classloader不一致, 通过reflect调用 Method animalSay = clazz.getMethod("say"); animalSay.invoke(animalObj); } /** * 使用自定義ClassLoader * 注:(1)不需要屏蔽classpath下的Animal.class;(2)copy .class到其它目錄(如D:\temp1) */ public static void test03(ClassLoaderTest02 loader) throws Exception { loader.setPath("D://temp1//"); System.out.println("classLoader~~~:" + ClassLoaderTest02.class.getClassLoader().getClass().getName()); System.out.println("getParent~~~:" + loader.getParent().getClass().getName()); Class
clazz = loader.findClass("com.test.Animal"); // 直接调用 System.out.println("clazz~~~:" + clazz.getClassLoader().getClass().getName()); Object animalObj = clazz.newInstance(); // classloader不一致, 通过reflect调用 Method animalSay = clazz.getMethod("say"); animalSay.invoke(animalObj); } /** * 使用自定義ClassLoader,加载不同版本同名jar包 * 注:(1)需要先屏蔽classpath下的Animal.class(如重命名);(2)copy .class到其它目錄(如\jar) */ public static void test04(ClassLoaderTest02 loader) throws Exception { URL url1 = new URL("file:D://workspace//jar//Animal-0.0.1.jar"); // 输出为"hello world 1!" URL url2 = new URL("file:D://workspace//jar//Animal-0.0.2.jar"); // 输出为"hello world 2~~~" URLClassLoader myClassLoader1 = new URLClassLoader( new URL[] { url1 } ); URLClassLoader myClassLoader2 = new URLClassLoader( new URL[] { url2 } ); System.out.println("myClassLoader1~~~" + myClassLoader1.getClass()); Class
clazz1 = myClassLoader1.loadClass("com.test.Animal"); Class
clazz2 = myClassLoader2.loadClass("com.test.Animal"); Object animalObj1 = clazz1.newInstance(); Object animalObj2 = clazz2.newInstance(); Method animalSay1 = clazz1.getMethod("say"); Method animalSay2 = clazz2.getMethod("say"); animalSay1.invoke(animalObj1); animalSay2.invoke(animalObj2); } /** * web环境 * JVM中类用全名和ClassLoader的实例作为唯一标识 * 参考:CSDN -> "Peter_K的专栏" -> "ClassLoader解决jar包冲突问题" */ public static void test05(ClassLoaderTest02 loader) throws Exception { URL url1 = new URL("file:D://workspace//jar//Animal-0.0.1.jar"); System.out.println("ContextClassLoader~~~" + Thread.currentThread().getContextClassLoader()); System.out.println("ContextClassLoader-getParent~~~" + Thread.currentThread().getContextClassLoader().getParent()); URLClassLoader myClassLoader1 = new URLClassLoader( new URL[] { url1 } , Thread.currentThread().getContextClassLoader()); // 当前线程类加载器 System.out.println("myClassLoader1~~~" + myClassLoader1.getClass()); Class
clazz1 = myClassLoader1.loadClass("com.test.Animal"); Object animalObj1 = clazz1.newInstance(); Method animalSay1 = clazz1.getMethod("say"); animalSay1.invoke(animalObj1); } /* * 更多参考: * 1)ITEye -> "classloader 加载同名类问题" * 2)http://blog.csdn.net/is_zhoufeng/article/details/26602689 */}
文件位置

你可能感兴趣的文章
JMeter最常用的三种类型的压力测试
查看>>
Hibernate HQL 语法大全(上)
查看>>
深入Java事务的原理与应用
查看>>
CSS单位和CSS默认值大全
查看>>
交大我来了--周末再见了
查看>>
网页中flash wmode属性
查看>>
挑战自我,勇攀高峰
查看>>
神奇的HTML5画图应用
查看>>
flex 滚动条问题
查看>>
软件开发管理中的博奕论
查看>>
计算机认证考试种类
查看>>
SQL in和exists 比较
查看>>
社会性网络服务(SNS)研究
查看>>
鼠标DarkField技术
查看>>
傻傻的我
查看>>
paypal 沙盒账号注册
查看>>
ebay 沙盒账号注册
查看>>
linux -8 Linux磁盘与文件系统的管理
查看>>
linux -8 Linux磁盘与文件系统的管理
查看>>
linux 9 -文件系统的压缩与打包 -dump
查看>>