java自定义类加载器来加载本地class文件,用demo来解析类加载的双亲委派机制、沙箱机制、打破双亲委派机制

news2024/9/22 1:32:17

1、首先将class文件放入指定本地目录下

2、编写自定义类加载器demo代码来加载class文件

/**
 * @author WuSong
 * @version 1.0
 * @date 2022/12/7 12:07
 * @description
 */
public class MyClassLoaderTest {

    /**
     * 1:继承ClassLoader类
     * 2:重写findClass方法
     */
    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;
        }

        @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("D:/test");
        // java文件的本地目录:D:/test/com/wusong/jvm/User.java
        Class clazz = classLoader.loadClass("com.wusong.jvm.User");
        Object obj = (Object) clazz.newInstance();
        Method method = clazz.getDeclaredMethod("sout", null);
        method.invoke(obj,null);
        System.out.println(clazz.getClassLoader().getClass().getName());

    }


}

 3、结果+类加载器机制测试

可以看到加载了User.class的类加载器为自定义类加载器:MyClassLoader,我们看下项目中的目录:

所以自定义类加载器的父类加载器为应用程序类加载器,因为所有类加载器的顺序都是先向上委托进行加载,如果父类加载器加载类失败,没有对应的类,才会向下委托到当前类加载器进行加载。

比如本次这个例子:

1、自定义加载器:MyClassLoader执行loadClass后:

会向上委托找应用程序类加载器进行该路径类的加载,应用程序类加载器又会向上委托找扩展类加载器进行加载,扩展类加载器又会向上委托到引导类加载器进行加载,然后引导类加载器发现没有该路径的类可供加载就会向下委托给扩展类加载器进行加载,扩展类加载器发现也没有该路径可加载的类就会向下委托给应用程序类加载器进行加载,应用程序类加载器发现也没有该类路径所对应的类可供加载,最后会向下委托给MyClassLoader自定义类加载器进行加载,然后MyClassLoader自定义类加载器发现本地目录有该类可供加载,就加载进来了。

 所以加载了该类的加载器为:MyClassLoader

稍微调整一下:

将User类放入项目中的com.wusong.jvm目录中,然后我们运行一下类加载demo:

 

本次结果就为AppClassLoader:应用程序类加载器,因为在项目中有该类,就在应用程序类加载器这一步的时候加载成功了 

4、打破双亲委派机制

想要打破双亲委派机制,在自定义类加载器当中重写loadClass方法即可,但是有些类是有沙箱安全机制的,jdk约定好了只能某个类加载器来进行加载,比如:java.lang.Object、java.lang.String等,打破双亲委派机制demo源码:

/**
 * @author WuSong
 * @version 1.0
 * @date 2022/12/7 15:36
 * @description
 */
public class MyClassLoaderTestTwo {



    /**
     * 1:继承ClassLoader类
     * 2:重写findClass方法
     * 3:打破双亲委派机制的核心就是重写loadClass方法
     */
    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;
        }

        @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();
            }
        }

        /**
         * 打破双亲委派机制的核心就是重写loadClass方法
         */
        @Override
        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
//                    }

                    /**
                     * java.lang.Object 和 java.lang.Object 是java核心包,是有沙箱安全机制的,只能在最顶层的类加载器进行加载
                     * 在这里加上判断只有指定需要加载的类需要打破双亲委派机制,其它的类还是调用父类的类加载器进行加载即可
                     */
                    if (!name.equals("com.wusong.jvm.User")) {
                        c = this.getParent().loadClass(name);
                    }

                    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
                        PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                        PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                        PerfCounter.getFindClasses().increment();
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }




    }

    public static void main(String[] args) throws Exception {
        // 初始化自定义类加载器,会先初始化父类ClassLoader,其中会把自定义类加载器的父加载器设置为应用程序类加载器AppClassLoader
        MyClassLoader classLoader = new MyClassLoader("D:/test");
        // java文件的本地目录:D:/test/com/wusong/jvm/User.java
        Class clazz = classLoader.loadClass("com.wusong.jvm.User");
        Object obj = (Object) clazz.newInstance();
        Method method = clazz.getDeclaredMethod("sout", null);
        method.invoke(obj, null);
        System.out.println(clazz.getClassLoader().getClass().getName());

    }

}

 打破双亲委派机制就是:比如父类加载器可以加载user类,但是想在自定义加载器内加载user类,两个类的类路径一致,这时候就要打破双亲委派机制了,才可以加载自定义加载器内的user类,因为默认的机制的话是先向上委托父类加载器进行类的加载。

5、总结

沙箱机制:


在项目中创建了一个java.lang.String类,路径和jdk包里面的String类包路径一致,运行的时候就会报错,因为jdk的String类在引导类加载器的时候就已经加载了,而项目中的类是在应用程序类加载器中加载的,所以会报错,这就是Java类加载的沙箱机制,也避免了重复加载。

双亲委派机制:


加载某个类时会先委托父加载器寻找目标类,找不到再委托上层父加载器加载,如果所有父加载器在自己的加载类路径下都找不到目标类,则在自己的类加载路径中查找并载入目标类。比如项目中的Math类,最先会找应用程序类加载器加载,应用程序类加载器会先委托扩展类加载器加载,扩展类加载器再委托引导类加载器,顶层引导类加载器在自己的类加载路径里找了半天没找到Math类,则向下退回加载Math类的请求,扩展类加载器收到回复就自己加载,在自己的类加载路径里找了半天也没找到Math类,又向下退回Math类的加载请求给应用程序类加载器,应用程序类加载器于是在自己的类加载路径里找Math类,结果找到了就自己加载了。。双亲委派机制说简单点就是,先找父亲加载,不行再由儿子自己加载。

打破双亲委派机制:

想要打破双亲委派机制,在自定义类加载器当中重写loadClass方法即可,但是有些类是有沙箱安全机制的,jdk约定好了只能某个类加载器来进行加载,比如:java.lang.Object、java.lang.String等等,口说话说就是想要加载自己定义的一些类,但是和jdk底层的类路径冲突了,就需要打破双亲委派机制了,比如想重写和优化jdk底层的一些类,就写个自定义类加载器然后对其进行打破双亲委派机制进行类的加载即可。比如:想要优化java.lang.String类,在里面加个自定义方法,那么就把jdk里面的String类的所有内容复制到项目中自定义的String类中,然后加一个新方法,然后写一个自定义类加载器将项目中的String类进行加载即可(注意,类路径要一致,项目中的String类的路径也必须是java.lang.String)


注意:


同一个JVM内,两个相同包名和类名的类对象可以共存,因为他们的类加载器可以不一
样,所以看两个类对象是否是同一个,除了看类的包名和类名是否都相同之外,还需要他们的类
加载器也是同一个才能认为他们是同一个。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023最新扫码连wifi-扫码挪车-聚合CPS返利多合一小程序源码

2023最新扫码连wifi-扫码挪车-聚合CPS返利多合一系统 系统特点: 目前已接入的 CPS 渠道: 充值:话费充值、电费充值、影视会员充值、会员卡券充值 本地团购:联联周边游 电商平台:京东、拼多多、唯品会、淘宝、抖音美团:外卖、闪购、酒店、到店、优选饿了么:外卖、商超 出行服务:…

高压放大器在压电驱动器的机翼除冰方法研究中的应用

实验名称&#xff1a;高压放大器基于压电驱动器的机翼除冰方法研究 研究方向&#xff1a;压电效应、多普勒激光测振 实验原理&#xff1a;多普勒激光测振仪是基于多普勒激光测振原理工作的&#xff0c;当四边固支的矩形板通过驱动器激振起来时&#xff0c;通过激光扫描铝板上的…

知识图谱-KGE-语义匹配-双线性模型(打分函数用到了双线性函数)-2012:LFM(Latent Factor Model)

【paper】 A latent factor model for highly multi-relational data 【简介】 这篇文章是法国的研究团队发表在 NIPS 2012 上的文章&#xff0c;还挂了 Antoine Bordes 的名字。文章提出了 LFM&#xff08;Latent Factor Model&#xff09;&#xff0c;主要贡献有两点&#x…

机床测头应用一:仿形加工功能,降低废品率

机床测头是一种可安装在大多数数控机床上&#xff0c;并在加工循环中自动对工件的尺寸及位置进行测量的装置&#xff0c;使用合适的测量程序&#xff0c;还可以根据测量结果实现自动刀路补偿&#xff0c;可以保证“第一件和第一百件尺寸一致”&#xff0c;是批量生产中不可缺少…

PLC程序实例三:ModBusRTU客户端编程实例与测试方法

一、需求描述 1、设备作为ModBusRTU服务端时&#xff0c;需要给出对应的测试方法&#xff0c;即 PLC 作为主站&#xff0c;设备作为从站使用&#xff08;本文编写的是PLC主站程序&#xff09; 2、业务与上一篇文章ModBusTCP网络触发业务逻辑一致&#xff0c;描述如下&#xf…

SpringCloud学习笔记 - Nacos服务注册中心 - Nacos Discovery

1. Nacos简介 Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称&#xff0c;一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集&#xff0c;帮助您…

Git实战 | 让工作更高效,搞定Git的分支管理

上一篇讲到Git的分支管理实操&#xff0c;在线合并和本地合并都进行了实操。毕竟&#xff1a;光说不练是假把式。而只练不整理&#xff0c;只能是傻把式了。分支管理到底如何进行管理呢&#xff1f; 先以GitLab上的一张经典的图打头&#xff0c;作为一个总体概览&#xff0c;也…

汇编语言程序设计期末复习

汇编期末复习 第一章 汇编语言基础知识 机器指令&#xff1a;cpu能直接识别并遵照执行的指令&#xff0c;用二进制编码表示&#xff0c;由操作码&#xff0c;操作数组成&#xff0c;编码只含二进制0或1 机器语言&#xff1a;用二进制编码组成的机器指令的集合和一组使用机器…

java swing(GUI) MySQL实现的视频播放器系统源码+运行教程

今天给大家演示一下由Java swing实现的一款简单的多媒体播放器&#xff0c;项目源码我会放在我的网站上&#xff0c;并配有视频配置教程&#xff0c;保证运行起来的。这个小播放器实现了视频、音频文件的播放、暂停、快进、快退、停止、全屏等功能&#xff0c;还有历史记录功能…

Nacos学习

Nacos NacosNacosNacos 简介核心特性&#xff1a;Nacos 启动启动运行(windows)standalone&#xff08;单节点&#xff09;cluster模式Nacos Server 的配置数据是存在哪里呢&#xff1f;测试demo项目结构统一配置中心命名空间、分组、文件新建bootstrap.properties文件依赖contr…

字符串相似及匹配 Jaro-Winkler

前言 String str1 "明天吃红烧肉"; String str2 "明天中午吃红烧肉"; String str3 "明天吃红烧肉&#xff1f;"; String str4 "吃红烧肉";用普通的相等判断&#xff0c;只能得到是或否&#xff0c;但如果你在实际的业务需求中&am…

【中国信通院|低代码·无代码应用沙龙】低代码平台在云智慧的实践探索

从2014年 Forrester Research 首次提出“低代码开发平台&#xff08;LCAP&#xff09;”这一概念开始&#xff0c;低代码行业便备受关注。随着 SaaS 场景的加持&#xff0c;aPaaS 场景也被孵化了出来。与此同时&#xff0c;随着近两年 Outsystems 的快速发展&#xff0c;让其成…

猜数字-第11届蓝桥杯Scratch选拔赛真题精选

[导读]&#xff1a;超平老师计划推出Scratch蓝桥杯真题解析100讲&#xff0c;这是超平老师解读Scratch蓝桥真题系列的第97讲。 蓝桥杯选拔赛每一届都要举行4~5次&#xff0c;和省赛、国赛相比&#xff0c;题目要简单不少&#xff0c;再加上篇幅有限&#xff0c;因此我精挑细选…

【Unity】Entities 1.0 学习(二):调试工具

在 Entites 1.0 &#xff0c;Unity修改了之前的调试面板&#xff0c;以及在场景下构建 Ecs World 的流程&#xff0c;较之前的版本差别还是蛮大的。 之前的学习大多集中在代码和语法&#xff0c;很多是对之前成熟的代码做升级改造&#xff0c;所以没有用到新的调试工具。但是最…

Java以Graph方式发送Outlook、Exchange邮件(2022新版)

目录 问题提出 问解决题 注意 1、注册应用程序 2、引入需要依赖jar包——重点 3、微软管理员授予应用合适权限 参考链接 问题提出 在2022年10月份&#xff0c;微软公司出于安全考虑&#xff0c;陆续取消了Exchange邮件发送的Basic认证。通俗来说就是不能再用用户名密码…

ModuleNotFoundError: No module named ‘System‘解决办法

本人在做python和halcon接口的时候发现程序需要System库&#xff0c;报下面的错误 Traceback (most recent call last): File "D:/Project/pyhalcon/pcbhalcon.py", line 2, in <module> import System ModuleNotFoundError: No module named System Process …

APP隐私合规现状与防范措施

背景 2021年11月1《个人信息保护法》正式施行&#xff0c;标志信息保护进入强监管时代&#xff0c;APP监管被提升到前所未有的高度&#xff0c;数据安全、用户隐私、甚至功能体验等各个方面都出台了相应的规则规范&#xff0c;监管的初衷是&#xff1a;从各个层面保障用户的权…

Stimulsoft Reports.JAVA 2022.4.5 Crack

Stimulsoft Reports.JAVA Java 报表工具 Stimulsoft Reports.JAVA 是一种报告工具&#xff0c;用于在您的 Java 应用程序中进行业务报告的交互和工作。它包含 Java 和 HTML5 组件&#xff0c;允许您在不同平台、不同操作系统和不同硬件上使用创建的程序。因此&#xff0c;我们的…

树上的小兔子,藏了服务的新逻辑

【潮汐商业评论/原创】 自从一连三日委托会务组组织会议&#xff0c;Shirley在雅琳那收获了一个熟悉的称呼&#xff1a;雪梨&#xff0c;这是Shirley在部门内的“代号”&#xff0c;在过去独属于她最亲密的几位同事。 熟悉的称呼让她们感觉既轻松又亲近。然而&#xff0c;跳出…

虹科分享 | 加密U盘 | 何时使用USB驱动器进行备份(何时不用)

在存档或备份数字资产或数据时&#xff0c;有多种选择。虽然每个公司的需求和要求各不相同&#xff0c;但没有一种放之四海而皆准的方法或解决方案。在这里&#xff0c;我们将看看USB驱动器的优点和陷阱&#xff0c;USB驱动器是专业人士和个人用于存档和备份的最常见存储选项。…