作者: | 来源:互联网 | 2023-10-10 18:47
下面手把手用代码来实现打破JVM的双亲委派机制
一、Tomcat打破双亲委派机制
以Tomcat类加载为例,Tomcat作为web容器, 那么它要解决什么问题呢?Tomcat 如果使用默认的双亲委派类加载机制行不行?
1.1 Tomcat作为web容器, 那么它要解决什么问题呢?
1.2 Tomcat 如果使用默认的双亲委派类加载机制行不行?
答案是不行的。为什么?
二、Tomcat自定义加载器详解
2.1 tomcat的主要类加载器
从图中的委派关系中可以看出:
tomcat 这种类加载机制违背了java 推荐的双亲委派模型了吗?
答案是:违背了。 很显然,tomcat 不是这样实现,tomcat 为了实现隔离性,没有遵守这个约定,每个webappClassLoader加载自己的目录下的class文件,不会传递给父类加载器,打破了双亲委派机制。
2.2 模拟Tomcat实现打破双亲委派机制
模拟实现Tomcat的webappClassLoader加载自己war包应用内不同版本类实现相互共存与隔离
package cn.phlos.csdn.demo;import java.io.FileInputStream;
import java.lang.reflect.Method;public class MyClassLoaderTest {static class MyClassLoader extends ClassLoader {private String classPath;public MyClassLoader(String classPath) {this.classPath = classPath;}private byte[] loadByte(String name) throws Exception {name = name.replaceAll("\\.", "/");FileInputStream fis = new FileInputStream(classPath + "/" + name + ".class");int len = fis.available();byte[] data = new byte[len];fis.read(data);fis.close();return data;}protected Class> findClass(String name) throws ClassNotFoundException {try {byte[] data = loadByte(name);return defineClass(name, data, 0, data.length);} catch (Exception e) {e.printStackTrace();throw new ClassNotFoundException();}}/*** 重写类加载方法,实现自己的加载逻辑,不委派给双亲加载** @param name* @param resolve* @return* @throws ClassNotFoundException*/protected Class> loadClass(String name, boolean resolve)throws ClassNotFoundException {synchronized (getClassLoadingLock(name)) {// First, check if the class has already been loadedClass> c = findLoadedClass(name);if (c == null) {// If still not found, then invoke findClass in order// to find the class.long t = System.nanoTime();//非自定义的类还是走双亲委派加载if (!name.startsWith("cn.phlos.csdn.demo")) {c = this.getParent().loadClass(name);} else {c = findClass(name);}// this is the defining class loader; record the statssun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t);sun.misc.PerfCounter.getFindClasses().increment();}if (resolve) {resolveClass(c);}return c;}}}public static void main(String args[]) throws Exception {MyClassLoader classLoader = new MyClassLoader("D:/test/2023/demo/");Class clazz = classLoader.loadClass("cn.phlos.csdn.demo.MyTest");Object obj = clazz.newInstance();Method method = clazz.getDeclaredMethod("sout", null);method.invoke(obj, null);System.out.println(clazz.getClassLoader());System.out.println();MyClassLoader classLoader1 = new MyClassLoader("D:/test/2023/demo1/");Class clazz1 = classLoader1.loadClass("cn.phlos.csdn.demo.MyTest");Object obj1 = clazz1.newInstance();Method method1 = clazz1.getDeclaredMethod("sout", null);method1.invoke(obj1, null);System.out.println(clazz1.getClassLoader());}
}
注意:同一个JVM内,两个相同包名和类名的类对象可以共存,因为他们的类加载器可以不一样,所以看两个类对象是否是同一个,除了看类的包名和类名是否都相同之外,还需要他们的类加载器也是同一个才能认为他们是同一个。
代码运行步骤:
第一步下载MyTest类,以准备好,下载地址:点击下载-2023.zip
第二步把下载好的压缩包进行解压,修改代码里的D:/test为你解压的路径
第三步,运行上面的代码