参考文章:
利用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 爸爸虽然懒,但是也经不起我的折腾
代码
- 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;
// 驱动url
String url;
// URLClassloader
URLClassLoader urlClassLoader;
// 驱动jar包,用于关闭对应jar
JarFile jarFile;
}
- dynamicLoading.java:加载、卸载、获取 jar - classloader 操作
package chen.wset