10
头图
Like it first, then watch it, develop a good habit

The packaging plug-in of Spring Boot is very cool to use, directly tying the source code and all dependencies into a Jar package can also run java -jar So what if it is not a Spring Boot project and you want to make an executable Jar package?

Don't panic, Maven is a veteran build tool, it's not easy to get this done!

Here are some other Maven plug-ins, you can also directly package the Maven project into an executable Jar package (uber jar/executable jar), and it has more powerful functions and richer application scenarios!

For the origin of the name of this uber jar/executable jar, please refer to my previous article "Executable Jar/Uber Jar/Shade Jar/Shadow Jar/Fat Jar What is it? 》

maven-dependency-plugin

maven-dependency-plugin is a built-in plugin of Maven. As you can see from the name, its function is to handle dependencies. There are many goals built in, and the functions are very complete:

  • dependency:copydependency:copy-dependencies
  • dependency:unpack
  • dependency:unpack-dependencies
  • dependency:resolve
  • dependency:sources
  • dependency:resolve-plugins
  • dependency:go-offline
  • dependency:purge-local-repository
  • dependency:analyze
  • dependency:analyze-dep-mgt
  • dependency:analyze-report
  • dependency:tree
  • dependency:build-classpath
  • dependency:list-repositories
  • dependency:get

By unpack-dependencies the target of decompress the dependent package/source code , an all-in-one packaging method can be completed:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>

    <execution>
      <id>unpack-dependencies</id>
      <!-- 绑定到 prepare-package 阶段 -->
      <phase>prepare-package</phase>
      <goals>
        <goal>unpack-dependencies</goal>
      </goals>
      <configuration>
        <includeScope>runtime</includeScope>
        <outputDirectory>${project.build.outputDirectory}</outputDirectory>
      </configuration>
    </execution>
  </executions>
</plugin>

This unpack method will "decompress" all dependent packages (internal module dependencies and external module dependencies), which means that the code (class) of the dependent packages will be copied to the outputDirectory directory, which is similar to a merge operation, and the result is like this:
image.png
Then assign a main-class to Jar so that it can be executed directly:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>
          com.github.kongwu.mavenbuild.BuildExample
        </mainClass>
      </manifest>
    </archive>
  </configuration>
</plugin>

of course! This plug-in can do more than just this kind of things... Just look at the above commands and you will know that it has many functions, and only one of its small functions is introduced here.

maven-shade-plugin

maven-shade-plugin is also a built-in plug-in of Maven, you can also directly type an executable Jar. It has the same effect as the dependency plug-in. It is also a "decompression" mode. Put all the classes of the dependent packages together, and configure a transformer and mainClass:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <shadedArtifactAttached>true</shadedArtifactAttached>
        <transformers>
          <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>com.github.kongwu.mavenbuild.BuildExample</mainClass>
          </transformer>
        </transformers>
      </configuration>
    </execution>
  </executions>
</plugin>

The default jar file after the build is: ${artifactId}-${version}-shaded.jar , if you don’t like it, you can also modify the output jar file <outputFile>

plug-in lies in the shade, and this "decompression" is only the basic function.

Do you think the name of this plugin is strange, what does shade

The shade machine turns into shadows and masks. Shade jar refers to packaging the jar package and its dependent packages into a jar file, and provides the function of shade "masking/renaming" some dependent packages

shade a detailed explanation of 060d1362169899, please refer to my other article "Shade Jar/Shadow Jar Explanation"

maven-assembly-plugin

The last maven-assembly-plugin plug-in, which is the strongest build plugin , although it has only one useful goal, but the function is really very powerful:

  1. Detailed construction rules can be configured through a separate description file
  2. Include or exclude a module/directory/file
  3. Support maven filter
  4. One set of code to build multiple bin packages with different configurations at the same time
  5. Different build package formats, such as jar/zip/tar/gz, etc.
  6. ……

such as Zookeeper/Nacos/Arthas/Jenkins, or the recently popular pulsar and other software that needs to run independently, many of them are built with this plug-in

First look at a simple scenario of it, and build an executable Jar package:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
      <configuration>
        <archive>
          <manifest>
            <mainClass>
              com.github.kongwu.mavenbuild.BuildExample
            </mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </execution>
  </executions>
</plugin>

The effect is the same as the above two plug-ins, both are "decompression" methods, the default built file is ${artifactId}-${version}-jar-with-dependencies.jar

With such a powerful plug-in, it is a bit too wasteful to build an uber jar with it. If it is just a simple uber jar scenario, the first two methods are enough.

Therefore, this plug-in is more suitable for complex construction requirements. The simple uber jar scene is a little wasteful of using this Gatling-level tool...

Let's take a look at the usage in Nacos:
image.png
In the source code of Nacos, a distribution module is separately used for construction. With the assembly plug-in + profile function, you can easily build bin packages for various environments:

<!-- nacos distribution/pom.xml-->

<profile>
  <id>release-nacos</id>
  <dependencies>
    <dependency>
      <groupId>${project.groupId}</groupId>
      <artifactId>nacos-console</artifactId>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptors>
            <descriptor>release-nacos.xml</descriptor>
          </descriptors>
          <tarLongFileMode>posix</tarLongFileMode>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id>
            <phase>install</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
    <finalName>nacos</finalName>
  </build>
</profile>

 <profile>
   <id>release-core</id>
   <dependencies>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>nacos-core</artifactId>
     </dependency>
   </dependencies>
   <build>
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-assembly-plugin</artifactId>
         <executions>
           <execution>
             <id>release-core</id>
             <goals>
               <goal>single</goal>
             </goals>
             <phase>package</phase>
             <configuration>
               <descriptors>
                 <descriptor>release-core.xml</descriptor>
               </descriptors>
               <appendAssemblyId>false</appendAssemblyId>
             </configuration>
           </execution>
         </executions>
       </plugin>
     </plugins>
     <finalName>nacos-core</finalName>
   </build>
</profile>

Nacos is a relatively "mainstream" method of construction. If you have a need to build a standalone package someday, I believe you will use this method too.

to sum up

The complete code is placed at https://github.com/kongwu-/maven-build-examples/blob/master/pom.xml , interested friends can pull it down and try

Well, after introducing the gameplay of these plug-ins to build uber-jar, let's make a comparison:

dependencyshadeassembly
advantageThe goals are rich, in addition to unpack, there are many other functions, such as cleaning/viewing the dependency tree, etc.It is specially designed for uber-jar and supports the shade function. If there is a need for relocation, you can only choose itThe strongest function, the configuration is very flexible, but there is no shade function
DisadvantageAfter all, it's just a plug-in that handles dependencies, and its function in terms of construction is relatively weak.Under complex construction requirements, the functions will be somewhat insufficientThere is no shade function, and the configuration is more complicated
Application scenarioSuitable for simple uber-jar functionsMost suitable for the construction of uber-jar, it is perfect with the shade functionSuitable for construction in complex scenarios, not only uber jar

The three plug-ins introduced in this article are different from Spring Boot in the mechanism of uber jar

The Spring Boot build plug-in will put the dependent Jar package in uber jar , which is a "jars-in-a-jar" way, through its custom ClassLoader to load the Jar package in the Jar package; and the above introduced Several plug-ins do not interfere with mainClass and ClassLoader, and cannot load the Jar package in the Jar package, so they all use the "decompression" method.

Note that Spring Boot's build plug-in can not only be used in Spring Boot projects. Its core function is still construction, just replace the startup class with Spring Boot, and then load it through its custom ClassLoader.

Therefore, using spring-boot-maven-plugin to package some non-Spring (Boot) projects into a uber jar is no problem at all, just match the JDK and Maven versions.

reference

For the detailed functions of the above plugins, you can refer to the official documentation of the following plugins. The Maven documentation is more detailed:

Free side dishes

Attached is a Maven default life cycle diagram redrawn by myself, which is quite clear, indicating the different goals of different plugins corresponding to each phase, and save it if necessary (the original image is slightly larger, click to view the larger image)

maven_lifecycle (5) (1).png

Originality is not easy, unauthorized reprinting is prohibited. If my article is helpful to you, please like/favorite/follow to encourage and support it ❤❤❤❤❤❤

空无
3.3k 声望4.3k 粉丝

坚持原创,专注分享 JAVA、网络、IO、JVM、GC 等技术干货