jvm中双亲委派机制是什么?

2 个回答

  • 凤雪儿
    人总要要沉下心来过一段宁静而自省的日子来整理自己。
    ## 什么是双亲委派机制 ![image.png](https://images.codewd.com/1ccaf8ace3c32cf794f3f4a4a5ecbfed.jpg "image.png") 当一个类加载器收到了类加载请求,它首先检查自己是否已经加载过,如果自己没加载过,则把这个类委托给父类加载器去完成,如果到了顶级(没有父类加载器),还是没有加载过并且也没有找到此类,则就会要求子加载器尝试自己去加载,这个过程就是双亲委派机制 # 从源码角度看双亲委派机制 ``` 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(); try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // 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; } } ``` ## 为什么设计双亲委派机制 - 沙箱安全机制:自己写的Date类不会被加载,这样便可以防止核心API库被随意篡改 - 避免类的重复加载:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一 次,保证**被加载类的唯一性 ** ## 自定义类加载器 ``` package com.lglbc.day1; import java.io.FileInputStream; import java.lang.reflect.Method; /** * @Description TODO * @Author 乐哥聊编程 * @Date 2022/11/14 21:04 */ public class MyClassLoader extends ClassLoader{ private String classPath = "/Users/neil/Desktop/code/training-code/jvm/target"; 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; } @Override 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(); } } public static void main(String args[]) throws Exception { MyClassLoader classLoader = new MyClassLoader(); Class clazz = classLoader.loadClass("com.lglbc.UserService"); Object obj = clazz.newInstance(); Method method = clazz.getDeclaredMethod("print", null); method.invoke(obj, null); System.out.println("MyClassLoader 被"+MyClassLoader.class.getClassLoader()+"加载"); } } ```
    发布于 2022-08-04 17:30 •IP属地 贵州
    举报
    评论
    收藏

  • 蚂蚱
    在漆黑的夜里,你需要一道光照亮夜行的路,我燃烧了我自己,但也造就了你我不能相拥。
    ![image.png](https://images.codewd.com/a21b55a0a877c19771a466e8c829cde7.png) 就是类加载器一共有三种: **启动类加载器**:主要是在加载JAVA_HOME/lib目录下的特定名称jar包,例如rt.jar包,像java.lang就在这个jar包中。 **扩展类加载器**:主要是加载JAVA_HOME/lib/ext目录下的具备通用性的类库。 **应用程序类加载器**:加载用户类路径下所有的类库,也就是程序中默认的类加载器。 工作流程: 除启动类加载器以外,所有类加载器都有自己的父类加载器,类加载器收到一个类加载请求时,首先会判断类是否已经加载过了,没有的话会调用父类加载器的的loadClass方法,将请求委派为父加载器,当父类加载器无法完成类加载请求时,子加载器才尝试去加载这个类。 目的是为了保证每个类只加载一次,并且是由特定的类加载器进行加载(都是首先让启动类来进行加载)。 ```java public abstract class ClassLoader { ... public Class<?> loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); } protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { //使用synchronized加锁,保证不会重复加载 synchronized (getClassLoadingLock(name)) { //判断这个类是否已加载 Class<?> c = findLoadedClass(name); if (c == null) { ... try { if (parent != null) {//有父类加载器,让父类加载器先尝试加载 c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { } //使用当前类加载器进行类加载 if (c == null) { ... c = findClass(name); // do some stats ... } } if (resolve) { resolveClass(c); } return c; } } protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); } ... } ```
    发布于 2022-02-23 17:33 •IP属地 安徽
    举报
    评论
    收藏