The jar package for your SpringBoot project is thin and slim. The tutorials searched online have not been used

Thin the jar package for your SpringBoot project


The default packaging method of Spring boot is the full amount of dependent packages (also known as fat packages), which is not only slow in packaging, but also large in size and slow in transmission. Today I will teach you how to slim down spring boot.

Background
Now the microservice architecture is becoming more and more popular, and it is common to have more than 10 spring boot-based service modules for a project. Assuming that a service module packaged into a jar package is 100M, then a full release may require uploading a 1G file. It may not feel much when the network situation is good, but if the code needs to be copied to the intranet for release, or uploaded to some foreign servers, it will seriously affect work efficiency.

So, is there any way to slim down the jar package of spring boot we typed?
The answer is yes, through relevant configurations, when spring boot is packaged, only some frequently changing dependency packages are loaded, such as the common module of the project, some API modules that call the feign interface, and those fixed dependency packages are directly uploaded to the server. In the specified directory, you can specify the directory loaded by the lib package through the command when the project starts. In this way, the jar package we typed out is less than a few M at most, which greatly reduces the size of the jar package of the spring boot project and improves the efficiency of publishing and launching.

Supplement:
fat jar: Fat jar, the output jar package contains all dependent packages.
The advantage is that it can be run directly without adding other commands. The disadvantage is that the volume is too large and the transmission is difficult.

**thin jar:** is a thin package. The output jar package only contains some frequently changing dependent packages, which are generally public modules in the project or some API interface dependent modules.
The advantage is that the size is small, which is conducive to improving the efficiency of project release;
the disadvantage is that external dependency packages may have security risks. If the project's maven dependencies change frequently, it will be more troublesome to maintain the lib directory on the server, and it is not conducive to problem location.

Slimming exercise
1. Modify maven packaging parameters

<build>
ᅠ ᅠ ᅠ ᅠ <plugins>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ <plugin>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ <groupId>org.springframework.boot</groupId>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ <artifactId>spring-boot-maven-plugin</artifactId>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ <configuration>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ <layout>ZIP</layout>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ<includes>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ<include>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ<groupId>nothing</groupId>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ<artifactId>nothing</artifactId>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ</include>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ<include>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ<groupId>com.huacloud.tax.rpc</groupId>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ<artifactId>common</artifactId>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ</include>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ</includes>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ </configuration>
ᅠ ᅠ ᅠ ᅠ ᅠ ᅠ </plugin>
ᅠ ᅠ ᅠ ᅠ </plugins>
ᅠ ᅠ </build>



illustrate:

The layout
is used to configure the type of Main-Class in the executable jar package. It must be set to ZIP here, so that the Main-Class in the typed jar package is PropertiesLauncher.

includes
will need to keep the jar package, according to groupId and artifactId (note that both are required) include.
nothing represents non-existing dependent packages, which means that no dependent packages are introduced into
common is the imported public service module.

2. Execute maven packaging
First execute mvn clean, then execute mvn package

Copy the packed package in the target directory to the D:\web directory, and rename it to tax-ws-thin-zip.jar.

View the MANIFEST.MF file in the META-INF directory in tax-ws-thin-zip.jar through the decompression tool:

It is found that the value of Main-Class has indeed changed to PropertiesLauncher, indicating that our configuration is successful.
(As for why it is necessary to configure Main-Class as PropertiesLauncher, I will introduce it later)

3. Compare the volume of FatJar and ThinJar:

It can be found that the volume of the thin package tax-ws-thin.jar is much smaller than that of the fat package.

4. Copy the lib package from the fatJar package to the D:\web directory

5. Start the jar package by command

D:\web>java -Dloader.path="D:\web\lib" -jar tax-ws-thin.jar
1
Configure the loading path of the external dependency package through the startup parameter loader.path.

The successful start of the project indicates that the loading of the outsourced dependency package we configured has taken effect.

Principle exploration
Why setting the Main-Class of the executable jar package to PropertiesLauncher can specify the loading path of the dependent package by configuring the startup parameter loader.path?
First of all, we have an understanding of the Launcher in the implementation principle of the spring boot executable jar package.

The following is excerpted from the spring boot official website:
The org.springframework.boot.loader.Launcher class is a special bootstrap class that is used as the main entry point for the executable jar. It's the actual Main-Class in the jar file that sets the appropriate URLClassLoader and finally calls the main() method.

There are three launcher subclasses (JarLauncher, WarLauncher and PropertiesLauncher). Their purpose is to load resources (.class files, etc.) from nested jar files or war files in directories (rather than files explicitly on the classpath). For JarLauncher and WarLauncher, nested paths are fixed. JarLauncher is located in BOOT-INF/lib/, while WarLauncher is located in WEB-INF/lib/ and WEB-INF/lib-provided/. Additional jars can be added in these locations if desired. By default, PropertiesLauncher looks in BOOT-INF/lib/ in your application archive. You can add additional locations by setting an environment variable called LOADER_PATH or loader.path in loader.properties (which is a comma-separated list of directories, archives, or directories within an archive).
———————————————

That is to say, the launcher Launcher loads dependent resources for project startup. There are 3 launchers (JarLauncher, WarLauncher, and PropertiesLauncher). The paths for JarLauncher and WarLauncher to load resources are fixed, and PropertiesLauncher can use the environment variable loader.path. Specifies where to load resources.


Layout attribute value description:

JAR, the usual executable jar
Main-Class: org.springframework.boot.loader.JarLauncher

WAR, the usual executable war, requires servlet container dependencies located in
Main-Class: org.springframework.boot.loader.warLauncher

ZIP, that is, DIR, is similar to JAR
Main-Class: org.springframework.boot.loader.PropertiesLauncher
(just remember this, there are fewer other application scenarios)

PropertiesLauncher attribute configuration

PropertiesLauncher has some special features that can be enabled via external properties (system properties, environment variables, manifest entries or loader.properties). The following table describes these properties:

Key purpose
loader.path lib package loading path
loader.home is used to resolve the relative path in loader.path. For example, given loader.path = lib, then ${loader.home}/lib is the classpath location (and all jar files in that directory). This property is also used to find the loader.properties file, as shown in the example /opt/app below. It defaults to ${user.dir}.
loader.args Default arguments for the main method (separated by spaces).
loader.main The name of the main class to start (eg com.app.Application)
loader.config.name The path to the properties file (eg classpath:loader.properties). Defaults to loader.properties.
loader.system Boolean flag indicating that all properties should be added to system properties. The default is false.
For more information, you can view the official website's documentation on the spring boot executable jar package: The Executable Jar Format

Trap Correction
I have seen a method on the Internet before that does not configure layout=ZIP, but after directly packaging it into a thin package, use -Djava.ext.dirs to specify the loading path of the external dependency package in the startup command.

D:\web>java -Djava.ext.dirs="D:\web\lib" -jar tax-ws-thin.jar
1
Principle analysis:
-Djava.ext.dirs will override the ext settings of Java itself, java. The directory specified by ext.dirs is loaded by the ExtClassLoader loader. If your program does not specify this system property, the loader loads all jar files in the $JAVA_HOME/jre/lib/ext directory by default. But if you manually specify the system properties and forget to add the $JAVA_HOME/jre/lib/ext path, then ExtClassLoader will not load the jar files under $JAVA_HOME/lib/ext, which means you will lose some functions, For example, the encryption and decryption algorithm that comes with java is implemented.

Therefore, directly forcibly modifying the loading path of the java default extension class loader through this writing method can easily lead to some problems. It is best not to use it casually.

The problem that the Oracle driver package cannot be found
When using -Djava.ext.dirs to configure the loading path of the external dependency package, there is a problem that the Oracle driver package cannot be loaded. At this time, you need to add
-Doracle.jdbc.thinLogonCapability=o3 , configure oracle login compatibility

Expansion: Parental Delegation Mechanism
Here, in terms of expansion, it involves java's parental delegation loading mechanism.


1. BootStrapClassLoader: Bootstrap class loader, the ClassLoader is created at boot time and written in the JVM kernel. It is not a bytecode file, but a binary code written in C++, so developers cannot obtain the bootstrap classloader A reference to a class cannot be manipulated by reference. This loader loads the class library under $JAVA_HOME/jre/lib (or specified by the parameter -Xbootclasspath).

2. EXTClassLoader: Extended class loader, ExtClassLoader will load the class library under $JAVA_HOME/jre/lib/ext (or specified by the parameter -Djava.ext.dirs).

3. AppClassLoader: The application loader will load the class library under the path specified by the java environment variable CLASSPATH, and the path specified by CLASSPATH can be obtained through Systemn.getProperty("java.class.path"), which can be overwritten .

4. CustomClassLoader: The custom loader is the CLassLoader defined by the user. For example, the standardClassLoader of tomcat belongs to this category.

ClassLoader parent delegation mechanism:
1. When APPClassLoader loads a class, it will not load the class by itself first, but delegate the class loading request to the parent class loader EXTClassloader to complete.

2. When EXTClassLoader loads a class, it will not try to load the class first, but delegate the class loading request to BootStrapClassLoader to complete.

3. If BottStrapClassLoader fails to load, it will use EXTClassLoader to try to load.

4. If EXTClassLoader also fails to load, it will use APPClassLoader to load. If APPClassLoader also fails to load, it will report an abnormal ClassNotFundException.

Summary
1. Why do you need to slim down the executable jar package for the spring boot project?
2. Description of the three types of launchers for spring boot.
3. How to configure the PropertiesLauncher launcher to load external dependencies.
4. Point out that by specifying -Djava.ext. The dirs parameter realizes the problem of external dependency package loading
5. The extension explains java's parent delegation loading mechanism
6. The solution to the problem that the external dependency package cannot be loaded with the Oracle driver package

Finally,
thank you for your recent support. Although learning is my own business, it is really encouraging to see everyone's likes, comments and concerns. Thank you.
I will continue to work hard to share more high-quality technical articles, and hope to communicate and grow with everyone.

More exciting, follow me.

————————————————
Copyright statement: This article is the original article of CSDN blogger "Dou Zhe_2013", following the CC 4.0 BY-SA copyright agreement, please attach the original source link for reprinting and this statement.
Original link: https://blog.csdn.net/w1014074794/article/details/106445145

Guess you like

Origin blog.csdn.net/qq_22905801/article/details/129800023