简体   繁体   English

类加载器问题-如何确定要加载的库版本(jar文件)

[英]Classloader issues - How to determine which library versions (jar-files) are loaded

I've just solved another *I-though-I-was-using-this-version-of-a-library-but-apparently-my-app-server-has-already-loaded-an-older-version-of-this-library-*issue (sigh). 我刚刚解决了另一个*我虽然正在使用这个版本的库,但显然我的应用服务器已经加载了一个旧版本-此库-*问题(叹气)。

Does anybody know a good way to verify (or monitor) whether your application has access to all the appropriate jar-files, or loaded class-versions? 有人知道一种验证(或监视)您的应用程序是否有权访问所有适当的jar文件或已加载的类版本的好方法吗?

Thanks in advance! 提前致谢!

[PS A very good reason to start using the OSGi module architecture in my view!] [在我看来,PS是开始使用OSGi模块体系结构的充分理由!]

Update : This article helped as well! 更新文章帮助的! It gave me insight which classes JBoss' classloader loaded by writing it to a log file. 通过将JBoss的类加载器写入日志文件,它使我了解了哪些类加载。

If you happen to be using JBoss, there is an MBean (the class loader repository iirc) where you can ask for all classloaders that have loaded a certain class. 如果您碰巧正在使用JBoss,则有一个MBean(类加载器存储库iirc),您可以在其中请求已加载特定类的所有类加载器。

If all else fails, there's always 'java -verbose:class' which will print the location of the jar for every class file that is being loaded. 如果所有其他方法均失败,则始终存在“ java -verbose:class”,它将为正在加载的每个类文件打印jar的位置。

If you've got appropriate versions info in a jar manifest, there are methods to retrieve and test the version. 如果您在jar清单中有适当的版本信息,则可以使用一些方法来检索和测试版本。 No need to manually read the manifest. 无需手动读取清单。

java.lang.Package .getImplementationVersion() and getSpecificationVersion() and isCompatibleWith() sound like they'd do what you're looking for. java.lang.Package .getImplementationVersion()和getSpecificationVersion()以及isCompatibleWith()听起来像它们会做您想要的。

You can get the Package with this.getClass().getPackage() among other ways. 您可以使用this.getClass()。getPackage()等方式获取Package。

The javadoc for java.lang.Package doesn't give the specific manifest attribute names for these attributes. java.lang.Package的javadoc没有提供这些属性的特定清单属性名称。 A quick google search turned it up at http://java.sun.com/docs/books/tutorial/deployment/jar/packageman.html Google进行了快速搜索, 网址http://java.sun.com/docs/books/tutorial/deployment/jar/packageman.html

In the current version of Java, library versioning is a rather wooly term that relies on the JAR being packaged correctly with a useful manifest. 在Java的当前版本中,库版本控制是一个很笼统的术语,它依赖于使用有用清单正确打包的JAR。 Even then, it's a lot of work for the running application to gather this information together in a useful way. 即使这样,正在运行的应用程序仍然需要大量工作来以有用的方式收集这些信息。 The JVm runtime gives you no help whatsoever. JVm运行时对您毫无帮助。

I think your best bet is to enforce this at build time, using dependency management tools like Ivy or Maven to fetch the correct versions of everything. 我认为您最好的选择是在构建时执行此操作,使用Ivy或Maven等依赖项管理工具来获取所有内容的正确版本。

Interestingly, Java 7 will likely include a proper module versioning framework for precisely this sort of thing. 有趣的是,Java 7可能会包括恰好适合此类情况的适当的模块版本控制框架。 Not that that helps you right at this moment, 目前尚不能帮助您,

I don't think there is a good way to check that. 我认为没有一个很好的方法来检查这一点。 And I'm not sure you want to do that. 我不确定您是否要这样做。 What you need to do is get familiar with your app-server's class loading architecture, and understand how that works. 您需要做的是熟悉应用程序服务器的类加载架构,并了解其工作原理。

A simplified explanation of how it works is: an EJB or a web-app will first look for a class or a resource in libraries declared in its own module (ejb-jar or war). 关于其工作原理的简化解释是:EJB或Web应用程序将首先在其自身模块(ejb-jar或war)中声明的库中查找类或资源。 if the class is not found there, the class loader forwards the request to the its parent class loader which is either a declared dependency (usualy an ejb) or the the application class loader which is responsible to load libraries and resources declared in the ear package. 如果在那里找不到类,则类加载器将请求转发到其父类加载器,该父类加载器是声明的依赖项(通常是ejb)或负责加载在ear包中声明的库和资源的应用程序类加载器。 If the class or the resource is still not found the request is forwarded to the app server which will look in its own classpath. 如果仍然找不到该类或资源,则将请求转发到应用服务器,该服务器将在其自己的类路径中查找。

This being said, you should remember that a Java EE module (web-app, ejb) will always load classes from a jar that is in the nearest scope. 话虽如此,您应该记住,Java EE模块(web-app,ejb)将始终从最接近作用域的jar中加载类。 For example if you package log4j v1 in the war file, log4j v2 at ear level and you put log4j v3 in your app-server's class path, the module will use the jar in its own module. 例如,如果将log4j v1打包在war文件中,将log4j v2打包在耳边,然后将log4j v3放在应用服务器的类路径中,则该模块将在其自己的模块中使用jar。 take that away and it'll use the one at ear level. 拿走它,它会在耳朵水平使用。 take that out and it will use the one in the app-server's classpath. 取出它,它将使用应用程序服务器的类路径中的那个。 Things get more tricky when you have complex dependencies between modules. 当模块之间具有复杂的依赖关系时,事情变得更加棘手。

Best is to put application global libraries at ear level. 最好的方法是将应用程序全局库放在耳边。

There must be a better way than the way I do it, but I tend to do this in a very manual way. 一定有比我更好的方法,但是我倾向于以一种非常手动的方式来做到这一点。

  1. Every Jar must have it's version number in the file name (if it doesn't change it's name). 每个Jar的文件名中都必须带有版本号(如果不更改名称)。
  2. each application has it's own classpath. 每个应用程序都有自己的类路径。
  3. There must be a reason to start using an updated Jar (new version). 必须有理由开始使用更新的Jar(新版本)。 Don't just change because it is available, change because it gives you functionality that you need. 不要仅仅因为它可用而进行更改,而是因为它为您提供所需的功能而进行更改。
  4. Each release must include all Jars that are needed. 每个发行版都必须包含所有需要的Jar。
  5. I keep a Version class that knows the list of Jars it needs (this is coded into the source file) and can be checked at runtime against the list of Jars in the classpath. 我保留了一个Version类,该类知道它需要的Jar列表(已编码到源文件中),并且可以在运行时根据类路径中的Jar列表进行检查。

As I said, it is manual, but it works. 就像我说的那样,它是手动的,但是有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM