027-JVM-打破双亲委派机制

152 阅读2分钟
  • 为了类的安全加载,jvm 底层默认实现为双亲委派,但是在实际开发中有没有 - 打破这种双亲委派机制的情况呢?
    答案是肯定的:有

原理是什么?
前面从源码我们看到,在 ClassLoader 的 loadClass() 方法实现类具体的双亲委派逻辑,如果要打破就要用我们自己写的 ClassLoader,用我们自己的 loadClass() 方法了。这样就简单了。只需要重写 ClassLoader 的 loadClass() 方法即可!

源码,这块写的很轻清楚。
我们的目标就是让这里代码失效,换成自己的即可。

2.1 Jdk1.2 之前,自定义的 ClassLoader 均需要重写 loadClass() 方法

2.2 ThreadContextClassLoader 可以实现基础类调用实现类代码,通过 thread.setContextClassLoader 指定

2.3 热启动,热部署

在 idea 或者其他 tomcat 等工具中会用到,原理就是重写了 ClassLoader.loaderClass 方法。
下面给出例子:

2.3.1 正常的类加载

package com.yuhl.c2020.rebushu;

import com.yuhl.c2020.MyClassLoader;

/**
 * @author yuhl
 * @Date 2020/12/26 17:08
 * @Classname NomalClassLoader
 * @Description 正常部署
 */
public class NomalClassLoader {
    public static void main(String[] args) throws Exception {
        MyClassLoader msbClassLoader = new MyClassLoader();
        Class clazz = msbClassLoader.loadClass("com.yuhl.c2020.LoadClassResource");

        msbClassLoader = null;
        System.out.println(clazz.hashCode()); //1163157884

        msbClassLoader = null;

        msbClassLoader = new MyClassLoader();
        Class clazz1 = msbClassLoader.loadClass("com.yuhl.c2020.LoadClassResource");
        System.out.println(clazz1.hashCode()); //1163157884

        System.out.println(clazz == clazz1); //true
    }
}

2.3.2 热部署的类加载

package com.yuhl.c2020.rebushu;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * @author yuhl
 * @Date 2020/12/26 17:08
 * @Classname HotClassLoader
 * @Description 热部署
 */
public class HotClassLoader {
    private static class MyClassLoaderHot extends ClassLoader {
        @Override
        public Class<?> loadClass(String name) throws ClassNotFoundException {

            File f = new File("D:/tmp/jvm/" + 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);
        }
    }

    public static void main(String[] args) throws Exception {
        MyClassLoaderHot m = new MyClassLoaderHot();
        Class clazz = m.loadClass("com.yuhl.c2020.Miao");

        m = new MyClassLoaderHot();
        Class clazzNew = m.loadClass("com.yuhl.c2020.Miao");

        System.out.println(clazz == clazzNew); //false
    }
}

通过上面 2.3.1 和 2.3.2 比较很容易得出结论:真的可以热部署哦!

此处讨论的较为浅显,目的是明白有打破双亲委派机制的这种应用场景和原理存在。如需深入理解,请参见《深入java虚拟机》或看其他资料!

自律的艰辛总甜过懊悔的苦果!
专注于 java 后端技术及解决方案,善于总结,分享!
自律的艰辛总甜过懊悔的苦果!
专注于 java 后端技术及解决方案,善于总结,分享!
自律的艰辛总甜过懊悔的苦果!
专注于 java 后端技术及解决方案,善于总结,分享!