Java 类加载器问题 - 如何确定加载了哪些库版本(jar 文件)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/139534/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Classloader issues - How to determine which library versions (jar-files) are loaded
提问by Johan Pelgrim
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).
我刚刚解决了另一个 *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(叹气)。
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!
提前致谢!
[P.S. A very good reason to start using the OSGi module architecturein my view!]
[PS在我看来,这是开始使用OSGi 模块架构的一个很好的理由!]
Update: Thisarticle helped as well! It gave me insight which classes JBoss' classloader loaded by writing it to a log file.
更新:这篇文章也有帮助!它让我深入了解 JBoss 的类加载器通过将其写入日志文件来加载哪些类。
采纳答案by Tom
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 的位置。
回答by entzik
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). 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. 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.
其工作原理的简化解释是:EJB 或 Web 应用程序将首先在其自己的模块(ejb-jar 或 war)中声明的库中查找类或资源。如果在那里找不到该类,类加载器会将请求转发到其父类加载器,它是声明的依赖项(通常是 ejb)或负责加载在 ear 包中声明的库和资源的应用程序类加载器. 如果仍未找到类或资源,则请求将转发到应用服务器,该服务器将在其自己的类路径中查找。
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. 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. 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.
话虽如此,您应该记住 Java EE 模块(web-app、ejb)将始终从最近范围内的 jar 加载类。例如,如果您将 log4j v1 打包在 war 文件中,将 log4j v2 打包在耳朵级别并将 log4j v3 放在您的应用程序服务器的类路径中,则该模块将在其自己的模块中使用该 jar。拿走它,它会在耳朵高度使用那个。取出它,它将使用应用程序服务器的类路径中的那个。当模块之间存在复杂的依赖关系时,事情会变得更加棘手。
Best is to put application global libraries at ear level.
最好是将应用程序全局库放在耳朵级别。
回答by Ron Tuffin
There must be a better way than the way I do it, but I tend to do this in a very manual way.
一定有比我做的更好的方法,但我倾向于以非常手动的方式来做到这一点。
- Every Jar must have it's version number in the file name (if it doesn't change it's name).
- each application has it's own classpath.
- There must be a reason to start using an updated Jar (new version). Don't just change because it is available, change because it gives you functionality that you need.
- Each release must include all Jars that are needed.
- 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.
- 每个 Jar 必须在文件名中包含它的版本号(如果它没有改变它的名称)。
- 每个应用程序都有自己的类路径。
- 必须有理由开始使用更新的 Jar(新版本)。不要仅仅因为它可用而改变,而是因为它提供了你需要的功能而改变。
- 每个版本都必须包含所有需要的 Jar。
- 我保留了一个 Version 类,它知道它需要的 Jars 列表(这被编码到源文件中),并且可以在运行时根据类路径中的 Jars 列表进行检查。
As I said, it is manual, but it works.
正如我所说,它是手动的,但它有效。
回答by skaffman
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. 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.
在当前版本的 Java 中,库版本控制是一个相当模糊的术语,它依赖于使用有用清单正确打包 JAR。即便如此,正在运行的应用程序要以有用的方式收集这些信息也需要大量工作。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. Not that that helps you right at this moment,
有趣的是,Java 7 可能会包含一个适当的模块版本控制框架来处理这类事情。并不是说此刻对你有帮助,
回答by John M
If you've got appropriate versions info in a jar manifest, there are methods to retrieve and test the version. No need to manually read the manifest.
如果您在 jar 清单中有适当的版本信息,则有一些方法可以检索和测试版本。无需手动读取清单。
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() 等方式获取包。
The javadoc for java.lang.Package doesn't give the specific manifest attribute names for these attributes. A quick google search turned it up at http://java.sun.com/docs/books/tutorial/deployment/jar/packageman.html
java.lang.Package 的 javadoc 没有给出这些属性的具体清单属性名称。一个快速的谷歌搜索在http://java.sun.com/docs/books/tutorial/deployment/jar/packageman.html