更新一下这个问题的目前解决思路、非最优:
妥协在非最优的先实现了的原因——
如果在 jar 包内部通过 Class.forName 、或者自定义 ClassLoader 方法去装载类,这样的类装载肯定是要到运行态才能发现的——因此配置不可避免,和大家说的一样。
那么即便是非最优、但提的上 [有点优] ,那就还是要搞点事情的:
1 、可只配置依赖 jar 包文件路径,而不必明确每个需要依赖的类名
2 、当出现依赖不完整时,即出现 ClassNotFound/NoSuchMethodException 异常时,自动尝试寻找更进一步的企业内框架 jar 库路径自动解决依赖,作为托底,并对应 warning log 提示动态装载类开发者明确依赖(这里有点安全性问题、企业内应该还好)
先阅读背景材料:
https://stackoverflow.com/questions/60764/how-to-load-jar-files-dynamically-at-runtime然后跟着写了一个代码,没有发现所说的 java<=8 和>=9 两者存在区别,用 URLClassLoader 足以解决问题
[但 这 里 有 个 大 大 大 坑]
URLClassLoader 是一个实现 Closeable 的 resource ,IDE 会提示你 close ,否则一直 warning
如果你 close 了,那么恭[进]喜[坑]
例:
你在 A.class 里面动态加载 B.class ,在需调用计算的 B.someCaller 里面,引用了一个 C.jar 里面的 D.class 的 D.someCallee
伪码:
myClsLoader = new URLClassLoader(someClsPathURL, someDefaultLoader)
Class<?> bClass = myClsLoader.loadClass(BclassName)
myClsLoader.close()
return bClass;
—— bClass 返回的很好,close 正常,啥错都没有。然后再进一步调用
bInstance = bClass.newInstance()
——也没问题,但
bInstance.someCaller()
——此时,就会报错 ClassNotFound: D.class
摸不着头脑了吧,一开始还以为是 java<=8 和>=9 的区别,搞了一圈 hack ,结果实际是——
[这个 URLClassLoader 是在真正的 Call 没有发生前,是不能关闭的;关了就没办法加载进一步 Call 内引用的 C.jar 内依赖 D.class]
这样 URLClassLoader 的生命周期就要和 Caller 的生命周期一样了,从加载框架层、跨越到逻辑执行层,味道太烂了。不能关。
那不关是不是就 resource leak 了呢?单纯这么写,当然是 leak 的
参:
https://blog.csdn.net/moneyshi/article/details/81939477 ,但按这文章里面讲的办法关闭估计还是无法加载 D.class 的
那么怎么解决 leak 呢?
有不能关闭的 resource ,把它 cache 起来,保证 resource load once and only once ,这样不就行了嘛。同时也能 cache 各种 loader 过程和反射方法等等,一举多得。
但是进一步的又有点 [担心] :
a ,被 cache 的 URLClassLoader 是否会在对象回收时,被 JVM 主动释放,造成 cache stale 现象
b ,毕竟是个外部 resource ,是否会影响 JVM 的优雅停止
因此在 [有点优] 的事情 2 上,本身就是要 try 包住 caller 过程的,其中考虑用户依赖不完整时,同时也处理掉 staled-cache ,重建 URLClassLoader 重新 cache 。不过担心 b 还是存在啊
这样一路实现下来,感觉 [有点优] 里不优雅的事情还是很多啊……大家有什么更好的设计思路?