directory
- 1. Bugs
- 2. Try to solve the case
- 3. The truth emerges
- 4. To summarize
- Update record
- Related articles recommended
1. Bugs
Live migration of an application from Docker to a Linux host.
Run the docker exec it $CONTAINER /bin/sh command to enter the CONTAINER. Ps -ef finds only one process: jar-jar xxx.jar. Unzip the JAR package as shown:
Unlike the jar structure of SpringBoot, there are classes, configuration files, and meta-INF directories.
Looking at the env environment variable, there is no CLASSPATH value either. Wondering (where are those dependent JAR packages loaded from?) But I didn’t figure out what was going on.
Jar = jar = jar = jar = jar = jar = jar = jar It suddenly occurred to me that there was a SYNC_lib directory in the same directory as the original Docker container JAR. This directory seems to contain the third-party packages that the JAR depends on.
Migrate the SYNC_lib directory to the same directory as the JAR package and specify classpath to restart: Java -cp.:SYNC_lib/*: xxx.jar. When all classes are loaded, there is an error that the driver of the database is not up to date. Copy a new driver to the SYNC_lib directory:
mv SYNC_lib/Postgresql-old-version.jar SYNC_lib/Postgresql-old-version.jar.bak
cp /path/Postgresql-new-version.jar SYNC_lib/
Copy the code
Java-cp.:SYNC_lib/*: xxx.jar: java-cp.:SYNC_lib/*: xxx.jar: java-cp.:SYNC_lib/*: xxx.jar
What’s going on? The new driver package is already in the classpath, so why not find the class? I also unzipped the new Driver package to make sure it found the org.postgresql.Driver class.
Even weirder is that switching to an older version of the Driver package will now load the org.postgresql.Driver class (verbose on the JVM will print the loaded classes and the corresponding JAR package in the log).
Docker learning reference fengmengzhao. Making. IO / 2021/06/25 /… .
2. Try to solve the case
To summarize the suspects at the scene:
- Question 1: used by Java processes inside the container
java -jar xxx.jar
Start, command line andCLASSPATH
None of the environment variables are specifiedSYNC_lib
How does the JVM instance load these third partiesjar
The package? - Question 2: Specifies after the migration
classpath
Start the JAR package, only replacedclasspath
The next JAR package version, unexpectedly reported an errorClassNotFoundException
?
I’m running out of options, so I have to manually write code to see if I can load the class from the specified classpath:
import java.security.*;
public class FindClass {
public static void main(String args[]) { Class<? > clazz =null;
try {
clazz = Class.forName("com.uxun.uxunplat.util.OperateResult");
} catch(ClassNotFoundException e) { e.printStackTrace(); } CodeSource cs = clazz.getProtectionDomain().getCodeSource(); String location = cs.getLocation().getPath(); System.out.println(location); }}Copy the code
Org.postgresql. Driver is successfully loaded, indicating that the new Driver JAR package is ok, and the command line parameter -classpath (or -cp) is set correctly.
Scratching their heads……
3. The truth emerges
Instead of using the jar package, you can start the class containing the main() method directly.
The main() method starts:
#Here add xxx.jar to -cp
#Add the application that was started with -jar to the classpath
java -cp .:SYNC_lib/*:xxx.jar: com.xxx.xxx
Copy the code
The application started successfully!
Sure enough, the JAR package is the demon. At this point, I open the JAR again, this time without ignoring any details, and open the meta-INF \ manifest.mf file, as shown below:
The original mystery is here, beat the chest, regret late!
The meta-INF \ manifest. MF file is the metadata file of the JAR package, which specifies:
Main-Class
: Entry class for the JAR package (containsmain
Method class).Class-Path
: Classpath path of the dependent JAR package. Jar package paths are separated by Spaces.
Solve:
- Question 1Jar package in container is not set
classpath
Also able to load third party dependencies, not metaphysics, butclasspath
Specified in the JAR package. - Question 2: An error occurs when the driver package is replaced
ClassNotFoundException
Is because ofMANIFEST.MF
Defined in the fileclasspath
Overrides the command line-classpath
Parameter Settings. That is, correctly specified on the command line-classpath
It didn’t actually work (not because the parameters were incorrectly set, but because the parameters were overwritten).
In fact, back in the days of “slash-and-burn”, building a Java program with third party dependencies without building tools (e.g. Ant, Maven, etc.) can be done with the command:
#The c argument creates the JAR archive
#Parameter v indicates that detailed logs are printed
#The parameter f represents the name of the specified jar, in this case xxx.jar
#The parameter m specifies the metadata information file, in this case manifest.txt
jar cvfm xxx.jar MANIFEST.txt com.xxx.xxx
Copy the code
About the jar packaging and MANIFEST. MF more references: docs.oracle.com/javase/tuto… .
Modern Java program development using IDE integrated development environment, do not need to manually type commands. For example, export a JAR package with IDEA:
1). Add an artifact to the project.
2). Perform the build and export the JAR file.
Even though modern application development is much more convenient with ides, basic knowledge (such as what is MANIFEST in jar packages? What does it do? Is conducive to the understanding of programming system.
4. To summarize
- Don’t dabble at a point of doubt. If you skip this point, you may be off track from finding the bug, and it will be harder to get back to the correct direction. This example does not give much thought to why, without specifying the classpath,
java -jar xxx.jar
Can run normally; I didn’t open the JAR package and look at itMANIFEST.MF
File contents. If either of these two are done, the case will be solved in the first 30% of the time. - Sometimes what you see is not just a bug. Try to control variables and locate the cause of the exception. Avoid a pot of porridge, disorderly attempt, finally physical and mental exhaustion, the brain is not clear. In this example, the connected library is an older version of the Postgresql library. An error occurs if the driver of an earlier version is used. An error occurs after a higher version is upgraded
ClassNotFoundException
To make sure that it is not the older version of the driver that is unavailable, but that there is a problem with the jar package loading, do not go astray. - Based on cognition, find conclusions that can be derived with certainty. In this example, after replacing the driver JAR package, the
ClassNotFoundException
In fact, you can assume that the command line argument does not ultimately work (in this case, in the JAR package)MANIFEST
File overwritten). Of course, cognition may have blind areas, one more step verification, if found cognitive blind areas, to understand the relevant knowledge.
Update record
- 2022-01-12 18:10 Read, optimize, erratum nuggets column before publication
Related articles recommended
- Docker Guide -2021.