java类加载器(classLoader)
- 作用:
java.lang.classLoader类的基本职责就是根据一个指定类的名称,找到或者生成其对应的字节码,从堆中生成一个java.lang.Class类的一个实例,作为方法区类数据的访问入口 类加载器的结构
- 引导类加载器(boostrap classLoader):用来加载java的核心库,使用C语言实现的
- 扩展类加载器(extension classLoader):用来加载java的扩展库
- 应用程序类加载器(application classLoader) :根据java应用的路径classPath加载,一般,java应用的类都是由它来完成的
- 自定义类加载器:我们可以通过继承java.lang.classLoader类的方式实现自己的类加载器,以满足特殊需要。
类加载器的代理模式
- jvm默认使用的是代理模式的双亲委托机制,也就是某个特定的类加载器在接受到加载类的时候,依次追溯,直到最高的爷爷辈。如果父类无法加载才会去自己加载。这样保证了java核心库的类型安全(比如:用户自定义一个java.lang.String,这时加载器要去最顶段的引导类加载器加载,发现有这个类就直接返回了,而不会去加载用户自定义的这个String类)。但是我们平常使用的tomcat服务器加载器是会首先去尝试加载某个类,如果找不到再代理给父类。
- 自定义一个类加载器
package com.test;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class DefinedClassLoader extends ClassLoader{
private String rootDir;//文件根目录
public DefinedClassLoader(String rootDir){
this.rootDir=rootDir;
}
@Override
protected Class<?> findClass(String className) throws ClassNotFoundException{
Class<?> clazz=findLoadedClass(className);//先去查询有没有加载这个类
if(clazz != null){
return clazz;
}else{
// ClassLoader parent=this.getParent();
// clazz=parent.loadClass(className);//可以委派给父类加载器,也可以直接自己处理
byte[] classData=this.getClassData(className);
if(classData == null){
throw new ClassNotFoundException();
}else{
clazz=defineClass(className, classData, 0, classData.length);
}
}
return clazz;
}
private byte[] getClassData(String className){
String classPath=rootDir +"/"+className.replace(".", "/")+".class";
InputStream is=null;
ByteArrayOutputStream bos=null;
try {
is=new FileInputStream(new File(classPath));
bos=new ByteArrayOutputStream();
byte[] buffer=new byte[1024];
int temp=0;
while((temp=is.read(buffer))!=-1){
bos.write(buffer, 0, temp);
}
return bos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
return null;
}finally{
if(is != null){
try{
is.close();
}catch(IOException e){
e.printStackTrace();
}finally{
is = null;
}
}
}
}
public static void main(String[] args) throws ClassNotFoundException {
DefinedClassLoader definedclassLoader=new DefinedClassLoader("D:/java");
Class<?> clazz=definedclassLoader.loadClass("com.test.Test");
}
}
- 被两个类加载器加载相同的类,jvm认为是不同的类。