您的位置:首页 > 其它

ClassLoader类加载机制

2016-05-13 17:06 435 查看
类加载流程

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
*/
}


文件位置





内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: