破坏双亲委派模型

如何打破双亲委派模型

1.自定义类加载器

  • 双亲委派模型源码

采用递归 向上委托,向下查找

 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;
        }
    }
  • 编写自定义类加载器
package jvm;

import java.io.FileInputStream;

/**
 * @author islandempty
 * @since 2021/5/16
 **/
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<?> 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) {
                    c = findClass(name);
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                byte[] data = loadByte(name);
                //defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组。
                return defineClass(name, data, 0, data.length);
            } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }
        }
    }
public static void main(String[] args) throws Exception{
        //初始化自定义类加载器,会先初始化父类ClassLoader,其中会把自定义类加载器的父加载器设置为应用程序类加载器AppClassLoader
        MyClassLoader classLoader = new MyClassLoader("G:/Spring");
        //D盘创建 artisan/com/gof/facadePattern 目录,将Boss类的复制类Boss1.class丢入该目录
        Class clazz = classLoader.loadClass("JUC\\src\\main\\java\\jvm\\Test");
        Object obj = clazz.newInstance();
        // 调用sout方法
        Method method = clazz.getDeclaredMethod("say", null);
        method.invoke(obj, null);
        System.out.println(clazz.getClassLoader().getClass().getName());
    }
}


  • 核心
//直接加载,不向上委托
Class<?> c = findLoadedClass(name);
  • 测试
    编写测试类
package jvm;

/**
 * @author islandempty
 * @since 2021/5/16
 **/
public class Test {
    public static void main(String[] args) {

    }
    public void say(){
        System.out.println("hello");
    }
}

javac编译测试类,删掉java文件,只保留class文件

  • 测试

幸好学过字节码,version 52对应的是jdk1.8,version 53对应的则是jdk1.9,所以需要1.9以上的jdk才能运行,但是没有下载jdk,所以偷个懒qwq

has been compiled by a more recent version of the Java Runtime (class file version 53.0), this version of the Java Runtime only recognizes class file versions up to 52.0

2.使用线程上下文类加载器

  • 核心
    线程上下文类加载器让父级类加载器能通过调用子级类加载器来加载类,这打破了双亲委派模型的原则

https://www.cnblogs.com/looyee/articles/13954722.html

# Java 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×