【实战JVM】打破双亲委派机制之自定义类加载器

在这里插入图片描述



个人名片:

在这里插入图片描述


🐼作者简介:一名大三在校生,喜欢AI编程🎋
🐻‍❄️个人主页🥇:落798.
🐼个人WeChat:hmmwx53
🕊️系列专栏:🖼️

  • 零基础学Java——小白入门必备🔥
  • 重识C语言——复习回顾🔥
  • 计算机网络体系———深度详讲
  • HCIP数通工程师-刷题与实战🔥🔥🔥
  • 微信小程序开发——实战开发🔥
  • 系统SSM框架学习——精通Spring🔥🔥🔥
  • HarmonyOS 4.0 应用开发实战——实战开发🔥🔥🔥
  • Redis快速入门到精通——实战开发🔥🔥🔥
  • RabbitMQ快速入门🔥
    🐓每日一句:🍭我很忙,但我要忙的有意义!
    欢迎评论 💬点赞👍🏻 收藏 📂加关注+


文章目录

  • 打破双亲委派机制
    • 一、自定义类加载器
      • 自定义类加载器父类怎么是AppClassLoader呢?
      • 两个自定义类加载器加载相同限定名的类,不会冲突吗?
    • 欢迎添加微信,加入我的核心小队,请备注来意


打破双亲委派机制

打破双亲委派机制历史上有三种方式,但本质上只有第一种算是真正的打破了双亲委派机制:

  • 自定义类加载器并且重写loadClass方法。Tomcat通过这种方式实现应用之间类隔离,《面试篇》中分享它的做法。
  • 线程上下文类加载器。利用上下文类加载器加载类,比如JDBC和JNDI等。
  • Osgi框架的类加载器。历史上Osgi框架实现了一套新的类加载器机制,允许同级之间委托进行类的加载,目前很少使用。

一、自定义类加载器

一个Tomcat程序中是可以运行多个Web应用的,如果这两个应用中出现了相同限定名的类,比如Servlet类,Tomcat要保证这两个类都能加载并且它们应该是不同的类。如果不打破双亲委派机制,当应用类加载器加载Web应用1中的MyServlet之后,Web应用2中相同限定名的MyServlet类就无法被加载了。

在这里插入图片描述
Tomcat使用了自定义类加载器来实现应用之间类的隔离。 每一个应用会有一个独立的类加载器加载对应的类。

在这里插入图片描述
那么自定义加载器是如何能做到的呢?首先我们需要先了解,双亲委派机制的代码到底在哪里,接下来只需要把这段代码消除即可。
ClassLoader中包含了4个核心方法,双亲委派机制的核心代码就位于loadClass方法中。

public Class<?> loadClass(String name)
类加载的入口,提供了双亲委派机制。内部会调用findClass   重要

protected Class<?> findClass(String name)
由类加载器子类实现,获取二进制数据调用defineClass ,比如URLClassLoader会根据文件路径去获取类文件中的二进制数据。重要

protected final Class<?> defineClass(String name, byte[] b, int off, int len)
做一些类名的校验,然后调用虚拟机底层的方法将字节码信息加载到虚拟机内存中

protected final void resolveClass(Class<?> c)
执行类生命周期中的连接阶段

1、入口方法:

在这里插入图片描述
2、再进入看下:

在这里插入图片描述

如果查找都失败,进入加载阶段,首先会由启动类加载器加载,这段代码在findBootstrapClassOrNull中。如果失败会抛出异常,接下来执行下面这段代码:

在这里插入图片描述
父类加载器加载失败就会抛出异常,回到子类加载器的这段代码,这样就实现了加载并向下传递。

3、最后根据传入的参数判断是否进入连接阶段:

在这里插入图片描述
接下来实现打破双亲委派机制:

package classloader.broken;//package com.itheima.jvm.chapter02.classloader.broken;

import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.ProtectionDomain;
import java.util.regex.Matcher;

/**
 * 打破双亲委派机制 - 自定义类加载器
 */

public class BreakClassLoader1 extends ClassLoader {

    private String basePath;
    private final static String FILE_EXT = ".class";

    //设置加载目录
    public void setBasePath(String basePath) {
        this.basePath = basePath;
    }

    //使用commons io 从指定目录下加载文件
    private byte[] loadClassData(String name)  {
        try {
            String tempName = name.replaceAll("\\.", Matcher.quoteReplacement(File.separator));
            FileInputStream fis = new FileInputStream(basePath + tempName + FILE_EXT);
            try {
                return IOUtils.toByteArray(fis);
            } finally {
                IOUtils.closeQuietly(fis);
            }

        } catch (Exception e) {
            System.out.println("自定义类加载器加载失败,错误原因:" + e.getMessage());
            return null;
        }
    }

    //重写loadClass方法
    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        //如果是java包下,还是走双亲委派机制
        if(name.startsWith("java.")){
            return super.loadClass(name);
        }
        //从磁盘中指定目录下加载
        byte[] data = loadClassData(name);
        //调用虚拟机底层方法,方法区和堆区创建对象
        return defineClass(name, data, 0, data.length);
    }

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
        //第一个自定义类加载器对象
        BreakClassLoader1 classLoader1 = new BreakClassLoader1();
        classLoader1.setBasePath("D:\\lib\\");

        Class<?> clazz1 = classLoader1.loadClass("com.itheima.my.A");
         //第二个自定义类加载器对象
        BreakClassLoader1 classLoader2 = new BreakClassLoader1();
        classLoader2.setBasePath("D:\\lib\\");

        Class<?> clazz2 = classLoader2.loadClass("com.itheima.my.A");

        System.out.println(clazz1 == clazz2);

        Thread.currentThread().setContextClassLoader(classLoader1);

        System.out.println(Thread.currentThread().getContextClassLoader());

        System.in.read();
     }
}

自定义类加载器父类怎么是AppClassLoader呢?

默认情况下自定义类加载器的父类加载器是应用程序类加载器:

在这里插入图片描述

以Jdk8为例,ClassLoader类中提供了构造方法设置parent的内容:

在这里插入图片描述

这个构造方法由另外一个构造方法调用,其中父类加载器由getSystemClassLoader方法设置,该方法返回的是AppClassLoader。

在这里插入图片描述

两个自定义类加载器加载相同限定名的类,不会冲突吗?

不会冲突,在同一个Java虚拟机中,只有相同类加载器+相同的类限定名才会被认为是同一个类。
在Arthas中使用sc –d 类名的方式查看具体的情况。
如下代码:

 public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
        //第一个自定义类加载器对象
        BreakClassLoader1 classLoader1 = new BreakClassLoader1();
        classLoader1.setBasePath("D:\\lib\\");

        Class<?> clazz1 = classLoader1.loadClass("com.itheima.my.A");
         //第二个自定义类加载器对象
        BreakClassLoader1 classLoader2 = new BreakClassLoader1();
        classLoader2.setBasePath("D:\\lib\\");

        Class<?> clazz2 = classLoader2.loadClass("com.itheima.my.A");

        System.out.println(clazz1 == clazz2);
     }

打印的应该是false,因为两个类加载器不同,尽管加载的是同一个类名,最终Class对象也不是相同的。
通过Arthas看:
在这里插入图片描述

也会出现两个不同的A类。


欢迎评论 💬点赞👍🏻 收藏 📂加关注+



在这里插入图片描述

欢迎添加微信,加入我的核心小队,请备注来意

👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/537076.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JVS智能BI:嵌套数据集在多层次数据关联中的实战应用

在数据分析平台中&#xff0c;数据集的嵌套调用主要用于处理复杂数据结构或多层次数据关联&#xff0c;或者有多场景使用的重复使用中间数据&#xff0c;那么就需要把某些数据生成中间结果的数据集合。 例如&#xff1a;用户的分类需要根据用户的各方面的数据特征进行分类打标…

算法设计与分析实验报告c++实现(矩阵链相乘问题、投资问题、背包问题、TSP问题、数字三角形)

一、实验目的 1&#xff0e;加深学生对动态规划算法设计方法的基本思想、基本步骤、基本方法的理解与掌握&#xff1b; 2&#xff0e;提高学生利用课堂所学知识解决实际问题的能力&#xff1b; 3&#xff0e;提高学生综合应用所学知识解决实际问题的能力。 二、实验任务 1、…

自动化测试提速必备 - 并发编程

在自动化测试领域&#xff0c;多线程和多进程技术被广泛应用于提高测试的执行效率和性能。通过并发运行测试用例&#xff0c;可以显著缩短测试周期&#xff0c;特别是在面对大量测试用例或者需要在多个环境中进行测试时尤为重要。 在实际的自动化测试中&#xff0c;我们经常碰…

2024年【T电梯修理】考试总结及T电梯修理考试技巧

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 T电梯修理考试总结考前必练&#xff01;安全生产模拟考试一点通每个月更新T电梯修理考试技巧题目及答案&#xff01;多做几遍&#xff0c;其实通过T电梯修理试题及解析很简单。 1、【多选题】修理工陶、陈&#xff0c…

废石颗粒运动理论模型及Python模拟

学者赵国彦等[26]对于废石颗粒运动的理论模型进行做了较为充分的研究&#xff0c;本文在以往研究的基础上对相关推导进行补充修正&#xff0c;并以某金矿充填废石的基本物理性能测试数据为基础&#xff0c;对废石运动理论模型的进行模拟。 4.2.1废石运动理论模型 4.2.1.1废石…

AI大模型探索之路-应用篇10:Langchain框架-架构核心洞察

目录 前言 一、LangChain设计目标 二、LangChain设计之道 三、LangChain典型应用 1、简单的问答Q&A over SQL CSV: 2、聊天机器人Chatbots: 3、总结摘要Summarization: 4、网页爬虫Web scraping: 5、本地知识库&#xff08;Q&A with RAG): 三、LangChain架构…

数字阅览室-数字图书馆体系的重要补充

数字阅览室&#xff08;Digital Reading Room&#xff09;是一种依托现代信息技术&#xff0c;特别是互联网、数字媒体技术和数据库管理技术&#xff0c;为用户提供在线访问、阅读、学习和研究各类数字化文献资源的虚拟空间。它是数字图书馆服务体系中的一个重要组成部分&#…

文库配置异步转换(宝塔)| 魔众文库系统

执行以下操作前提前进入网站根目录&#xff0c;如 cd /www/wwwroot/example.com执行 artisan 命令前请参照 开发教程 → 开发使用常见问题 → 如何运行 /www/server/php/xxx/bin/php artisan xxx 命令 步骤1&#xff0c;生成数据库队列表迁移文件 在执行该步骤前&#xff0c;请…

数据可视化高级技术Echarts(折线图)

目录 一、什么是折线图 二、如何实现 1.基本折线图 2.如何变得平滑只需要定义&#xff1a; smooth 3.如何定义线条的样式 color&#xff1a;设置线的颜色 width&#xff1a;设置线宽 type&#xff1a;设置线的类型 4.如何定义节点样式 symbol symbolSize&#xff1a…

开发着开发着,盘满了

办公电脑突然报家目录不足1G空间了, 使用 Disk Usage Analyzer 工具打开看了下, 微软还真没把我当穷人, 一个vs code给我占了30几个G的空间. 大家可能也遇到这种情况的, 看到真的让人窒息, 以前windows上被VS studio 支配C盘的感觉又回来了. 不过这个ubuntu好处理点, 我该删…

算法打卡day32

今日任务&#xff1a; 1&#xff09;738.单调递增的数字 2&#xff09;968.监控二叉树 738.单调递增的数字 题目链接&#xff1a;738. 单调递增的数字 - 力扣&#xff08;LeetCode&#xff09; 文章讲解&#xff1a;代码随想录 (programmercarl.com) 视频讲解&#xff1a;贪…

CPU核心数、线程数都是什么意思?

最早&#xff0c;每个物理 cpu 上只有一个核心&#xff0c;对操作系统而言&#xff0c;也就是同一时刻只能运行一个进程/线程。 为了提高性能&#xff0c;cpu 厂商开始在单个物理 cpu 上增加核心&#xff08;实实在在的硬件存在&#xff09;&#xff0c;也就出现了多核 cpu&…

个人博客项目笔记_07

写文章 写文章需要 三个接口&#xff1a; 获取所有文章类别 获取所有标签 发布文章 1. 所有文章分类 1.1 接口说明 接口url&#xff1a;/categorys 请求方式&#xff1a;GET 请求参数&#xff1a; 参数名称参数类型说明 返回数据&#xff1a; {"success":…

Linux启动流程,常见故障英文总结/Linux学习环境发行版本选择及运行故障(补充)

小编这里对前面文章内容进行补充 1.运维架构人员理解Linux启动流程&#xff08;对故障进行排查&#xff09;&#xff0c;企业面试面试官让面试者描述Linux启动细节&#xff0c;小编在这篇文章补充以下&#xff0c;制作了图表&#xff0c;有利于大家看懂整个流程 2.对于初学者/老…

14亿美元!德国默克与AI生物科技公司合作;马斯克Neuralink首位脑机接口植入者用意念打游戏;黄仁勋在俄勒冈州立大学开讲

AI for Science 的新成果、新动态、新视角—— 日本第一 IT 公司富士通&#xff1a;生成式 AI 加速药物研发 马斯克&#xff1a;Neuralink 首位脑机接口植入者用「意念」打游戏 默克与 AI 生物科技公司 Caris 达成合作 AI 蛋白质设计服务提供商「天鹜科技」完成数千万元 Pre…

IDEA中使用正则表达式替换时间日期

很多时候需要把系统中的时间替换成当前时间&#xff0c;这是后我们就可以把数据库SQL文件在IDEA中打开&#xff0c;然后使用正则进行替换&#xff0c;下面我们来看下&#xff1a; 1.日期格式&#xff1a;校验yyyy&#xff0d;MM&#xff0d;dd ((([0-9]{3}[1-9]|[0-9]{2}[1-9…

ELK 企业级日志分析 ELFK

一 ELK 简介 ELK平台是一套完整的日志集中处理解决方案&#xff0c;将 ElasticSearch、Logstash 和 Kiabana 三个开源 工具配合使用&#xff0c; 完成更强大的用户对日志的查询、排序、统计需求。 1 ElasticSearch&#xff1a; 是基于Lucene&#xff08;一个全文检索引擎的…

golang的引用和非引用总结

目录 概述 一、基本概念 指针类型&#xff08;Pointer type&#xff09; 非引用类型&#xff08;值类型&#xff09; 引用类型&#xff08;Reference Types&#xff09; 解引用&#xff08;dereference&#xff09; 二、引用类型和非引用类型的区别 三、golang数据类型…

李沐27_含并行连结的网络GoogLeNet_Inception——自学笔记

Inception块 1.四个路径从不同层面抽取信息&#xff0c;然后在输出通道维合并。 2.有更少的参数个数和计算复杂度&#xff08;相比于3X3和5X5卷积层&#xff09; GoogLeNet 1.五个stages&#xff0c;九个inception块 Inception各种后续变种 1.Inception-BN(V2)——使用ba…

【Harbor】harbor.yml详解

目录 前言参数详解hostnameHTTP和HTTPSinternal_tlsharbor_admin_passworddatabasedata_volumestorage_serviceclairtrivyjobservicenotificationchartlog_versionexternal_databaseexternal_redisuaaproxy 前言 网络上对Harbor相关的资料真是少之又少&#xff0c;基本上都是教…