The most wonderful six months of work experience problems
background
The company recently bought a project, a series of strange problems on startup, the other's technology stack requirement is Tomcat7 start, but due to our company for safety reasons it is required to start using Tomcat9.
Problem Description
The following are the same as the case of the case where the same war package Tomcat
system | Tomcat version | Can start |
---|---|---|
Windows | Tomcat7 | can |
Windows | Tomcat9 | can |
macOS | Tomcat7 | can |
macOS | Tomcat9 | Can not |
Linux | Tomcat7 | can |
Linux | Tomcat9 | Can not |
Due to the project are not familiar with, resulting in a long time to find to find out why. Ali discovery process is to use open source Arthas
that class problems compiler is running out, and found two classes from different Jar package, so the question turned to the loading order of Jar is what factors led.
Issues get to the bottom
Class two with the same name in the path name of the class loader will load only once
This problem occurs when knew check the information, JVM class loader is a tree structure, in the process of loading the JVM parents adopt delegated model, the higher the level, the class loader will load earlier in its path the type. Here is the level of Tomcat class loader is located.
Bootstrap
|
System
|
Common
/ \
Webapp1 Webapp2 .
复制代码
We know that the problem is two Jar in the same class loader, so ruled out the issue of different levels of class loader caused.
Tomcat7 load Jar package principle
Tomcat to realize his own class loader for loading all class files its own local project jar package, so in the same class loader, if there is the same path and class names so the load order is the order jar package to decide. Who advanced to the jar package, then to which class loader.
But why all the Tomcat7 environment are functioning properly, and in Tomcat9 would not be in it? So when you see the Tomcat7 jar package source loaded in the Context of the project
Tomcat7 jar loading portion, in WebappLoader.setRepositories()
a method in which the paste important codes.
// Looking up directory /WEB-INF/lib in the context
NamingEnumeration<NameClassPair> enumeration = null;
try {
//这一句是获得jar包的路径
enumeration = libDir.list("");
} catch (NamingException e) {
IOException ioe = new IOException(sm.getString(
"webappLoader.namingFailure", libPath));
ioe.initCause(e);
throw ioe;
}
复制代码
list path is obtained under application WEB-INF lib at all a jar. We track go find FileDirContext
the list method has the following sentence
Arrays.sort(names); // Sort alphabetically
复制代码
We can be found in the Tomcat7 made a sort of action to get all the jar packages. To jar packets initials az sorted. And we expect that the loaded jar package initials just in the wrong jar package earlier.
Tomcat9 load Jar package principle
Above we know why Tomcat7 able to start up in all the projects, because Tomcat7 made a sort of action, then when Tomcat9 load Jar package, but also how to do it?
Tomcat9 when the source is loaded by StandardRoot.processWebInfLib()
loading method
protected void processWebInfLib() throws LifecycleException {
WebResource[] possibleJars = listResources("/WEB-INF/lib", false);
for (WebResource possibleJar : possibleJars) {
if (possibleJar.isFile() && possibleJar.getName().endsWith(".jar")) {
createWebResourceSet(ResourceSetType.CLASSES_JAR,
"/WEB-INF/classes", possibleJar.getURL(), "/");
}
}
}
复制代码
In this we can see that Tomcat did not make any moves to Jar taken out, just File file = new File()
so it traverses out. So why the same Tomcat9 same War in Windos can start up package, but in macOS and Linux are not started up yet? After testing found that Java access to the folder all of the following documents are related with the operating system's file system, the same folder contents, taken out in Windows, the name of the output you will find that the output is the result of az sorted, but in macOS or Linux, you can command ll -fi
can output the natural order, you will find that there is no law at all.
solve
To all the problems described above, here we can explain through, and how the next step was resolved.
- Tomcat9 modified source code, Jar package to get all of the time, to sort it
- To get rid of files with conflicts
The first solution can only solve the problem temporarily, that the project can start up normally, but then once it comes to the modification of related classes, then the class conflict which class it? Then the problem is definitely a time bomb.
After the second option is to find files that have conflicts, and then do not find that to be deleted, but found a deletion would pop out the other, removed several items found due to buy the code is not standardized, so this phenomenon particularly, if a simple screening by hand, then extremely troublesome. So I wrote a script ran out project files for all classes of the same name.
Script ideas
- Find all the Java files
- Java files found on
package
that line, then read this line package
The back of the package name and class name spliced into the collection List- We screened the same set of content
Specific script code can go to GitHub to see in. Use simple instructions, the whole project code you want to scan in a folder, for example, I want to scan A, B, C, D four projects.
--/
--scanDir
--A
--B
--C
--D
复制代码
So I just Jar package introduced after the call with the following
List<String> list = FindDuplicate.findDuplicatePath("/scanDir/");
复制代码
Is a collection of returned record indicates a conflict has set a file, the file path conflicts are two
||||||||
spaced