What is executable jar / Uber jar / shade jar / shadow jar / fat jar?


In Java, if you want to run a java program, you need a jar package or class file containing the main method class, and then execute the command

#Run a class file
java $class

#Run a java package (main class specified in manifest)
java -jar $jarfile

#Run the main method of a class, and add multiple jar packages to the classpath of the runtime
Java - CP (- classpath) $path (directory / jar file / zip file) # zip file should conform to the specification of jar format

This method will have some disadvantages, because most Java programs contain a lot of dependencies. If you want to start this program, you must pass the-classpathTo specify these dependent package files, and the classpath must be specified on the server, which is not very convenient

Especially with the popularity of Devops / microservices, this method of specifying classpath is too inflexible. Can we directly build an aggregate jar package, publish or run it?

Executable Jar

Executable jar (executable jar package) generally means that all dependent jar packages are placed in one jar package. This jar package contains all jar package codes that run time needs to rely on, but it does not specify the way of “putting”. You can put the dependent jar package directly in the entry jar package, just like this

├─executable jar
│  ├─com...
│  ├─lib
│  │  ├─io.netty....jar
│  │  ├─com.google....jar
│  │  ├─com.github....jar
│  │  ├─org.apache.....jar

You can also copy the files in the dependent jar package to the jar package of the portal, just like this:

├─executable jar
│  ├─com...
│  ├─io.netty.... classes
│  ├─com.google.. classes
│  ├─com.github.. classes
│  ├─org.apache.. classes

Spring boot can be regarded as delivering executable jar to thousands of families. Spring boot provides a maven plug-inspring-boot-maven-plugin, this plug-in can package all your Maven dependent jar packages into a jar file during construction, and load the jar packages into these executable jar packages through the classloader and startup classes of spring boot, which is the first way described above: put the dependent jar packages directly into the entry jar package

Uber Jar

The first time I saw this word, I was at a loss. I didn’t know what the meaning of this word was. Uber took a taxi?

After looking up the information, I found out that the original word of Uber jar isÜber Jar, is a German word that can be interpreted as “over” and ends, but in the actual context, it may be more appropriate to translate it as “everything”.

This term was originally coined by developers who thought that putting all dependencies and their own code into a jar file could solve many conflicts. But most of the input methods are GermanÜIt’s hard to type, so it’s called Uber.

Fat jar

Fat jar is a good explanation for fat, fat and big: fat jar and Uber jar mean jar package that contains all dependent packages

Shade Jar/Shadow Jar

shadeShade jar is to package jar package and its dependent packages into a jar file, and provide the function of shade / rename some dependent packages

For example, a maven project relies on many third-party packages, but you want to rename some packages during actual packaging. The process of renaming can be called shade here

Here is a detailed explanation of “shade”. The purpose of shade in this process is to rename some packages, so why rename them?

For example, when we develop an agent based on Java instrumentation API, we also need to rely on some third-party packages, such as netty, so we need to load our agent jar package in the form of – javaagent or dynamic attach agent jar in actual operation;

The agent loaded here can only be an independent jar package, so first of all, we need to build a “Uber jar” by typing our agent and its dependent packages into a jar package. Then we need to consider the problem of class package conflict, because the class of the dependent package in the agent and the class in the target JVM process are likely to conflict, for example, the agent relies on netty 4.1.58.final, while the target JVM process relies on netty 4.0.14.final, and our agent uses an API that does not exist in 4.0.14 (for example, the method of a class is newly added in the new version); at this time, the program will make an error, nosuchmethoderror, because the target process has loaded that class, and the class with the same name in the agent package will not be loaded repeatedly

To solve this problem, there is a simple solution. When building “Uber jar”, modify and relocate the package name of the dependent package, such asio.nettyAmend to readcom.github.kongwu.io.nettyAt the same time, all references in Java code are modified to the package name after relocation. In this way, by modifying the package name, the problem of dependency package class conflict is perfectly avoided

The above “relocation” behavior is called shade, or shadow

The shade plug-in in Maven ishttps://maven.apache.org/plugins/maven-shade-plugin/, you can package the program into a separate jar package, including dependency packages

Another similar Maven plug-in ishttps://maven.apache.org/plugins/maven-assembly-plugin/usage.html, can also achieve the same effect

There are similar plug-ins in gradlehttps://imperceptiblethoughts.com/shadow/, the function is also very powerful, also supports the shade function

reference resources