黑马程序员-ClassLoader
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
概念:
ClassLoader(类装载器),类加载器是负责加载类的对象。ClassLoader 类是一个抽象类。如果给定类的二进制名称,那么类加载器会试图查找或生成构成类定义的数据。一般策略是将名称转换为某个文件名,然后从文件系统读取该名称的“类文件”。
每个Class对象都包含一个对定义它的ClassLoader的引用。
java中的装载器:
1. BootStrap: 在java虚拟机启动时会用这个装载器来装载JDK安装目录下的jre\lib\rt.jar,也就是java中一些核心的类,如System类,这个装载器底层是用c++写的,是嵌入在jvm中的,所以它不是java类。只是作为一个java中类的起源工具。
2.ExtClassLoader:这个类加载器加载JDK安装目录下的/JRE/LIB/ext/*.jar 所有的类 我们只要把我们的类打包成JAR包放在这里即可。这个装载器是一个java类。
3.AppClassLoader:我们在java程序中classpath对应的类都有这个AppClassLoader导入进来。这个装载器也是一个java类。
类装载器的工作原理和委托模型:
上图是java中类装载器的委托模型,当我们在程序中用到某个类时,jvm首先判断该类在那个类装载器下(即为发起者),然后先用BootStrap这个装载器去找这个类,如果没有就转到ExtClassLoader去装载,再没有就用AppClassLoader这样一级一级的往下找,这就是所谓的父类委托机制。当找到发起者这里时,如果还未找到,就会抛出ClassNotFoundException异常。
顺便提个小问:我们为什么不利用AppClassLoader下级的加载器呢?
答:因为AppClassLoader下级可能有多个类加载器多个类加载器相互独立,如果加载类那么就会导致内存中出现多份字节码,造成不必要的的内存浪费。这就是类加载器的委托模型。
如何自定义类装载器?
1.首先写一个类继承ClassLoader
public class MyClassLoader extends ClassLoader{
private String attachment;//接收自定义的装载目录。
public MyClassLoader(){
}
public MyClassLoader(String attachment){
this.attachment=attachment;
}
public static void main(String[] args) throws Exception {
String srcPath=args[0];
String destPath=args[1]+"\\"+srcPath.substring(srcPath.lastIndexOf('\\')+1);
FileInputStream in=new FileInputStream(srcPath);
FileOutputStream out=new FileOutputStream(destPath);
cypher(in,out);//定义自己类装载器的加解密算法。
in.close();
out.close();
}
public static void cypher(InputStream src,OutputStream dest) throws Exception{
int len=0;
while((len=src.read())!=-1){
dest.write(len ^ 0xf);
}
}
@Override
//要写自己的classloader,建议覆盖findClass方法。若果要覆盖loadClass方法将会很复杂,请参考api。
protected Class<?> findClass(String name) throws ClassNotFoundException {
String srcPath=this.attachment+"\\"+name.substring(name.lastIndexOf('.')+1)+".class";
FileInputStream in=null;
try {
in=new FileInputStream(srcPath);
ByteArrayOutputStream out=new ByteArrayOutputStream();
cypher(in, out);
in.close();
System.out.println("aaaaa");// 验证是否是自定义类装载器装载
byte[] arrs=out.toByteArray();
return defineClass(arrs, 0, arrs.length);//返回字节码文件对象。
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
2.建立自定义装载目录,这里是MyClassPath
3.建立测试类测试自定义类装载器
//测试自己的类装载器
public class ClassLoaderTest {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//loadClass方法先会检查是否已装载类,然后调用父类的loadClass方法,如果父类类加载器为null,即为Bootstrap加载器,并且没找到class字节码,就调用自己类装载器的findClass方法
Class clazz=new MyClassLoader("MyClassPath").loadClass("cn.jiava.classloader.MyClassLoaderAttachment");
Date mAttachment=(Date) clazz.newInstance();
System.out.println(mAttachment);
System.out.println(clazz.getClassLoader());
}
}
知识拓展:
用自定义的类转载器,可以对字节码进行加密和解密,这样可以对class字节码文件又一定的保护作用。
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------