一个类加载的谜团解决了

面对一个好老问题

我在应用程序服务器上遇到一些类加载问题。 这些库被定义为Maven依赖项,因此被打包到WAR和EAR文件中。 不幸的是,其中一些也已安装到应用程序服务器中,但版本不同。 启动应用程序时,我们遇到了与这些类型的问题相关的各种异常。 如果您想深入了解,那么有一篇不错的IBM文章关于这些异常。

即使我们知道该错误是由类路径上的某些双重定义的库引起的,但仍花了两个多小时来调查我们真正需要的版本以及要删除的JAR。

同一周在水罐上偶然发生了相同的话题

几天后,我们参加了“您真的得到了Classloaders吗? 苏黎世Java用户协会会议。 Simon Maple对类加载器进行了非常出色的介绍,并从一开始就介绍了非常深入的细节。 对于许多人来说,这是一次令人大开眼界的会议。 我还必须注意,Simon工作零周转,他为JRebel进行宣传。 在这种情况下,辅导课程通常偏向于实际产品,即辅导员的面包。 在这种情况下,我认为西蒙绝对是绅士和道德主义者,保持了适当的平衡。

创建一个工具,解决神秘问题

只是创造另一个

一周后,我花了一些时间来学习程序,而现在我已经有几个星期没有时间了,所以我决定创建一个小工具,列出所有在类路径中的类和JAR文件,以便可以更轻松地查找重复。 我试图依靠这样的事实,即类加载器通常是URLClassLoader实例,因此可以调用方法getURLs()来获取所有目录名称和JAR文件。

在这种情况下,单元测试可能非常棘手,因为该功能与类加载器的行为密切相关。 为了务实,我决定只做一些从JUnit开始的手动测试,只要代码是实验性的即可。 首先,我想看看这个概念是否值得进一步发展。 我打算执行测试,并查看报告没有重复类的日志语句,然后执行相同的运行,但是第二次向类路径添加一些冗余依赖项。 我使用的是JUnit 4.10,在这种情况下,该版本很重要。

我从命令行执行了单元测试,发现没有重复的类,我感到很高兴。 之后,我从Eclipse执行了相同的测试,并且感到惊讶:我冗余定义了21个类!

12:41:51.670 DEBUG c.j.c.ClassCollector - There are 21 redundantly defined classes.
12:41:51.670 DEBUG c.j.c.ClassCollector - Class org/hamcrest/internal/SelfDescribingValue.class is defined 2 times:
12:41:51.671 DEBUG c.j.c.ClassCollector -   sun.misc.Launcher$AppClassLoader@7ea987ac:file:/Users/verhasp/.m2/repository/junit/junit/4.10/junit-4.10.jar
12:41:51.671 DEBUG c.j.c.ClassCollector -   sun.misc.Launcher$AppClassLoader@7ea987ac:file:/Users/verhasp/.m2/repository/org/hamcrest/hamcrest-core/1.1/hamcrest-core-1.1.jar
...

仔细研究一下,我很容易发现JUnit 4.10具有额外的依赖关系,如maven所示。

$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building clalotils 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ clalotils ---
[INFO] com.verhas:clalotils:jar:1.0.0-SNAPSHOT
[INFO] +- junit:junit:jar:4.10:test
[INFO] |  \- org.hamcrest:hamcrest-core:jar:1.1:test
[INFO] +- org.slf4j:slf4j-api:jar:1.7.7:compile
[INFO] \- ch.qos.logback:logback-classic:jar:1.1.2:compile
[INFO]    \- ch.qos.logback:logback-core:jar:1.1.2:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.642s
[INFO] Finished at: Wed Sep 03 12:44:18 CEST 2014
[INFO] Final Memory: 13M/220M
[INFO] ------------------------------------------------------------------------

这实际上在4.11中已修复,因此如果我将依赖关系更改为JUnit 4.11,则不会遇到此问题。 好。 一半的谜团解决了。 但是,为什么maven命令行执行未报告双重定义的类?

扩展日志记录,越来越多的日志记录我可以发现一条线:

12:46:19.433 DEBUG c.j.c.ClassCollector - Loading from the jar file /Users/verhasp/github/clalotils/target/surefire/surefirebooter235846110768631567.jar

这个文件里有什么? 让我们解压缩它:

$ ls -l /Users/verhasp/github/clalotils/target/surefire/surefirebooter235846110768631567.jar
ls: /Users/verhasp/github/clalotils/target/surefire/surefirebooter235846110768631567.jar: No such file or directory

该文件不会退出! 看来maven创建了这个JAR文件,然后在测试执行完成后将其删除。 再次使用Google搜索,找到了解决方案。

Java从类路径加载类。 可以在命令行上定义类路径,但是应用程序类加载器还有其他来源可以从中获取文件。 一个这样的源是JAR的清单文件。 JAR文件的清单文件可以定义执行JAR文件中的类所需的其他JAR文件。 Maven创建一个JAR文件,除了清单文件定义清单中列出JAR和列出类路径的目录外,该文件不包含其他内容。 这些JAR和目录不是通过getURLs()方法返回的,因此我的小工具(第一个版本)没有找到重复项。

出于演示目的,我已经足够快地在运行mvn test命令的同时复制了文件,并获得了以下输出:

$ unzip /Users/verhasp/github/clalotils/target/surefire/surefirebooter5550254534465369201\ copy.jar 
Archive:  /Users/verhasp/github/clalotils/target/surefire/surefirebooter5550254534465369201 copy.jarinflating: META-INF/MANIFEST.MF    
$ cat META-INF/MANIFEST.MF 
Manifest-Version: 1.0
Class-Path: file:/Users/verhasp/.m2/repository/org/apache/maven/surefire/surefire-booter/2.8/surefire-booter-2.8.jar file:/Users/verhasp/.m2/repository/org/apache/maven/surefire/surefire-api/2.8/surefire-api-2.8.jar file:/Users/verhasp/github/clalotils/target/test-classes/ file:/Users/verhasp/github/clalotils/target/classes/ file:/Users/verhasp/.m2/repository/junit/junit/4.10/junit-4.10.jar file:/Users/verhasp/.m2/repository/org/hamcrest/hamcrest-core/1.1/hamcrest-core-1.1.jar file:/Users/verhasp/.m2/repository/org/slf4j/slf4j-api/1.7.7/slf4j-api-1.7.7.jar file:/Users/verhasp/.m2/repository/ch/qos/logback/logback-classic/1.1.2/logback-classic-1.1.2.jar file:/Users/verhasp/.m2/repository/ch/qos/logback/logback-core/1.1.2/logback-core-1.1.2.jar
Main-Class: org.apache.maven.surefire.booter.ForkedBooter$

实际上,除了定义类路径的清单文件外,别无其他。 但是为什么Maven会这样做呢? 索纳型的人,我个人也认识一些聪明的人。 他们不会无所事事地做这种事情。 创建临时JAR文件以启动测试的原因是, 在某些类路径长度可能超过的操作系统上 ,命令行的长度受到限制 。 即使Java(自Java 6起)本身可以解析类路径中的通配符 ,也不是maven的选择。 JAR文件位于Maven存储库中的不同目录中,每个目录都具有长名称。 通配符解析不是递归的,这是有充分理由的,即使是通配符解析,您也不希望将所有本地存储都放在类路径中。

结论

  • 不要使用JUnit 4.10! 使用旧的或较新的东西,或为意外做好准备。
  • 了解什么是类加载器以及它如何工作,做什么。
  • 使用对命令行长度的最大大小有巨大限制的操作系统。
    或只是忍受限制。

还有吗 你的想法?

翻译自: https://www.javacodegeeks.com/2014/09/a-classloading-mystery-solved.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/362215.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue 隐藏滚动条

element-ui隐藏组件scrollbar&#xff1a; <el-scrollbar style"height:100%"> </el-scrollbar>真正的隐藏滚动条代码在这里&#xff1a;.el-scrollbar__thumb {display: none;}.el-scrollbar__wrap {overflow-x: hidden;overflow-y: auto;}更多专业前端…

希望菜鸟通过博客园的记录和学习,成为一个可以能把自己想发实现的小程序员!...

我是一个学习电气自动化专业的毕业生&#xff0c;工作多年&#xff0c;接触过c语言、vb、单片机、PLC、linux&#xff0c;希望菜鸟通过博客园的记录和学习&#xff0c;成为一个可以能把自己想发实现的小程序员&#xff01; 生活和工作中有许多自己的表格和统计数据&#xff0c;…

获取DOM元素方法小结

在开发中不可避免的需要操作DOM&#xff0c;现在就来总结一下原生的获取DOM的API。 getElementById() 该方法是最常用的通过元素的id属性来获取DOM元素的API&#xff0c;返回一个DOM元素。 <body><div id"div">我是div</div><script type&qu…

推荐:个人时间跟踪工具 ManicTime

在《个人管理 &#xff0d; 目标管理之前&#xff0c;你会时间管理吗》中我介绍的时间管理三阶段之一“对时间的实际去处进行记录”时说过现在有很多时间管理工具&#xff0c;也有人希望我介绍一下我使用的工具&#xff0c;那么我就利用中午休息时间&#xff0c;马上给大家介绍…

Java和甜蜜的科学

当您使用Java进行开发已有15年并且同事要求您帮助他们调试空指针异常时&#xff0c;您不会感到惊讶。 通常&#xff0c;很明显什么是null&#xff0c;唯一要做的就是找出原因。 有时会有些困难&#xff0c;因为有人创建了一系列取消引用的对象。 前几天&#xff0c;我遇到了一…

SQL Server 2005怎样进行性能排错

很少会有偶然的性能下降。设计不良的数据库或工作负载配置不正确的系统会经常导致性能问题。管理员需要能预先阻止或最小化问题的影响&#xff0c;当管理员遇到问题时&#xff0c;应该诊断问题并采取正确操作来修复问题。本文提供了按部就班的指导&#xff0c;通过使用可用的工…

AcWing 207. 球形空间产生器 (高斯消元)打卡

有一个球形空间产生器能够在n维空间中产生一个坚硬的球体。 现在&#xff0c;你被困在了这个n维球体中&#xff0c;你只知道球面上n1个点的坐标&#xff0c;你需要以最快的速度确定这个n维球体的球心坐标&#xff0c;以便于摧毁这个球形空间产生器。 输入格式 第一行是一个整数…

jQuery中的ready

基于jQuery v1.8.3 在js与DOM交互之前要确保DOM已经加载构建完成&#xff0c;在jQuery中都是使用 (fn)或者(document).ready(fn)来确保自己写的代码在DOM构建完成之后执行。 那么jQuery的ready事件内部怎么实现的呢&#xff1f; 通过阅读源码&#xff08;line:842 ~ 898&…

JVM PermGen –您在哪里?

这篇文章介绍了JVM内存结构的一些基础知识&#xff0c;并快速窥视了PermGen&#xff0c;以了解自Java SE 8出现以来它已消失的地方。 裸基础 JVM只是系统上运行的另一个进程&#xff0c;魔术始于java命令。 像任何OS进程一样&#xff0c;它需要内存才能运行。 记住– JVM本身是…

vue 开发过程中遇到的问题

1. gitlab团队协作开发 2. element ui 问题集锦 3. 使用vue和ElementUI快速开发后台管理系统 更多专业前端知识&#xff0c;请上 【猿2048】www.mk2048.com

python6-函数

转载于:https://www.cnblogs.com/WIU1905/p/11101249.html

Windows Phone 7.1 “芒果” SDK Beta 下载地址

Windows Phone 7.1 “芒果” SDK Beta 今天早上发布&#xff0c;第一时间下载体验。功能果然激动人心。 下载地址&#xff1a; 离线ISO请点我&#xff0c; 在线安装请点我。转载于:https://www.cnblogs.com/finehappy/archive/2011/05/25/2056849.html

Windows系统安装 ffmpeg

下载及解压 ffmpeg官方下载地址&#xff1a;https://ffmpeg.org/download.html 下载好后将其解压至你想保存的位置中。 环境变量设置 打开Windows设置&#xff0c;在搜索框输入&#xff1a;系统高级设置。 新建环境变量&#xff0c;并输入bin目录具体位置。 安装检查 按住 w…

基于webpack3.x从0开始搭建React开发环境

在开发react单页面的时候无可避免的要使用到webpack打包&#xff0c;今天就从零开始搭建一个react的开发环境。 需要实现的功能有&#xff1a; 使用Babel编译ES6编译.jsx文件实现热更新编译CSS预处理文件Less&#xff0c;CSS后处理文件PostCSS提取公共的CSS样式到一个公共的文…

死机简单配置

编写整个框架的目的是为了处理应用程序的配置。 我更喜欢一种简单的方法。 如果通过配置我们的意思是“ 部署之间可能有所不同的所有内容 ”&#xff0c;那么我们应该尝试使配置保持简单。 在Java中&#xff0c;最简单的选项是不起眼的属性文件。 属性文件的缺点是&#xff0c…

VMWARE虚拟机环境网卡3种模式介绍

NAT模式&#xff1a;相当于你的虚拟机通过你的宿主机上网 桥接模式&#xff1a;相当于你的虚拟机和宿主机同在一个局域网通过静态屁访问网络 仅主机模式&#xff1a;虚拟机只能和宿主机通信&#xff0c;但宿主机不会为虚拟机提供任何路由服务&#xff0c;不能连接到实际网络中转…

一个网站的诞生- MagicDict开发总结2 [ACCESS的烦恼]

说到数据库&#xff0c;有很多很多选择&#xff0c;除了MS-SQL&#xff0c;Oracle&#xff0c;SQLite&#xff0c;MySql&#xff0c;这些大家都非常熟悉的同学&#xff0c;还有DB2&#xff0c;IMSDB&#xff08;灰常灰常古老的数据库&#xff0c;用在OS390等Mainframe中&#x…

TS引用JS模块

为TypeScript引用的JS写声明文件 写TypeScript声明文件的时候会有三个困惑&#xff0c;一个是声明文件是什么&#xff1f;一个是声明文件怎么写&#xff1f;还有一个是TS依据什么规则找到我们的声明文件或者说模块。 第一个问题&#xff1a;按照我的理解声明文件就是告诉TS编…

angular模块

深入浅析AngularJS中的模块 模块是AngularJS应用程序的一个组成部分&#xff0c;模块可以是一个Controller、Service服务、Filter过滤器、directive指令&#xff0c;这些都属于模块。 大多数的应用程序都有一个函数入口main文件&#xff0c;用它来进行初始化&#xff0c;加载…

对象应该是不可变的

在面向对象的编程中&#xff0c;如果对象的状态在创建后无法修改&#xff0c;则该对象是不可变的 。 在Java中&#xff0c;不可变对象的一个​​很好的例子是String 。 创建完成后&#xff0c;我们将无法修改其状态。 我们可以要求它创建新的字符串&#xff0c;但是它自己的状…