专栏首页盛开在夏天的太阳1.4 打破双亲委派机制

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('.', '/').concat(".class");
        //String path = "";
        // 去路径下查找这个类
        FileInputStream fileInputStream = new FileInputStream(classPath + "/"  + path);
        int len = fileInputStream.available();

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

    public 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", null);
        sout.invoke(obj, null);
        System.out.println(clazz.getClassLoader().getClass().getName());
    }

} 

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 1.5 tomcat是如何打破双亲委派机制的?

    首先, 来举个例子, 通常,一个tomcat要加载几个应用程序呢? 当然是n多个应用程序, 加入我们使用的都是spring的框架, 那我们能保证所有的应用程序都...

    用户7798898
  • 重新初始化k8s master节点

    卸载k8s, 可以参考这篇文章: https://blog.csdn.net/ccagy/article/details/85845979

    用户7798898
  • 1.2 双亲委派机制及其原理

    参考博客: https://www.cnblogs.com/ITPower/p/13197220.html

    用户7798898
  • 通过源码浅析Java中的资源加载

    最近在做一个基础组件项目刚好需要用到JDK中的资源加载,这里说到的资源包括类文件和其他静态资源,刚好需要重新补充一下类加载器和资源加载的相关知识,整理成一篇文章...

    Throwable
  • (JVM)Java虚拟机:手把手带你深入了解类加载器(含双亲委派模型讲解)

    即实现 类加载过程中“加载”环节里 “通过类的全限定名来获取定义此类的二进制字节流” 的功能

    Carson.Ho
  • Mybatis入门

    发现一个非常好的Mybatis详细教程,地址:https://www.w3cschool.cn/mybatis/

    SuperHeroes
  • 一个小时学会MySQL数据库

    随着移动互联网的结束与人工智能的到来大数据变成越来越重要,下一个成功者应该是拥有海量数据的,数据与数据库你应该知道。 一、数据库概要 数据库(Database)...

    张果
  • Zepto中数据缓存原理与实现

    基本用法大家肯定很熟悉,需要注意的地方是,我们也可以直接获取定义在html标签上以data-为前缀的属性。接下来我们就直接看源码实现啦

    IMWeb前端团队
  • Zepto中数据缓存原理与实现

    本文作者:IMWeb 谦龙 原文出处:IMWeb社区 未经同意,禁止转载 前言 以前我们使用Zepto进行开发的时候,会把一些自定义的数据存到dom...

    IMWeb前端团队
  • 一个小时学会MySQL数据库

    随着移动互联网的结束与人工智能的到来大数据变成越来越重要,下一个成功者应该是拥有海量数据的,数据与数据库你应该知道。

    张果

扫码关注云+社区

领取腾讯云代金券