打破类加载双亲委派机制
(26条消息) java编程之自定义类加载器以及打破类加载双亲委派的方法_天码行空码飞舞的博客-CSDN博客_自定义类加载器,如何打破双亲委派
1.如何自定义类加载器
我们就知道关键的方法是findClass,那我们只要继承ClassLoader,重写findClass方法就好了(里面调用了defineClass方法)。
package com.loman.classloader;
import com.loman.classloader.Test;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
public class CustomClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
File f = new File("d:/test/", name.replace(".", "/").concat(".class"));
FileInputStream fis = null;
ByteArrayOutputStream baos = null;
try {
fis = new FileInputStream(f);
baos = new ByteArrayOutputStream();
int b = 0;
while ((b=fis.read()) !=0) {
baos.write(b);
}
byte[] bytes = baos.toByteArray();
return defineClass(name, bytes, 0, bytes.length);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(baos != null) {
baos.close();
}
if(fis != null) {
fis.close();
}
}
return super.findClass(name); //throws ClassNotFoundException
}
public static void main(String[] args) throws Exception {
ClassLoader l = new CustomClassLoader();
Class clazz = l.loadClass("com.loman.classloader.Test");
Class clazz1 = l.loadClass("com.loman.classloader.Test");
System.out.println(clazz == clazz1);
Test h = (Test)clazz.newInstance(); //Test是自己定义的一个类,代码就不贴了
h.method1(); //Test类的实例方法
System.out.println(l.getClass().getClassLoader());
System.out.println(l.getParent());
System.out.println(getSystemClassLoader());
}
}
2.打破双亲委派

从图中可以看出,双亲委派是一个自底向上逐层检查类是否加载,自顶向下逐层进行实际查找和加载的过程,有点递归的意思。检查的过程就是加载之前,先检查一下是不是已经加载过了,如果自己加载了那就返回结果,如果自己没加载,那就问问父加载器(注意不是类加载器的加载器,也不是类加载器的父类加载器)是否加载了,如果父类加载器加载了就直接返回结果,如果没有就继续往上一层去检查。那如果到了最顶层的类加载器还是没有加载的话,那就“调头”,逐层往下去查找,如果能找到(类加载器有各自的“责任范围”)那就加载,然后返回结果,如果找不到,那就交给下一层,这样层层递推。如果到最底层还是找不到,怎么办?这时会抛出异常:ClassNotFoundException,这个异常相信大家都不陌生,那可能的原因就是.class文件的路径写错了,或者文件不存在。
双亲委派的目的主要是为了安全,其次就是避免重复加载。
既然我们知道了双亲委派的原理流程,那要怎么去打破它呢?通过分析jdk源码,可以得到答案,那就是在自定义类加载器的基础上,重写loadClass方法。这里我就只贴重写的loadClass方法
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
File f = new File("D:/test/" + name.replace(".", "/").concat(".class"));
if(!f.exists()) return super.loadClass(name);
try {
InputStream is = new FileInputStream(f);
byte[] b = new byte[is.available()];
is.read(b);
return defineClass(name, b, 0, b.length);
} catch (IOException e) {
e.printStackTrace();
}
return super.loadClass(name);
}
(26条消息) 为什么tomcat要打破类加载概念 – CSDN
1. Tomcat类加载机制要考虑的问题
Tomcat作为Servlet容器,它负责加载我们的Servlet类,此外它还负责加载Servlet所依赖的 JAR 包。并且Tomcat本身也是也是一个Java程序,因此它需要加载自己的类和依赖的JAR包,所以可能要考虑这几个问题:
- 假如在Tomcat中运行了两个Web应用程序,两个Web应用中有同名的 Servlet,但是功能不同,Tomcat需要同时加载和管理这两个同名的Servlet 类,保证它们不会冲突,也就是说,Web应用之间的类需要隔离
- 假如两个Web应用都依赖同一个第三方的JAR包,比如Spring,那Spring的JAR包被加载到内存后,Tomcat要保证这两个Web应用能够共享,也就是说Spring的JAR包只被加载一次,否则随着依赖的第三方JAR包增多,JVM 的内存会膨胀
- Tomcat自身也是一个Java程序,需要隔离Tomcat本身的类和Web应用的类,避免相互影响,比如Web应用中定义了一个同名类导致Tomcat本身的类无法加载
所以,Tomcat是如何来解决这些问题的?答案是通过设计多层次的类加载器。

热加载、osgi等都打破了双亲委派。