JVM自定义类加载器在代码扩展性的实践

基于Simulink使用激光雷达数据跟踪车辆仿真(附源码) 这些模型将长方体的尺寸定义为状态转换期间的常量,并且它们的估计值在滤波器的校正阶段随时间演变。下面的动画显示了在滤波器的预测阶段将具有不同概率的恒定速度和恒定转弯率模型混合在一起的效果。此示例显示了如何使用带有 IMM 过滤器的 JPDA 跟踪器来跟踪使用激光雷达传感器的对象。图像和激光雷达数据读取器从 MAT 文件中读取记录的数据,并分别输出参考图像和点云中点的位置。跟踪器块选中“启用所有轨道输出”和“启用可检测的跟踪 ID 输入”复选框,以从跟踪器输出所有轨道,并将其检测概率作为其状态的函数进行计算。 阅读详情

一、背景

名单管理系统是手机上各个模块将需要管控的应用配置到文件中,然后下发到手机上进行应用管控的系统,比如各个应用的耗电量管控;各个模块的管控应用文件考虑到安全问题,有自己的不同的加密方式,按照以往的经验,我们可以利用模板方法+工厂模式来根据模块的类型来获取到不同的加密方法。代码类层次结构示意如下:

获取不同加密方法的类结构图

利用工厂模式和模板方法模式,在有新的加密方法时,我们可以通过添加新的handler来满足"对修改关闭,对扩展开放"的原则,但是这种方式不可避免的需要修改代码和需要重新发版本和上线。那么有没有更好的方式能够去解决这个问题,这就是我们今天要重点讲的主题。

二、类加载的时机

一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经历 加载 (Loading)、 验证 (Verification)、 准备 (Preparation)、 解析 (Resolution)、 初始化 (Initialization)、 使用 (Using)和 卸载 (Unloading)七个阶段,其中验证、准备、解析三个部分统称为连接(Linking)。这七个阶段的发生顺序如图1所示。

虽然classloader的加载过程有复杂的7步,但事实上除了加载之外的四步,其它都是由JVM虚拟机控制的,我们除了适应它的规范进行开发外,能够干预的空间并不多。而加载则是我们控制classloader实现特殊目的最重要的手段了。这就是接下来我们介绍的重点了。

三、加载

“加载”(Loading)阶段是整个“类加载”(Class Loading)过程中的一个阶段。在加载阶段,Java虚拟机需要完成以下三件事情:

  • 通过一个类的全限定名来获取定义此类的二进制字节流。
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
  • 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

《Java虚拟机规范》对这三点没有进行特别具体的要求,从而留给虚拟机实现与Java应用的灵活度都是相当大的。例如“通过一个类的全限定名来获取定义此类的二进制字节流”这条规则,它并没有指明二 进制字节流必须得从某个Class文件中获取,确切地说是根本没有指明要从哪里获取、如何获取。比如我们可以从ZIP压缩包中读取、从网络中获取、运行时计算生成、由其他文件生成、从数据库中读取。也可以从加密文件中获取。

从这里我们可以看出,只需要我们能够获取到加密类的.class文件,我们就可以通过类加载器获取到对应的加密类class对象,进而通过反射去调用具体的加密方法。因此类加载器在.class文件的加载过程有着至关重要的地位。

四、双亲委派模型

目前Java虚拟机已经存在三种类加载器,分别为启动类加载器、扩展类加载器和应用程序类加载器;绝大多数的Java程序都会使用这三种类加载器进行加载。

4.1 启动类加载器

这个类由C++实现,负责加载存放在\lib目录,或者被-Xbootclasspath参数所指定的路径中存放的,而且是Java虚拟机能够识别的(按照文件名识别,如rt.jar、tools.jar,名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机的内存中。启动类加载器无法被Java程序直接引用,用户在编写自定义类加载器时, 如果需要把加载请求委派给引导类加载器去处理,那直接使用null代替即可。

4.2 扩展类加载器

这个类加载器是在

类 sun.misc.Launcher$ExtClassLoader 中以Java代码的形式实现的。它负责加载\lib\ext目录中,或者被java.ext.dirs系统变量所指定的路径中所有的类库。根据“扩展类加载器”这个名称,就可以推断出这是一种Java系统类库的扩展机制,JDK的开发团队允许用户将具有通用性的类库放置在ext目录里以扩展Java SE的功能,在JDK9之后,这种扩展机制被模块化带来的天然的扩展能力所取代。由于扩展类加载器是由Java代码实现的,开发者可以直接在程序中使用扩展类加载器来加载Class文件。

4.3 应用程序类加载器

这个类加载器由

sun.misc.Launcher$AppClassLoader 来实现。由于应用程序类加载器是ClassLoader类中的 getSystemClassLoader() 方法的返回值,所以有些场合中也称它为“系统类加载器”。它负责加载用户类路径(ClassPath)上所有的类库,开发者同样可以直接在代码中使用这个类加载器。如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

由于现有的类加载器加载路径都有特殊的要求,自己所编译的加密类所产生的.class文件所存放的路径不在三个现有类加载器的路径里面,因此我们有必要自己定义类加载器。

五、自定义类加载器

除了根类加载器,所有类加载器都是ClassLoader的子类。所以我们可以通过继承ClassLoader来实现自己的类加载器。

ClassLoader类有两个关键的方法:

  • protected Class loadClass(String name, boolean resolve):name为类名,resove如果为true,在加载时解析该类。
  • protected Class findClass(String name) :根据指定类名来查找类别。

所以,如果要实现自定义类,可以用这两个方法来实现。但推荐重写findClass方法,而不是重写loadClass方法,重写loadClass方法可能会破坏类加载的双亲委派模型,因为loadClass方法内部会调用findClass方法。

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;

        }

    }

loadClass加载方法流程:

  • 判断此类是否已经加载;
  • 如果父加载器不为null,则使用父加载器进行加载;反之,使用根加载器进行加载;
  • 如果前面都没加载成功,则使用findClass方法进行加载。

所以,为了不影响类的加载过程,我们重写findClass方法即可简单方便的实现自定义类加载。

六、代码实现

6.1 实现自定义的类加载器

public class DynamicClassLoader extends ClassLoader {

 

    private static final String CLASS_EXTENSION = "class";

 

    @Override

    public Class<?> findClass(String encryptClassInfo) {

        EncryptClassInfo info = JSON.parseObject(encryptClassInfo, EncryptClassInfo.class);

        String filePath = info.getAbsoluteFilePath();

        String systemPath = System.getProperty("java.io.tmpdir");

        String normalizeFileName = FilenameUtils.normalize(filePath, true);

        if (StringUtils.isEmpty(normalizeFileName) || !normalizeFileName.startsWith(systemPath)

                ||getApkFileExtension(normalizeFileName) == null

                || !CLASS_EXTENSION.equals(getApkFileExtension(normalizeFileName))) {

            return null;

        }

 

        String className = info.getEncryptClassName();

        byte[] classBytes = null;

        File customEncryptFile = new File(filePath);

        try {

            Path path = Paths.get(customEncryptFile.toURI());

            classBytes = Files.readAllBytes(path);

        } catch (IOException e) {

            log.info("加密错误", e);

        }

        if (classBytes != null) {

            return defineClass(className, classBytes, 0, classBytes.length);

        }

        return null;

    }

 

    private static String getApkFileExtension(String fileName) {

        int index = fileName.lastIndexOf(".");

        if (index != -1) {

            return fileName.substring(index + 1);

        }

        return null;

    }

}

这里主要是通过集成ClassLoader,复写findClass方法,从加密类信息中获取到对应的.class文件信息,最后获取到加密类的对象

6.2 .class文件中的encrypt()方法

public String encrypt(String rawString) {

        String keyString = "R.string.0x7f050001";

        byte[] enByte = encryptField(keyString, rawString.getBytes());

        return Base64.encode(enByte);

    }

6.3 具体的调用

public class EncryptStringHandler {

 

    private static final Map<String, Class<?>> classMameMap = new HashMap<>();

 

    @Autowired

    private VivofsFileHelper vivofsFileHelper;

 

    @Autowired

    private DynamicClassLoader dynamicClassLoader;

 

    public String encryptString(String fileId, String encryptClassName, String fileContent) {

        try {

            Class<?> clazz = obtainEncryptClass(fileId, encryptClassName);

            Object obj = clazz.newInstance();

            Method method = clazz.getMethod("encrypt", String.class);

            String encryptStr = (String) method.invoke(obj, fileContent);

            log.info("原字符串为:{},加密后的字符串为:{}", fileContent, encryptStr);

            return encryptStr;

        } catch (Exception e) {

            log.error("自定义加载器加载加密类异常", e);

            return null;

        }

    }

 

    private Class<?> obtainEncryptClass(String fileId, String encryptClassName) {

        Class<?> clazz = classMameMap.get(encryptClassName);

        if (clazz != null) {

            return clazz;

        }

 

        String absoluteFilePath = null;

        try {

            String domain = VivoConfigManager.getString("vivofs.host");

            String fullPath = domain + "/" + fileId;

            File classFile = vivofsFileHelper.downloadFileByUrl(fullPath);

            absoluteFilePath = classFile.getAbsolutePath();

            EncryptClassInfo encryptClassInfo = new EncryptClassInfo(encryptClassName, absoluteFilePath);

            String info = JSON.toJSONString(encryptClassInfo);

            clazz = dynamicClassLoader.findClass(info);

            //设置缓存

            Assert.notNull(clazz, "自定义类加载器加载加密类异常");

            classMameMap.put(encryptClassName, clazz);

            return clazz;

        } finally {

            if (absoluteFilePath != null) {

                FileUtils.deleteQuietly(new File(absoluteFilePath));

            }

        }

    }

}

通过上述代码的实现,我们可以通过在管理平台添加编译好的.class文件,最后通过自定义的类加载器和反射调用方法,来实现具体方法的调用,避免了我们需要修改代码和重新发版来适应不断新增加密方法的问题。

七、问题

上面的代码在本地测试时,没有出现任何异常,但是部署到测试服务器以后出现了JSON解析异常,看上去貌似是json字符串的格式不对。

json解析逻辑主要存在于DynamicClassLoader#findClass方法入口处的将字符串转换为对象逻辑,为什么这里会报错,我们在入口处打印了入参。

发现这里除了我们需要的正确的入参(第一个入参信息打印)外,还多了一个Base64的全路径名
cn.hutool.core.codec.Base64。出现这种情况,说明由于我们重写了ClassLoader的findClass方法,而Base64加载的时候会调用原始的ClassLoader类的loadClass方法去加载,并且里面调用了findClass方法,由于findClass已经被重写,所以就会报上面的json解析错误。

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;

        }

    }

但是这里期望的是除了用于加密的.class文件用自定义类加载器进行以外,不希望其他的类用自定义类加载器加载,通过对ClassLoader#loadClass方法分析,那么我们就希望能否通过其父类加载器加载到Base64这个三方类。因为启动类加载器Bootstrap Class Loader肯定不能加载到Base64,所以我们需要显示的设置父类加载器,但是这个父类加载器究竟设置为哪一个类加载器,那么就需要我们了解Tomcat类加载器结构。

为什么Tomcat需要在JVM基础之上做一套类加载结构,主要是为了解决如下问题:

  • 部署在同一个服务器上的两个web应用程序所使用的Java类库可以实现相互隔离;
  • 部署在同一个服务器上的两个web应用程序所使用的Java类库可以实现共享;
  • 服务器需要尽可能保证自身安全,服务器所使用的类库应该与应用程序的类库相互独立;
  • 支持JSP应用的Web服务器,大对数需要支持HotSwap功能。

为此,tomcat扩展出了 Common类加载器 (CommonClassLoader)、 Catalina类加载器 (CatalinaClassLoader)、 Shared类加载器 (SharedClassLoader)和 WebApp类加载器 (WebAppClassLoader),他们分别加载/commons/*、/server/*、/shared/*和/WebApp/WEB-INF/*中的Java类库的逻辑。

通过分析,我们知道WebAppClassLoader类加载器可以加载到/WEB-INF/*目录下的依赖包,而我们所依赖的类
cn.hutool.core.codec.Base64 所在的包 hutool-all-4.6.10-sources.jar 就存在于/WEB-INF/*目录下面,并且我们自定义类加载器所在的包 vivo-namelist-platform-service-1.0.6.jar 也在/WEB-INF/*下,所以自定义类加载器DynamicClassLoader也是WebAppClassLoader加载的。

我们可以写一个测试类测试一下:

@Slf4j

@Component

public class Test implements ApplicationListener<ContextRefreshedEvent> {

 

    @Override

    public void onApplicationEvent(ContextRefreshedEvent event) {

        log.info("classLoader DynamicClassLoader:" + DynamicClassLoader.class.getClassLoader().toString());

    }

}

测试结果:

所以我们可以设置自定义类加载器DynamicClassLoader的父加载器为加载其本身的类加载器:

public DynamicClassLoader() {

        super(DynamicClassLoader.class.getClassLoader());

}

我们再次执行文件的加解密操作时,已经没有发现报错,并且通过添加日志,我们可以看到加载类
cn.hutool.core.codec.Base64 对应的类加载器确实为加载DynamicClassLoader对应的类加载器WebAppClassLoader。

public String encrypt(String rawString) {

        log.info("classLoader Base64:{}", Base64.class.getClassLoader().toString());

        String keyString = "R.string.0x7f050001";

        byte[] enByte = encryptField(keyString, rawString.getBytes());

        return Base64.encode(enByte);

    }

现在再来思考一下,为什么在IDEA运行环境下不需要设置自定义类加载器的父类加载器就可以加载到
cn.hutool.core.codec.Base64 。

在IDEA运行环境下添加如下打印信息:

public String encrypt(String rawString) {

        System.out.println("类加载器详情...");

        System.out.println("classLoader EncryptStrategyHandler:" + EncryptStrategyHandlerH.class.getClassLoader().toString());

        System.out.println("classLoader EncryptStrategyHandler:" + EncryptStrategyHandlerH.class.getClassLoader().getParent().toString());

        String classPath = System.getProperty("java.class.path");

        System.out.println("classPath:" + classPath);

        System.out.println("classLoader Base64:" + Base64.class.getClassLoader().toString());

        String keyString = "R.string.0x7f050001";

        byte[] enByte = encryptField(keyString, rawString.getBytes());

        return Base64.encode(enByte);

    }

发现加载.class文件的类加载器为自定义类加载器DynamicClassLoader,并且.class加载器的父类加载器为应用类加载器AppClassLoader,加载


cn.hutool.core.codec.Base64 的类加载器也是AppClassLoader。

具体的加载流程如下:

1)先由自定义类加载器委托给 AppClassLoader ;

2) Ap pClassLoader 委托给父类加载器 ExtClassLoader ;

3) ExtClassLoader 再委托给 BootStrapClassLoader , 但是BootClassLoader无法加载到,于是ExtClassLoader自己进行加载,也无法加载到;

4)再由AppClassLoader进行加载;

AppClassLoader会调用其父类UrlClassLoader的findClass方法进行加载;

5)最终从用户类路径 java.class.path 中加载到
cn.hutool.core.codec.Base64 。

由此,我们发现在IDEA环境下面,自定义的加密类.class文件中依赖的三方类
cn.hutool.core.codec.Base64 是可以通过AppClassLoader进行加载的。

而在linux环境下面,经过远程调试,发现初始时加载
cn.hutool.core.codec.Base64 的类加载器为DynamicClassLoader。然后委托给父类加载器AppClassLoader进行加载,根据双亲委派原理,后续会交由AppClassLoader自己进行处理。但是在用户路径下仍然没有找到类 cn.hutool.core.codec.Base64 ,最终交由DynamicClassLoader进行加载,最终出现了最开始的JSON解析错误。

八、总结

由于类加载阶段没有严格限制如何获取一个类的二进制字节流,因此给我们提供一个通过自定义类加载器来动态加载.class文件实现代码可扩展性的可能。通过灵活自定义classloader,也可以在其他领域发挥重要作用,例如实现代码加密来避免核心代码泄漏、解决不同服务依赖同一个包的不同版本所引起的冲突问题以及实现程序热部署来避免调试时频繁重启应用。

【OAG vs RAG】RAG的“语义崩溃“:为什么你的知识库越大,AI越笨?_语义检索oag-优快云博客 19.9 元(AI 编程 / Agent 实战 | 本文同主题系统课程)·49.9 元(AI 时代成长方法论)。单篇不过瘾?订阅解锁全量源码、实战与答疑;文末附资料包领取方式 ↓图1:RAG语义崩溃概念图。 阅读详情

相关推荐

计算机视觉-全景图像拼接中的特征匹配与优化策略

本文深入探讨了计算机视觉中全景图像拼接的核心技术,重点解析了特征匹配后的关键优化策略。通过SIFT特征提取、RANSAC算法剔除误匹配,并结合APAP算法应对视差与鬼影问题,详细阐述了从基础对齐到无缝融合的完整流程,为开发者实现高质量全景拼接提供了实用指南。

weixin_29039773的博客 362

2022-07-26 hutool工具包部分工具使用(不定时更新)

对于在工作中使用到的hutool工具包内容进行记录,方便随时查看

Young的博客 2462

保姆级教程:DBeaver社区版安装与驱动配置(附阿里云镜像解决下载超时)

本文提供DBeaver社区版的保姆级安装教程,涵盖版本选择、安装路径设置到驱动配置优化。特别针对国内用户遇到的下载超时问题,详细介绍了如何配置阿里云镜像加速驱动下载,确保高效连接MySQL等主流数据库。

weixin_30430169的博客 480

什么是JVM的类加载器?引导类加载器、扩展类加载器

什么是JVM的类加载器?引导类加载器、扩展类加载器

杨荧的优快云博客 852

【脑电分析系列】第15篇:脑电功能连接性与脑网络分析(二):Granger因果性、图论指标与复杂网络构建

摘要: 本文深入探讨了脑电(EEG)分析中的高阶连接性方法——有效连接(Effective Connectivity),重点介绍了Granger因果性(Granger Causality, GC)的原理与应用。GC通过统计预测揭示脑区间信息流动方向,超越了传统功能连接的同步性分析。文章还结合图论指标(如度、路径长度、聚类系数和模块化)量化脑网络的拓扑结构,并通过Python代码(MNE和NetworkX库)演示了从EEG数据构建、分析复杂脑网络的完整流程。该研究为理解大脑动态互动、认知任务信息流及神经系统疾

qq_32516809的博客 1568

工业场景实战:基于YOLO与多格式标注的传送带异物检测数据集构建指南

本文详细介绍了基于YOLO与多格式标注的传送带异物检测数据集构建方法,涵盖数据采集、标注技巧(YOLO、COCO、VOC格式)、数据增强策略及实战案例。通过工业级解决方案,有效提升异物检测准确率与效率,适用于各类工业场景。

weixin_29168393的博客 464

【利用hutool简单演示前后端加解密流程】

利用hutool,简单演示前后端加解密过程,代码可直接复制运行

kanseiu的博客 1961

别再只盯着照片了!手把手教你用Python提取大疆照片里的GPS、姿态和RTK数据

本文详细介绍了如何使用Python提取大疆照片中的GPS、姿态和RTK数据,帮助用户解锁无人机拍摄照片中的隐藏元数据。通过实战代码示例,展示了如何解析EXIF格式的定位、姿态和RTK状态信息,并实现批量处理与数据分析,适用于测绘、农业巡检等专业领域。

weixin_30790841的博客 156

Java面试必会高频考题

复制算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片”问题。缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。对MySQL的存储引擎的考察也是一个几乎必考的知识点,为了让大家对存储引擎有一个更好的了解,我们先来看下MySQL的基本逻辑架构图,从整体上了解下MySQL包括哪些逻辑架构。

m0_72885838的博客 753

【WorkBuddy】WorkBuddy 智能体快速上手:从零到一的实践指南

文章摘要: 传统自动化脚本难以应对灵活多变的自然语言需求,导致逻辑复杂、维护成本高。智能体(Agent)通过理解语义意图、动态决策和松耦合组件解决了这些问题。WorkBuddy采用声明式配置,通过可视化界面定义意图、实体和对话策略,无需编码即可快速构建智能体。其核心组件包括意图分类、实体提取、对话策略、故事样本和回退机制,适用于客服支持、知识问答等高频场景。通过环境准备(Python/Node.js/Redis)和简单配置,用户可以快速搭建可运行的智能体,显著提升自动化效率。

ruiqideng的博客 1688

xtop:multi_driven_net与incomplete_timing_cell fail reason 分析

man multi_driven_net”可以得知,这个问题是multi driven结构引起的,使用命令“get_failed_pins -reason multi_driven_net”,获取violation pin。“man incomplete_timing_cell”可以得知,这个fail reason的原因是缺少timing library cell,检查并补全后这个错误就显示了。这里选择的解决方法是修改lib文件,把inout改成input,重新lib2idb。通过这种方法解决了问题。

m0_61544122的博客 568

论在代码扩展性的实践还得看JVM自定义类加载器

一、背景 名单管理系统是手机上各个模块将需要管控的应用配置到文件中,然后下发到手机上进行应用管控的系统,比如各个应用的耗电量管控;各个模块的管控应用文件考虑到安全问题,有自己的不同的加密方式,按照以往的经验,我们可以利用模板方法+工厂模式来根据模块的类型来获取到不同的加密方法。代码类层次结构示意如下: 获取不同加密方法的类结构图 利用工厂模式和模板方法模式,在有新的加密方法时,我们可以通过添加新的handler来满足"对修改关闭,对扩展开放"的原则,但是这种方式不可避免的需要修改代码和需要重新

aa119101的博客 118

2xmax96717+max96724+agx orin驱动代码

说明:这里主要解决max96717的设备地址和sensor地址映射,vc0->vc1多颗max96717+max96724使用配置思路如下: 1、改变max96717的pipez stream id,然后max96724的pipe绑定使用相应的stream id 2、max96717默认是vc0,把vc0改写成vc1\vc2\vc3,然后max96724再重新映射vc输出

mantouyouyou的博客 115

【JAVA】JVM类加载器知识笔记

Java提供了强大的类加载器扩展机制,允许开发者创建自己的类加载器来实现特殊的需求。自定义类加载器需要继承java.lang.ClassLoader类,并重写findClass方法。热部署需求:在不停机的情况下更新和重新加载类模块化系统:实现插件架构,每个插件使用独立的类加载器加密解密:加载加密的class文件,在内存中解密后加载从特殊来源加载:从数据库、网络等非文件系统加载类在我之前开发的一个插件化平台中,就大量使用了自定义类加载器。

WizLC 1542

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

JVM基础:深入理解类加载器

类加载器是JVM中一个非常重要的组件,它负责将.class文件加载到JVM中,并为其创建java.lang.Class对象。通过了解类加载器的层次结构、加载机制以及类加载过程,我们可以更好地理解和使用Java平台,避免在开发中遇到类加载相关的问题。同时,自定义类加载器也为Java平台提供了更多的灵活性和扩展性。

m0_63550220的博客 2320

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

JVM——如何打造一个类加载器?

JVM——如何打造一个类加载器?

从知识输入到知识输出 1291

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

jvm类加载器

通过继承可以创建自定义类加载器,用于加载自定义路径或加密的类。JVM 类加载器是 Java 动态加载机制的核心,提供了灵活的类加载支持。本文详细介绍了类加载器的分类、双亲委派模型、类加载的生命周期,并通过代码展示了自定义类加载器及其应用。合理使用类加载器可以显著提高程序的扩展性与安全性。

Flying_Fish_roe的博客 430

JVM-基础篇-10-类加载器的分类

引导类加载器:负责加载 Java 核心类库。扩展类加载器:负责加载 JDK 扩展目录下的类。系统类加载器:负责加载应用程序类路径下的类。自定义类加载器:由用户自定义,用于加载特定需求的类。通过这些类加载器,Java 实现了灵活的类加载机制,同时也确保了类加载的安全性与效率。模块化和分层设计:确保每个层次只负责加载特定类型的类。父委托机制:保证加载过程的安全性,防止核心类库被恶意替换。灵活性和隔离性:支持动态加载和模块隔离,适应复杂应用场景。性能优化:提高类加载效率,避免不必要的全局加载。

qq_41577703的博客 865

《深入理解JVM》实战笔记(二): 类加载机制与类加载器

本篇博客详细介绍了 JVM 的类加载机制,包括类的生命周期、类加载器的层级结构、双亲委派模型及其应用。本篇博客将详细探讨 JVM 的类加载过程以及类加载器的工作原理,帮助你更深入地理解 Java 的动态性和可扩展性。JVM 通过类加载器(ClassLoader)来完成这个过程,使 Java 具有动态加载和模块化的特性。的能力,使得 Java 程序可以在运行时加载新的类,而不需要在编译时确定所有的类信息。:当类不再被引用时,GC 可能会回收它(通常仅适用于自定义类加载器加载的类)。

weixin_39899039的博客 1066
上一篇: Redis+Caffeine两级缓存,让访问速度纵享丝滑
下一篇: SpringBoot接入轻量级分布式日志框架(GrayLog)
JavaMonsterr
博客等级 码龄4年 211粉丝 481原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值