类加载器问题-如何确定要加载的库版本(jar文件)
我刚刚解决了另一个*我虽然正在使用该版本的图书馆,但显然我的应用服务器已经加载了旧版本的-此库-*问题(叹气)。
有人知道一种验证(或者监视)应用程序是否可以访问所有适当的jar文件或者已加载的类版本的好方法吗?
提前致谢!
[P.S.在我看来,这是一个很好的理由开始使用OSGi模块架构!]
更新:这篇文章也有帮助!通过将JBoss的类加载器写入日志文件,它使我了解到了哪些类加载了JBoss的类加载器。
解决方案
我认为没有一个很好的方法来检查这一点。而且我不确定我们是否要这样做。我们需要做的是熟悉应用服务器的类加载架构,并了解其工作原理。
关于它如何工作的简化解释是:EJB或者Web应用程序将首先在其自己的模块(ejb-jar或者war)中声明的库中查找类或者资源。如果在那里找不到类,则类加载器将请求转发到其父类加载器,该父类加载器是声明的依赖项(通常是ejb)或者负责加载在ear包中声明的库和资源的应用程序类加载器。如果仍然找不到该类或者资源,则将请求转发到应用服务器,该服务器将在其自己的类路径中查找。
话虽这么说,我们应该记住,Java EE模块(web-app,ejb)将始终从最接近作用域的jar中加载类。例如,如果将log4j v1打包在war文件中,将log4j v2打包在耳边,然后将log4j v3放在应用服务器的类路径中,则模块将在其自己的模块中使用jar。拿走它,它会在耳朵的水平上使用它。删除它,它将使用应用程序服务器的类路径中的那个。当模块之间具有复杂的依赖关系时,事情变得更加棘手。
最好的方法是将应用程序全局库放在耳边。
一定有比我做的更好的方法,但是我倾向于以一种非常手工的方式来做。
- 每个Jar的文件名中都必须带有版本号(如果未更改,则为名称)。
- 每个应用程序都有自己的类路径。
- 必须有理由开始使用更新的Jar(新版本)。不要仅仅因为它可用而进行更改,而是因为它为我们提供所需的功能而进行更改。
- 每个发行版都必须包含所有需要的Jar。
- 我保留了一个Version类,该类知道它需要的Jar列表(已编码到源文件中),并且可以在运行时根据类路径中的Jar列表进行检查。
就像我说的那样,它是手动的,但是有效。
在Java的当前版本中,库版本控制是一个很笼统的术语,它依赖于使用有用清单正确打包的JAR。即使这样,正在运行的应用程序仍然需要大量工作来以有用的方式将这些信息收集在一起。 JVm运行时对我们毫无帮助。
我认为我们最好的选择是在构建时执行此操作,使用Ivy或者Maven等依赖项管理工具来获取所有内容的正确版本。
有趣的是,Java 7可能会包括恰好适合此类情况的适当的模块版本控制框架。目前尚不能,
如果我们碰巧正在使用JBoss,则有一个MBean(类加载器存储库iirc),我们可以在其中请求已加载特定类的所有类加载器。
如果所有其他方法均失败,则始终存在" java -verbose:class",它将为正在加载的每个类文件打印jar的位置。
如果我们在jar清单中有适当的版本信息,则可以使用一些方法来检索和测试版本。无需手动读取清单。
java.lang.Package.getImplementationVersion()和getSpecificationVersion()以及isCompatibleWith()听起来像它们会做我们想要的。
我们可以使用this.getClass()。getPackage()等方式获取Package。
java.lang.Package的javadoc没有提供这些属性的特定清单属性名称。 Google进行了快速搜索,网址为http://java.sun.com/docs/books/tutorial/deployment/jar/packageman.html