It happens that in a large project running in jvm, it
suddenly turns out that the application does not work and does not even start when updating any of the dependencies of the project. The same is possible because of any other event that changed the order of the libraries in the application's classpath.
Lyrical digression about the cause of this
phenomenon , everything is ugly. In jvm, before the implementation of the out-of-the-box
jigsaw project, it was not possible in the same jvm to simultaneously load several different versions of the same class with the same name package fully qualified name from different jar files. There were J2EE class loaders, self-written class loaders or their composition, OSGI containers, but this is a topic for another publication and a completely different world ... As a result, only one of these classes was loaded and not the fact that it is needed with all the ensuing consequences.
So, if your application happened to start a flurry of NoSuchMethodError / ClassNotFoundException or behave strangely without a single change in the source code of the project. You will be helped by a report on the duplicate classes of their loaders and resources, which can be done using the
jHades library.
')
If you can change the application code, simply add the artifact
org.jhades: jhades: 1.0.4 and the code snippet depending on maven.
new org.jhades.JHades() .dumpClassloaderInfo() .printClasspath() .overlappingJarsReport() .multipleClassVersionsReport();
That's just bad luck, if you find it difficult to include it in the assembly of your application or change management requirements prohibit such changes. In this case, aspect-oriented programming again hurries to the rescue.
In this example, the experimental program remains the SonarQube, as in the articles on
hawt.io/h2 ,
logging jdbc and
CRaSH-ssh . You can read more about the installation and configuration of the sonar and the virtual machine agent in the
hawt.io/h2 publication.
In the case of your application, you need to pass only two additional parameters when starting jvm: -javaagent: aspectj-scripting-1.0-agent.jar indicating the path in the file system to the
agent and the parameter -Dorg.aspectj.weaver.loadtime.configuration = config: file: classpath.xml
Content configuration classpath.xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <configuration> <aspects> <name>com.github.igorsuhorukov.JarhellInfo</name> <type>BEFORE</type> <pointcut>execution(* org.sonar.server.app.WebServer.main(..))</pointcut> <artifacts> <artifact>org.jodd:jodd:3.2</artifact> <classRefs> <variable>ClassLoaderUtil</variable> <className>jodd.util.ClassLoaderUtil</className> </classRefs> </artifacts> <process> <expression> libs = com.github.smreed.dropship.MavenClassLoader.forMavenCoordinates("org.jhades:jhades:1.0.4").getURLs(); java.net.URLClassLoader systemClassLoader = java.lang.ClassLoader.getSystemClassLoader(); for(lib: libs){ ClassLoaderUtil.addFileToClassPath(lib.getFile(), systemClassLoader); } new org.jhades.JHades() .dumpClassloaderInfo() .printClasspath() .overlappingJarsReport() .multipleClassVersionsReport(); </expression></process> </aspects> </configuration>
For your program, you will need to change the pointcut to the appropriate report generation point in your program.
In my case I will give a small part of the report:
Report>> jHades - scanning classpath for overlapping jars:
...
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/xml-apis-1.4.01.jar overlaps with
file: /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar - total overlapping classes: 342 - different classloaders.
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/aspectj-scripting-1.0-agent.jar overlaps with
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/plexus-classworlds-2.5.1.jar - total overlapping classes: 37 - same classloader! This is an ERROR!
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/xml-apis-1.4.01.jar overlaps with
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/stax-api-1.0-2.jar - total overlapping classes: 34 - same classloader! This is an ERROR!
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/stax-api-1.0-2.jar overlaps with
file: /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar - total overlapping classes: 34 - different classloaders.
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/commons-collections-3.2.1.jar overlaps with
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/commons-beanutils-1.8.3.jar - total overlapping classes: 10 - same classloader! This is an ERROR!
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/tomcat-embed-core-8.0.18.jar overlaps with
file: /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar - total overlapping classes: 8 - different classloaders.
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/ejb3-persistence-1.0.2.GA.jar overlaps with
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/tomcat-embed-core-8.0.18.jar - total overlapping classes: 6 - same classloader! This is an ERROR!
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/geronimo-spec-jta-1.0-M1.jar overlaps with
file: /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar - total overlapping classes: 6 - different classloaders.
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/sonar-server-5.1.2.jar overlaps with
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/sonar-core-5.1.2.jar - total overlapping classes: 1 - same classloader! This is an ERROR!
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/sonar-plugin-api-5.1.2.jar overlaps with
file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/sonar-core-5.1.2.jar - total overlapping classes: 1 - same classloader! This is an ERROR!
...
>> jHades multipleClassVersionsReport >> Duplicate classpath resources report:
/javax/xml/xpath/SecuritySupport$4.class has 2 versions for these classpath locations:
sun.misc.Launcher $ AppClassLoader - file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/xml-apis-1.4.01.jar - class file size = 495
Bootstrap class loader - file: /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar - class file size = 896
/javax/xml/transform/sax/SAXResult.class has 2 versions for these classpath locations:
sun.misc.Launcher $ AppClassLoader - file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/xml-apis-1.4.01.jar - class file size = 971
Bootstrap class loader - file: /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar - class file size = 1397
/org/w3c/dom/NameList.class has 2 versions on these classpath locations:
sun.misc.Launcher $ AppClassLoader - file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/xml-apis-1.4.01.jar - class file size = 272
Bootstrap class loader - file: /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar - class file size = 309
/org/w3c/dom/html/HTMLStyleElement.class has 2 versions on these classpath locations:
sun.misc.Launcher $ AppClassLoader - file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/xml-apis-1.4.01.jar - class file size = 299
Bootstrap class loader - file: /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar - class file size = 344
/javax/xml/xpath/SecuritySupport$3.class has 2 versions for these classpath locations:
sun.misc.Launcher $ AppClassLoader - file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/xml-apis-1.4.01.jar - class file size = 482
Bootstrap class loader - file: /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar - class file size = 908
/org/xml/sax/helpers/XMLReaderAdapter.class has 2 versions for these classpath locations:
sun.misc.Launcher $ AppClassLoader - file: /home/igor/dev/projects/sonar-demo/sonarqube-5.1.2/lib/server/xml-apis-1.4.01.jar - class file size = 3251
Bootstrap class loader - file: /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar - class file size = 5005
...
In more detail with the use of aspect-oriented programming and
AspectJ-scripting you can find out in the publications in Habré:
I took the illustration for this article from Wikipedia about the gates of hell,
but without JARs
I hope that the information from this article will be useful to you for diagnosing problems with the application classpath!