Make the jar package for your SpringBoot project slim

Spring boot is packaged in the default way because it is a full dependent package (also called a fat package), which is not only slow to package, large in size, and slow in transmission. Today, I will teach you how to thin spring boot.

background

Now that the microservice architecture is becoming more and more popular, more than 10 service modules based on spring boot for a project are common. Assuming that a service module is marked as a jar package of 100M, then a full release may need to upload 1G files. When the network condition is good, you may not feel much, but if the code needs to be copied to the intranet for publication, or uploaded to some foreign servers, it will seriously affect the work efficiency.

So, is there any way to make us thin the spring boot jar package?
The answer is yes, when spring boot is packaged through the relevant configuration, only some dependency packages that often change 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 where the lib package is loaded through the command when the project starts. In this way, the jar package we typed out is less than a few megabytes at most, which greatly reduces the size of the spring boot project jar package and improves the efficiency of publishing and launching.

Supplement:
fat jar: fat jar, the jar package that is typed out contains all dependent packages.
The advantage is that it can be run directly without adding other commands. The disadvantage is that it is too large and difficult to transmit.

**thin jar: ** means thin package. The jar package that is typed out only contains some frequently changed dependency packages, generally public modules in the project or some API interface dependent modules.
The advantage is that it is small in size, which is conducive to improving the efficiency of project release; the
disadvantage is that there may be security risks in relying on external packages. If the maven dependency of the project changes frequently, it is 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>

Description:

layout
used to configure executable jar package type Main-Class, there must be set to the ZIP, so that a jar hit the Main-Class is PropertiesLauncher.

includes
will need to keep the jar package, according to groupId and artifactId (note that both are required) include in.
Nothing stands for non-existent dependent packages, which means that
common service modules are imported without any dependent packages .

2. Execute maven packaging.
First execute mvn clean, and then execute mvn package
Insert picture description here
to copy the package that has been printed in the target directory to the D:\web directory, and rename it to tax-ws-thin-zip.jar.

Check the MANIFEST.MF file in the META-INF directory in tax-ws-thin-zip.jar through the compression tool: it is
Insert picture description here
found that the value of Main-Class has indeed changed to PropertiesLauncher, indicating that our configuration is successful.
(As for why the Main-Class must be configured as PropertiesLauncher, I will introduce it later)

3. Compare the volume of FatJar and ThinJar: It
Insert picture description here
can be found that the volume of the thin package tax-ws-thin.jar is much smaller than the volume of the fat package.

4. Copy the lib package from the fatJar package to the D:\web directory
Insert picture description here
5. Start the jar package by command

D:\web>java -Dloader.path="D:\web\lib"  -jar tax-ws-thin.jar

Configure the loading path of the external dependent package through the startup parameter loader.path.

The successful start of the project indicates that the outsourced dependency package we configured has been loaded into effect.

Principle Exploration

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

The following is taken from the official spring boot website: The
org.springframework.boot.loader.Launcher class is a special boot program class that serves as the main entry point for the executable jar. It is the actual Main-Class in the jar file, used to set the appropriate URLClassLoader and finally call 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 the directory (rather than files explicitly in the classpath). For JarLauncher and WarLauncher, the nesting path is fixed. JarLauncher is located in BOOT-INF/lib/, while WarLauncher is located in WEB-INF/lib/ and WEB-INF/lib-provided/. If needed, additional jars can be added at these locations. By default, PropertiesLauncher looks in BOOT-INF/lib/ in your application archive. You can add other locations by setting an environment variable called LOADER_PATH or loader.path in loader.properties (this is a comma-separated list of directories, archive files, or directories in archive files).
————————————————

In other words, 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 be accessed through the environment variable loader.path Specify where to load resources.
Insert picture description here

Layout attribute value description:

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

WAR, that is, the usual executable war, the required servlet container dependency is located in
Main-Class: org.springframework.boot.loader.warLauncher

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

PropertiesLauncher property configuration

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

Key purpose
loader.path lib package loading path
loader.home Used to resolve relative paths in loader.path. For example, given loader.path = lib, ${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 following example /opt/app. It defaults to ${user.dir}.
loader.args The default parameters of the main method (separated by spaces).
loader.main The name of the main class to start (for example, com.app.Application)
loader.config.name The path of the properties file (for example, classpath:loader.properties). The default is loader.properties.
loader.system Boolean flag indicating that all attributes should be added to system properties. The default is false.

For more information, you can view the documentation on the spring boot executable jar package on the official website: The Executable Jar Format

Trap correction

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

D:\web>java -Djava.ext.dirs="D:\web\lib"  -jar tax-ws-thin.jar

Principle analysis:
-Djava.ext.dirs will override the ext setting of Java itself. The directory specified by java.ext.dirs is loaded by the ExtClassLoader loader. If your program does not specify this system property, the loader will load $JAVA_HOME/ by default All jar files in the jre/lib/ext directory. But if you manually specify the system properties and forget to add the $JAVA_HOME/jre/lib/ext path, ExtClassLoader will not load the jar files under $JAVA_HOME/lib/ext, which means you will lose some functions. For example, the implementation of the encryption and decryption algorithm that comes with java.

Therefore, by this way of writing, directly forcibly modifying the loading path of the java default extended class loader can easily cause some problems. It is best not to use it casually.

Cannot find the Oracle driver package

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

Extension: Parental delegation mechanism

Expansion here involves the Java parent delegation loading mechanism.
Insert picture description here

1. BootStrapClassLoader: Start the class loader. The ClassLoader is created at startup and written in the JVM kernel. It is not a bytecode file, but a binary code written in c++, so the developer cannot get the startup The reference of the class cannot be operated by reference. This loader is to load 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 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 first load the class by itself, 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 delegates the class loading request to BootStrapClassLoader to complete.

3. If BottStrapClassLoader fails to load, EXTClassLoader will be used to try to load.

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

to sum up

1. Why do you want to make the executable jar package of the spring boot project slim
? 2. The three spring boot starters explain
3. How to configure the PropertiesLauncher starter to realize the loading of external dependency packages
4. Point out that by specifying -Djava.ext.dirs Parameter implementation of the problem of external dependency package loading
5. The extension explains the Java parent delegation loading mechanism
6. The solution to the problem that the external dependency package cannot be loaded with the Oracle driver package

At last

Thank you for your recent support. Although you say that learning is your own business, it is really encouraging to see your likes, comments and attention. Thank you all.
I will continue to work hard to share more high-quality technical articles and hope to communicate and grow with you.

More exciting, follow me.
Legend: Follow the old man to learn java

Guess you like

Origin blog.csdn.net/w1014074794/article/details/106445145