Java Classloader - how to reference different versions of a jar

大憨熊 提交于 2019-12-28 04:01:28

问题


This is a common problem. I'm using 2 libraries A.jar and B.jar and these depend on different versions of the same jar.
Let's say that at runtime I need THIS.x.x.x.jar

MY.jar   
     -> A.jar -> THIS.1.0.0.jar
     -> B.jar -> C.jar -> THIS.5.0.0.jar

I can compile the specific jar (A.jar/B.jar) against its dependency but at runtime I've to load only 1 version. Which one?
Loading only 1 dependency (the latest version) means that my code will probably throw runtime exceptions if the libraries are not Backward Compatible (are there Backward Compatible libraries out there?).

Anyway I know that something like OSGi can fix this issue.
I'm wondering what's the old way to fix this kind of problems...

Thanks a lot


回答1:


"Old way" you mentioned (and the one OSGI certainly uses under the hood) is to install your own ClassLoader for both branches of your dependencies. That's how, for instance, application servers are able to run both older and newer versions of the same application inside the same JVM.

Read about classloader hierarchy.

In your setup, the tricky part is the joint point, where classes from both branches meet. Neither branches can use classes loaded into another one. The way to make it work is to make sure only classes loaded by boot classloader (JRE classes) or classloader of MY.jar are passed down to both branches.




回答2:


OSGi can fix this problem. An OSGi bundle is nothing more than a jar with additional metadata detailing versions. A bundle has a version number, and will detail version numbers (or ranges) of dependent jars.

Take a look at this introductory Javaworld article for more information.

To solve this without OSGi means having to ensure manually that you compile and run with compatible jars. As you've discovered that's not necessarily a trivial task. Since jars don't necessarily identify their versions, the only sure way to do this to record/compare checksums or signatures.




回答3:


Many libraries are backward compatible. But not all..


The old way is to try to depend from only one version.

It is probably safer to compile both with the same version (latest).
At least you get compile-time errors, instead of runtime errors.

If needed, you can modify a little bit your library that works with the old dependency...
This would require access to the source...


Please note that compile-time compatibility will not guarantee correct runtime behavior either. It is one step, then you can:

  • read the WhatsNew file for the new version of the jar
  • look on the Internet for users reporting compatibility problems
  • write JUnits
  • compare the codes in both jars



回答4:


As mentioned by KLE, the default approach is to depend on the newer version. There is no guarantee, but most of the time this works. Probably the best way (while being a bloated one) is using OSGI to get over it.




回答5:


To refer a basic "oldway" implementation checkout https://github.com/atulsm/ElasticsearchClassLoader

This provides an approach to handle non-backward compatible versions of elasticsearch client usage.



来源:https://stackoverflow.com/questions/1553567/java-classloader-how-to-reference-different-versions-of-a-jar

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!