1.4 打破双亲委派机制

什么是打破双亲委派机制呢?

那么这里第一步,我们需要知道什么是双亲委派机制?

前面已经说了什么是双亲委派机制了,那打破是怎么回事呢?

 

 

 比如,我现在有一个自定义类加载器,加载的是~/com/lxl/jvm/User1.class类,而在应用程序的target目录下也有一个com/lxl/jvm/User1.class,  那么,最终User1.class这个类将被哪个类加载器加载呢? 根据双亲委派机制,我们知道,他一定是被应用程序类加载器AppClassLoader加载,而不是我们自定义的类加载器,为什么呢? 因为他要向上寻找,向下委托. 当找到了以后,便不再向后执行了. 

我们要打破双亲委派机制,就是要让自定义类加载器来加载我们的User1.class,而不是应用程序类加载器来加载

 

接下来分析,如何打破双亲委派机制呢? 双亲委派机制是在哪里实现的? 是在ClassLoader类的loadClass(...)方法实现的. 如果我们不想使用系统自带的双亲委派模式,只需要重新实现ClassLoader的loadClass(...)方法即可. 下面是ClassLoader中定义的loadClass()方法. 里面实现了双亲委派机制

 

 

 

下面给DefinedClassLoaderTest.java增加一个loadClass方法,拷贝上面的代码即可. 删除掉中间实现双亲委派机制的部分

 

 

 这里需要注意的是,com.lxl.jvm是自定义的类包,只有我们自己定义的类才从这里加载. 如果是系统类,依然使用双亲委派机制来加载.

来看看运行结果:

调用了user1的sout方法
com.lxl.jvm.DefinedClassLoaderTest

 

现在User1方法确实是由自定义类加载器加载的了

 源码:

package com.lxl.jvm;

import java.io.FileInputStream;
import java.lang.reflect.Method;

/**
 * 自定义的类加载器
 */
public class DefinedClassLoaderTest extends ClassLoader{

    private String classPath;

    public DefinedClassLoaderTest(String classPath) {
        this.classPath = classPath;
    }

    *
     * 重写findClass方法
     *
     * 如果不会写,可以参考URLClassLoader中是如何加载AppClassLoader和ExtClassLoader的
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            byte[] data = loadBytes(name);
            return defineClass(name,data,0,data.length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    private byte[] loadBytes(String name) throws Exception {
        // 我们需要读取类的路径
        String path = name.replace('.',1)">/').concat(".class");
        String path = "";
         去路径下查找这个类
        FileInputStream fileInputStream = new FileInputStream(classPath + "  + path);
        int len = fileInputStream.available();

        byte[] data = new [len];
        fileInputStream.read(data);
        fileInputStream.close();

        return data;
    }

     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 == ) {
                *
                 * 直接执行findClass()...什么意思呢? 首先会使用自定义类加载器加载类,不在向上委托,直接由
                 * 自己执行
                 *
                 * jvm自带的类还是需要由引导类加载器自动加载
                 */
                if (!name.startsWith(com.lxl.jvm)) {
                    c = this.getParent().loadClass(name);
                } else {
                    c = findClass(name);
                }
            }
            if (resolve) {
                resolveClass(c);
            }
             c;
        }
    }

    static void main(String[] args) throws Exception {
        DefinedClassLoaderTest classLoader = new DefinedClassLoaderTest(/Users/luoxiaoli);
        Class<?> clazz = classLoader.loadClass(com.lxl.jvm.User1);
        Object obj = clazz.newInstance();
        Method sout = clazz.getDeclaredMethod(sout",);
        sout.invoke(obj,);
        System.out.println(clazz.getClassLoader().getClass().getName());
    }

} 

 

相关文章

jinfo 命令可以用来查看 Java 进程运行的 JVM 参数,命令如下...
原文链接:https://www.cnblogs.com/niejunlei/p/5987611.ht...
java 语言, 开发者不能直接控制程序运行内存, 对象的创建都是...
jvm
1.jvm的简单抽象模型:  2.类加载机制     双亲委派模...
堆外内存JVM启动时分配的内存,称为堆内存,与之相对的,在代...
1.springboot和tomcat2.springcloud的请求如何通过网关鉴权?...