一.类加载器
类加载器是加载类的工具,它的作用是将硬盘上的.class文件加进内存,并对之进行一些处理。
java虚拟机中可安装多个类加载器,系统默认三个主要的类加载器,每个类加载器负责加载特定的类:
BootStrap xitClassLoader AppClassLoader
类加载器也是java类,因为其他是java类的类加载器也要被类加载器加载,显然必须有第一个类加载器不是java类, 这正是:BootStrap,它是由C++编写的。
java虚拟机中的所有类加载器采用具有 父子关系 的 树形结构 进行组织,在实例化每个类加载器对象时,需要为其指定一个父级类加载器对象,或者默认采用系统类加载器为其父级类加载器。
java虚拟机中可安装多个类加载器,系统默认三个主要的类加载器,每个类加载器负责加载特定的类:
BootStrap xitClassLoader AppClassLoader
类加载器也是java类,因为其他是java类的类加载器也要被类加载器加载,显然必须有第一个类加载器不是java类, 这正是:BootStrap,它是由C++编写的。
java虚拟机中的所有类加载器采用具有 父子关系 的 树形结构 进行组织,在实例化每个类加载器对象时,需要为其指定一个父级类加载器对象,或者默认采用系统类加载器为其父级类加载器。
树形结构图:
![](https://img-my.csdn.net/uploads/201303/19/1363625780_3045.png)
eg:
System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());
System.out.println(System.class.getClassLoader());
eg:
ClassLoader loader=ClassLoaderTest.class.getClassLoader();
while(loader!=null){
System.out.println(loader.getClass().getName());
loader=loader.getParent();
}
System.out.println(loader);
二.类加载器的委托机制
(1).首先当前线程的类加载器去加载线程中的第一个类。
(2).如果类A中引用了B类,java虚拟机将使用类A的加载器来加载类B
(3).还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
(2).如果类A中引用了B类,java虚拟机将使用类A的加载器来加载类B
(3).还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
思考:能否自己写一个java.lang.System类?
通常不可以,因为根据类加载器的委托机制,每次都会先委托给上级寻找,先找到的是Jdk中的java.lang.System,而不是自己写的 java.lang.System 类;但可以自己写一个类加载器,撇开器委托机制,不给它指定上级,来加载自己的类
通常不可以,因为根据类加载器的委托机制,每次都会先委托给上级寻找,先找到的是Jdk中的java.lang.System,而不是自己写的 java.lang.System 类;但可以自己写一个类加载器,撇开器委托机制,不给它指定上级,来加载自己的类
自定义类加载器
(1).自定义的类加载器必须继承ClassLoader
(2)loadClass方法与findClass方法:只需重新findClass方法,就会跳出委托机制。
(3)defineClass方法。
编程步骤:
(1).编写一个队文件内容进行监督加密的程序
(2).编写了一个自己的类加载器,可实现对加密的类进行撞在和解码。
(3)编写一个程序调用类加载器加载类,在源程序中不能用该类定义引用变量,因为编程器无法识别这个类。程序中可以除了使用C
lassLoader.load方法外,还可以使用使用设置线程的上下文加载器或者系统加载器,然后再使用Class.forName.
(2)loadClass方法与findClass方法:只需重新findClass方法,就会跳出委托机制。
(3)defineClass方法。
编程步骤:
(1).编写一个队文件内容进行监督加密的程序
(2).编写了一个自己的类加载器,可实现对加密的类进行撞在和解码。
(3)编写一个程序调用类加载器加载类,在源程序中不能用该类定义引用变量,因为编程器无法识别这个类。程序中可以除了使用C
lassLoader.load方法外,还可以使用使用设置线程的上下文加载器或者系统加载器,然后再使用Class.forName.
测试类代码:
eg:
import java.util.Date;
public class ClassLoaderAttachments extends Date {
@Override
public String toString() {
return "hello,java";
}
}
注:
这里最好继承一个类,以便于获取其实例时,定义父类的引用,而不是它自己的引用
eg:
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class MyClassLoader extends ClassLoader {
public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
String srcPath = args[0];
String destDir = args[1];
FileInputStream fis = new FileInputStream(srcPath);
String destFileName =srcPath.substring(srcPath.lastIndexOf('\\')+1);
String destPath = destDir+"\\"+destFileName;
FileOutputStream fos = new FileOutputStream(destPath);
cypher(fis, fos);
System.out.println("xxxxx");
fis.close();
fos.close();
}
private String classDir;
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// TODO Auto-generated method stub
String classFileName = classDir+"\\"+name+".class";
try {
FileInputStream fis = new FileInputStream(classFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cypher(fis,bos);
byte[] b = bos.toByteArray();
return defineClass(b, 0, b.length);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("aaaa");
return super.findClass(name);
}
public MyClassLoader(){
}
public MyClassLoader(String classDir){
this.classDir = classDir;
}
public static void cypher(InputStream ips,OutputStream ops) throws Exception{
int b = -1;
while((b=ips.read())!=-1){
ops.write(b^0xff);
}
//这时候不用关闭,谁创建资源,谁关闭资源。
}
}
调用自定义的类加载器
eg:
Class clazz = new MyClassLoader("itcastlib").loadClass("ClassLoaderAttachments");
Date d = (Date)clazz.newInstance();
System.out.println(d.toString());
类加载器的高级问题
当把我们写好的MyServlet作为jar包导入的Tomcat使用的JDK的jre/lib/ext中时,这时的MyServlet的类加载器由原来tomcat的WebAppClassLoader变成了ExtClassLoader,在加载TMyServlet时,又用到了HttpServlet,ExtClassLoader找不到就不会报错此时,只需将tomcat中包含HttpServlet的servlet-api.jar也导入ext文件夹下即可
eg:
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
ClassLoader loader = this.getClass().getClassLoader();
while(loader!=null){
out.println(loader.getClass().getName()+"<br>");
loader=loader.getParent();
}
out.close();
}
}