[SpringBoot] Jar slimming practice under iterative release

background

With Spring Bootthe popularity of Spring Boot, more and more developers choose to use Spring Boot to publish web applications. Different from traditional War package release, Spring Bootthe entire project is packaged into a runnable Jar package (the so-called Flat Jar), ​​resulting in a very large Jar package (usually 40M+). As is often the case with iterative releases these days, uploading such a huge file every time will waste a lot of time.

Let’s take a small project as an example to briefly describe the weight loss program used by my brother. Of course, if it is released on an intranet or the broadband you are using is extremely powerful, slimming down will not make much sense.

practice

Project Description

Create a new exercise project with the following structure:
Write picture description here

  1. ht-cdnStatic resources are stored (such as third-party js, css, images, etc.)
  2. ht-domainData entity definition in project
  3. ht-repositoryData layer interface and implementation
  4. ht-serviceBusiness logic interface and implementation
  5. ht-ui-webWeb management

Which ht-ui-webrelies on ht-domain, ht-repository, ht-serviceand implements a simple one GetMapping.

Then package the project, the entire jar package is 24M like this
Write picture description here

weight loss preparation

First we need to have a preliminary understanding of the Jar package. Its internal structure is as follows

example.jar
 |
 +-META-INF
 |  +-MANIFEST.MF
 +-org
 |  +-springframework
 |     +-boot
 |        +-loader
 |           +-<spring boot loader classes>
 +-BOOT-INF
    +-classes
    |  +-mycompany
    |     +-project
    |        +-YourClasses.class
    +-lib
       +-dependency1.jar
       +-dependency2.jar

When running this Jar, by default BOOT-INF/classes, the class is loaded from BOOT-INF/liband the dependent Jar packages are loaded from. If you want to add external dependent Jar, you can LOADER_PATHdo it by setting environment variables.

In this way, we can confirm our ideas:
1. Extract those unchanged dependent Jar packages (such as spring dependencies, database drivers, etc., which will not be updated without upgrading the version) from the Flat Jar Leave to a separate directory, such as libs
2. When starting Jar, set to LOADER_PATHuse the libs from the previous step

In this way, the size of our final packaged jar package is greatly reduced, and we only need to update this streamlined version of Jar after each iteration.

Specific steps

slim down while packing

Usually we use it spring-boot-maven-pluginfor packaging. After reading the documentation, we found that the plug-in can be configured to ignore specific dependencies when packaging. The documentation is in spring-boot-maven-plugin .

First, back up the original dependencies: compile and package them into a Flat Jar, then unzip all the jar files BOOT-INF/libexcept ht-*the related ones, and save them to libsthe directory.

Then modify pom.xmlthe configuration as follows

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <layout>ZIP</layout>
                <!--去除在生产环境中不变的依赖-->
                <excludeGroupIds>
                    org.springframework.boot,
                    org.springframework,
                    org.springframework.data,
                    org.mongodb,
                    com.github.0604hx,
                    com.fasterxml.jackson.core,
                    commons-beanutils,
                    commons-codec,
                    org.apache.commons,
                    org.apache.tomcat.embed,
                    org.hibernate,
                    org.slf4j,
                    com.jayway,
                    org.jboss,
                    com.alibaba,
                    com.fasterxml,
                    commons-collections,
                    ch.qos.logback,
                    org.scala-lang,
                    org.yaml,
                    org.jboss.logging,
                    javax.validation,
                    nz.net.ultraq.thymeleaf,
                    org.thymeleaf,
                    ognl,
                    org.unbescape,
                    org.javassist
                </excludeGroupIds>
            </configuration>
        </plugin>
    </plugins>
</build>

At this time, the packaged version ht-ui-web.jaris only 117kb.
Write picture description here

htThere are only relevant jars under BOOT-INF/lib
Write picture description here

But since there are no other dependencies, ht-ui-web.jarit cannot run as scheduled.

java -jar ht-ui-web-1.0.jar
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
        at org.springframework.boot.loader.PropertiesLauncher.main(PropertiesLauncher.java:521)
Caused by: java.lang.NoClassDefFoundError: org/springframework/boot/SpringApplication
        at com.nerve.huotong.web.WebApplication.main(WebApplication.java:21)
        ... 8 more
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:94)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 9 more

At this point we need to set up LOADER_PATHas follows

java -Dloader.path="libs/" -jar ht-ui-web.jar

You can see the familiar Spring Boot startup information.

continue to lose weight

As mentioned in the project structure introduction above ht-cdn, I put all the libraries used in the front end here. Then start a Web Application separately. If other projects need to use static resources, just use them directly.

Another way is to resources/publicthrow it directly to libsthe bottom (that is, put it together with the jar package stripped out in the previous step). The structure is as follows:

Write picture description here

This is also possible (but be careful not to have the same name as the static resources you wrote in the real project).

Conclusion

After the above slimming down, the Jar package developed in each iteration appears much slimmer.


digression

banner.txt in Spring Boot

Banner is the Easter egg information printed on the console when the spring boot application starts. The default is like this


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.4.3.RELEASE)

If you want to modify this text, just create a new one resourcesbelow banner.txt. You can customize the banner here: http://patorjk.com/software/taag

Guess you like

Origin blog.csdn.net/ssrc0604hx/article/details/54175027