参考文章:
利用classloader实现jar包的加载和卸载,实现类的热替换
动态添加classpath
关于ClassLoader.getSystemClassLoader()和Thread.currentThread().getContextClassLoader()
老大难的 Java ClassLoader 再不理解就老了
关闭URLClassLoader打开的jar包

前言

  • 本人小白,过程部分是本人对这几天崩溃状态的宣泄,见笑,不喜请略过,可直接看代码部分。
  • 如果有大神看到这篇文章,想劳烦大神解答一下疑问部分,谢谢。
  • 源码在文章最后,包含动态加载数据库驱动,其中有个需要注意的bug,如有兴趣了解,可转向另一篇转载文章 使用DriverManager动态加载JDBC驱动时,报:java.sql.SQLException: No suitable driver found for xxxx 错误

过程

最近在做动态加载数据驱动和数据池的部分,网上多是使用URLClassLoader 作为动态加载jar的,但是经过多天的百度和测试,都未能成功,很多情况下都给出了类似 动态添加classpath 这篇文章的例子,这些例子在测试环境是能正常使用的,但到部署环境,又会出现各种问题,而且想实现卸载,会有些麻烦,详情参考 关闭URLClassLoader打开的jar包 这篇文章,直接使用URLClassLoader.close(),会出现其他jar包读取不了的问题。而且这种卸载,测试的时候,也出现了不能重载的现象。

然后看到 利用classloader实现jar包的加载和卸载,实现类的热替换 这篇文章,参考这篇文章内容进行相应更改,成功在测试环境正常热加卸载。但是到了部署,还是会出现找不到的问题。不过这篇文章的优点在于他把jar包自行保存了一份,这样就不用像 关闭URLClassLoader打开的jar包 这篇文章那样,需要通过复杂过程获取jar包关闭,这个方法很好,所以保留在我的代码里了。

直到看到 关于ClassLoader.getSystemClassLoader()和Thread.currentThread().getContextClassLoader() 这篇文章,详细解决原因,请看原文,更换了classloader获取方式,终于成功在测试和部署上都成功热加卸不报错了。

你以为这就成功了?不是的,虽然加载卸载没问题,但是要使用这个数据池的时候,他会报找不到其他jar所需的class(例如 log4j2 )。嗯,心态崩溃了。

反正各种沉默后,突然灵光一现,可能是级别不够,找不到位?不知道怎么解析,反正我是这样想的,然后给Thread.currentThread().getContextClassLoader()加了个爸爸,变身Thread.currentThread().getContextClassLoader().getParent(),终于成功了。之前的报错,都没出现了。狂奔

都是自己对ClassLoader的不熟悉,导致各种问题出现,所以推荐大家看一下 老大难的 Java ClassLoader 再不理解就老了 这篇文章,虽然我暂时还没理解透

最后总结一句,ClassLoader 爸爸虽然懒,但是也经不起我的折腾


代码

  1. exJarEntity.java:用于保存对应jar包信息
package chen.wset.entity;import lombok.Data;import java.io.Serializable;
import java.net.URLClassLoader;
import java.util.jar.JarFile;//用于保存对应jar包信息
@Data
public class exJarEntity implements Serializable {// 驱动名String name;// 驱动urlString url;// URLClassloaderURLClassLoader urlClassLoader;// 驱动jar包,用于关闭对应jarJarFile jarFile;
}
  1. dynamicLoading.java:加载、卸载、获取 jar - classloader 操作
package chen.wset.utils;import chen.wset.entity.exJarEntity;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.db.ds.DSFactory;
import cn.hutool.db.ds.pooled.PooledDSFactory;import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import java.util.Map;
import java.util.jar.JarFile;public class dynamicLoading {//用于保存jar相关信息,便于对应操作Map<String, exJarEntity> cLoader = MapUtil.newHashMap();public dynamicLoading() {}// 动态添加jar到classpathpublic boolean loadJar(String name, String jarPath) {// 判断唯一if (isExit(name, jarPath)) {return false;}try {//获取classloaderURLClassLoader classloader = (URLClassLoader) Thread.currentThread().getContextClassLoader().getParent();// 获取 URLClassLoader addURL() 方法Method add = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});// 设置可访问if (!add.isAccessible()) add.setAccessible(true);// 获取jar路径File jarFile = FileUtil.file(jarPath);// 执行addURL()方法add.invoke(classloader, new Object[]{jarFile.toURI().toURL()});//储存信息exJarEntity ex = new exJarEntity();ex.setName(name);ex.setUrlClassLoader(classloader);ex.setUrl(jarPath);ex.setJarFile(new JarFile(jarFile));cLoader.put(name, ex);//成功返回truereturn true;} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}// 如果出错则返回falsereturn false;}//关闭classloaderpublic boolean close(String name) {// 判断是否有相应jar信息if (!isExit(name, null)) {return false;}try {//获取对应classloaderexJarEntity ex = cLoader.get(name);//此步为确定关闭所有连接池所作,不是所有jar都需要做,所以请根据实际情况进行操作//关闭前更换Hutool-db数据池//DSFactory.setCurrentDSFactory(new PooledDSFactory());//关闭ex.getJarFile().close();//移除关闭记录cLoader.remove(name);return true;} catch (Exception e) {e.printStackTrace();}return false;}// 获取保存的jar信息列表public List<exJarEntity> getList(){List<exJarEntity> list = null;if (!cLoader.isEmpty()){for (exJarEntity ex : cLoader.values()){list.add(ex);}}return list;}//判断是否存在cLoader数据public boolean isExit(String name, String jarPath) {//如果cLoader为空,则不存在,直接返回falseif (cLoader.isEmpty()) {return false;}if (!name.isEmpty()) {for (String cname : cLoader.keySet()) {if (cname.equals(name)) {return true;}}}if (jarPath.isEmpty()) {for (exJarEntity ex : cLoader.values()) {if (ex.getUrl().equals(jarPath)) {return true;}}}return false;}
}

疑问

  1. 参考文章中作者使用的是:Thread.currentThread().getContextClassLoader()
    而本人需要使用Thread.currentThread().getContextClassLoader().getParent()
    出现这个情况的原因是?
  2. 关闭URLClassLoader打开的jar包 和 利用classloader实现jar包的加载和卸载,实现类的热替换 这两篇文章都是直接关闭jar包的,区别是?
  3. URLClassLoader.close()方法为什么会导致其他jar包失效?

源码

CSDN
蓝奏云

URLClassLoader热加载、卸载,自定义热加载数据池 jar包(附:Springboot + Hutool-db 使用实例)相关推荐

  1. 【ClassLoader】实现自定义类加载器加载指定路径下的Class文件和Jar包

    文章目录 前言 自定义类加载器加载.class文件 自定义类加载器加载jar包文件 前言 在web开发中,一般我们是不需要去自己实现类加载器的,常见的web容器已经帮我们实现了指定路径下的加载,比如我 ...

  2. java 热替换_class卸载、热替换和Tomcat的热部署的分析

    所以一个class被一个ClassLoader实例加载过的话,就不能再被这个ClassLoader实例再次加载(这里的加载指的是,调用了defileClass(...)放方法,重新加载字节码.解析.验 ...

  3. gradle 修改java代码_自定义一个gradle插件动态修改jar包Class文件

    动态修改jar包中的class文件,预埋占位符字符串,在编译代码时动态植入要修改的值.记录一下整个过程及踩过的坑. 创建一个Android项目,再创建一个Android library,删掉里面所有代 ...

  4. android自定义图片加载,Android自定义ProgressDialog加载图片

    为了提高用户体验,我们肯定希望该Dialog能更加炫酷,让用户看着更舒服.那如何做呢,当然是我们自己定义一个ProgressDialog了. 一.使用系统加载框 mDialog = new Progr ...

  5. Linux自定义shell脚本一键启停jar包

    Linux运行jar包脚本,我的 jar包和 .sh文件在同一目录. #!/bin/sh port=8090 #端口 jar_name=ruoyi-admin.jar #/usr/local/ry-v ...

  6. Java运行时动态加载类之ClassLoader加载class及其依赖jar包

    需求场景是:通过ClassLoader动态加载外部class文件,class文件又依赖某个具体jar包,需要动态加载jar包,采用URLClassLoader. 1.xml配置文件 <?xml ...

  7. android jar 加入图片,Android动态加载外部jar包及jar包中图片等资源文件

    Android动态加载外部jar包及jar包中图片等资源文件 Android应用程序由Java开发,因此Java中许多实用的特性,在Android中也有体现.动态加载Class,也就是外部jar包,在 ...

  8. java进阶(9)——JVM jar包加载顺序

    最近工作当中遇到过好几例,由于项目当中依赖了一些框架,而这些框架无法直接修改时,我就直接本地代码写了一个同名同包路径的类,可以直接覆盖框架的类(本文说的框架类,不包括jdk的),屡试不爽.但是心里不免 ...

  9. springboot启动报jar包加载异常问题解决

    问题描述: springboot启动报jar包扫描错误,但不影响项目正常使用: Failed to scan [file:/Users/ds/.m2/repository/com/sun/xml/bi ...

最新文章

  1. 兴趣部落的 Git 迁移实践
  2. Flex的NumericStepper控件
  3. C语言学习之两个乒乓球队进行比赛,各出3人。甲队为A,B,C3人,乙队为X,Y,Z3人。已抽签决定比赛名单。
  4. SAP CRM Long text unit test preparation
  5. 在页面最上面显示当前登陆的状态
  6. kali 无法使用ifconfig等常用命令
  7. VS2008中开发Silverlight 2.0的配置
  8. 云图说 | 华为云应用服务网格,让你的应用治理智能化、可视化
  9. 【nodejs原理源码赏析(9)】用node-ssh实现轻量级自动化部署
  10. 中国姜黄根提取物行业市场供需与战略研究报告
  11. ThinkPad E550 Catalina用OC换Clover引导的过程(支持Mac Update)
  12. 在MySQL中生成随机经度和纬度
  13. [UE4]委托代理:单播委托,多播委托,动态单播委托,动态多播委托,事件
  14. 盘点——iOS应用开发常用工具
  15. macbook更新windows11
  16. 生物制剂时代的SpA研究正站在十字路口_Appel,Sieper2009
  17. 【微信小程序】开发入门篇(一)
  18. 微信小程序腾讯云环境搭建
  19. 盈透api python封装_盈透证券 简单API 实战
  20. 为什么Java仍将是未来的主流语言?

热门文章

  1. Flutter 中视频的播放
  2. 将多张图片无缝拼接方法
  3. iphone11右上角信号显示_iPhone11真机使用半个月,不黑不吹,信号明显比10好很多...
  4. Html5画布操作-旋转 | rotate()
  5. 高端微型计算机CPU产品,12nm、钎焊、5.0GHz、32核心!2018年CPU市场年终盘点
  6. Android 高德地图去掉 logo
  7. 微型计算机显卡,担心显卡难买?这套高性能主机配置就能满足你
  8. 如何在微信小程序中使用wxParser(富文本编辑器)
  9. TensorFlow2.0 问世,Pytorch还能否撼动老大哥地位?
  10. php中调行高代码_PhpSpreadsheet设置单元格常用操作汇总