java双亲委派机制

张开发
2026/4/20 7:16:33 15 分钟阅读

分享文章

java双亲委派机制
1.类的加载过程当我们在使用某个对象时jvm需要先将class文件加载进内存大概流程如下加载将硬盘上的class文件读到内存生成一个Class对象这一步通常是在使用到这个类时 才进行加载属于懒加载验证校验class字节码文件是否符合java规范准备给静态变量分配内存进行初始化这里的初始化是指按照jvm的规范赋默认值并不是类中定义的值解析将class文件的符号引用替换为直接引用符号引用指的是我们在类中写的各种关键字替换为内存地址也就是静态链接初始化对静态变量赋值执行静态代码块类加载到方法区后会创建一个Class对象放到堆区heap2.类加载器和双亲委派机制引导类加载器BootstrapClassloader负责加载jre下lib包下的核心类库如rt.jar等扩展类加载器ExtClassloader用于加载jre下lib/ext下的类库应用类加载器AppClassloader用于加载我们自己的应用类直接上代码java的两个类加载器都是Launcher.class的内部类都继承URLClassLoader在创建Launcher对象时会初始化AppClassLoader对象,并且指定parent为ExtClassLoader经过一系列的点点后到了这里parentExtClassLoader2.1 类加载器的源码入口是执行AppClassLoader的loadclass方法,最终都会执行到其父类的loadclass方法在这里首先会从AppClassLoader拿一次看有没有加载过如果加载了就直接返回如果没有则调用parent再次执行loadclass方法父类也没有则调用findBootstrapClassorNull去获取。缓存中没有加载的话就再从父到子去加载。流程图也如下2.2 打破双亲委派机制要打破双亲委派机制就要重写loadclass方法可以模仿Tomcat的写法重写findclass的逻辑自己读取class文件然后传到defindClass方法这样就完成了自定义类加载器package com.test; import java.io.FileInputStream; import java.lang.reflect.Method; public class MyClassLoader extends ClassLoader{ private String classPath; public MyClassLoader(String classPath) { this.classPath classPath; } protected Class? loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class? c findLoadedClass(name); if (c null) { long t0 System.nanoTime(); if(!name.startsWith(com.classload)){ cgetParent().loadClass(name); }else { c findClass(name); } long t1 System.nanoTime(); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } if (resolve) { resolveClass(c); } return c; } } protected Class? findClass(final String name) { byte[] b new byte[0]; try { b loadByte(name); } catch (Exception e) { e.printStackTrace(); } return defineClass(name, b, 0, b.length); } 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; } public static void main(String[] args) throws Exception { MyClassLoader myClassLoader new MyClassLoader(/Users/ligang/Desktop/code/test); Class? aClass myClassLoader.loadClass(com.classload.User); Object o aClass.newInstance(); Method print aClass.getDeclaredMethod(print, null); print.setAccessible(true); print.invoke(o,null); System.out.println(aClass.getClassLoader().getClass().getName()); } }执行结果Connected to the target VM, address: 127.0.0.1:50906, transport: socket 加载成功 com.test.MyClassLoader Disconnected from the target VM, address: 127.0.0.1:50906, transport: socket Process finished with exit code 0

更多文章