First thumb up and then watch, form a good habit

Spring Boot packaging plug-in with a very cool bar, directly into the source code and all dependencies into a JAR package can also run directly Java – JAR. What if you are not a Spring Boot project and want to make an executable JAR?

Don’t panic, Maven is an old build tool, it’s not easy to do this!

Here are some other Maven plugins that can also directly package a Maven project into an Uber Jar/Executable Jar, but with even more functionality and application scenarios!

For the name of this Uber Jar/ Executable Jar, please refer to my previous post, Executable Jar/Uber Jar/Shade Jar/Shadow Jar/Fat Jar.

maven-dependency-plugin

Maven -dependency-plugin is a built-in plugin to Maven that handles dependencies, as the name suggests. There are many built-in goals with complete functions:

  • 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

To achieve an all-in-one package, unpack dependent packages/source code with the unpack-dependencies target:

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>unpack-dependencies</id> <! - bound to prepare - package stage - - > < 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 “unpacks” all dependent packages (internal and external module dependencies), that is, copies all dependent packages (classes) into the OutputDirectory directory, similar to a merge operation, and the result looks like this:



Add a main-class to the Jar and make it executable:

<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 plugin does more than just that… Take a look at the above command, it has a lot of functions, here is only a small feature of it.

maven-shade-plugin

The maven-shade-plugin is one of the plugins built into Maven. It can also be printed directly into an executable Jar. Just like with the Dependency plugin, this is a “unzip” pattern, with all classes of dependent packages grouped together. A Transformer with a mainClass will do the trick:

<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>

${artifactId}-${version}-shaded.jar. If you don’t like it, you can use

to modify the output JAR file

The essence of this plugin is shade, and this “unzip” is just the basic function.

Have you ever thought this plugin name is very strange, shade is what mean?

A shade jar is used to package a JAR package and its dependencies into a JAR file, and to provide shade to “shade/rename” certain dependent packages

For a detailed explanation of Shade, see my other article, Shade Jar/Shadow Jar Interpretation

maven-assembly-plugin

The maven-assembly-plugin is one of the most powerful build plugins in Maven. It has only one goal, but it’s really, really powerful:

  1. Detailed build rules can be configured through a separate description file
  2. Include or exclude a module/directory/file
  3. Support for maven filter
  4. A set of code that builds multiple bin packages with different configurations simultaneously
  5. Different build package formats, such as jar/zip/tar/gz, etc

Such as a Zookeeper/Nacos/Arthas/Jenkins, or more fire pulsar recently need independent operation of the software, many of them are built by this plugin

Let’s start with a simple scenario to 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>

${artifactId}-${version} -jar-with-Dependents.jar

It’s a waste of time to build an Uber Jar with such a powerful plugin. If it’s just a simple Uber Jar scenario, the first two methods are sufficient.

So the plugin is more suited to complex build needs, and the simple Uber Jar scenario is a bit wasteful with a Gatling-level tool like this…

Here’s how to use it in NaCos:



In the source code of Nacos, there is a separate distribution module for building. With the help of the Assembly plugin + profile function, it is very convenient to build the bin package of 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 the “mainstream” way to build, and if you ever need to build a standalone runtime package, you’ll probably use it.

conclusion

The complete code on https://github.com/kongwu-/maven-build-examples/blob/master/pom.xml, interested friends can try

All right, so now let’s compare how these plugins build Uber-Jar:

dependency shade assembly
advantages Goals are rich. It can do a lot of things other than unpack, such as cleaning up and looking at dependency trees Designed for Uber-Jar, it supports SHADE function, which is the only option if you need to relocate The strongest function, configuration is very flexible, but there is no shade function
disadvantages It is, after all, a plug-in that handles dependencies and is weak on the build side With complex build requirements, the functionality can be somewhat inadequate There is no shade function, and the configuration is more complex
Application scenarios Suitable for simple Uber-Jar features The most suitable for Uber-Jar construction, with Shade function is simply perfect Suitable for building in complex scenarios, not just Uber Jars

Here are three plugins that are different from Spring Boot in building Uber Jars:

The Spring Boot build plugin will load the dependent JAR in the Uber JAR, which is a “JARS-IN-A-JAR” method, using its custom ClassLoader to load the JAR within the JAR. However, the plugins described above do not interfere with the mainClass and ClassLoader, and cannot load the JAR within the JAR package, so they all “unpack” the way.

Note that the Spring Boot build plug-in is not only available in the Spring Boot project. Its core function is still build, but it replaces the Boot class with Spring Boot’s, and then loads it through its custom ClassLoader.

So, it’s perfectly fine to package some non-spring (boot) projects into an Uber JAR using the spring-boot-maven-plugin, as long as the JDK and Maven versions match.

reference

For details of the above plugins, please refer to the official documentation of the plugins below. Maven documentation is relatively detailed:

  • https://juejin.cn/post/6941618160386703390
  • http://maven.apache.org/plugins/maven-dependency-plugin/index.html
  • http://maven.apache.org/plugins/maven-jar-plugin/
  • http://maven.apache.org/plugins/maven-shade-plugin/
  • http://maven.apache.org/plugins/maven-assembly-plugin/index.html
  • https://github.com/alibaba/nacos

Free side dishes

Attach a life cycle diagram of Maven Default redrawn by myself, which is relatively clear, indicating different goals of different plugins corresponding to each phase. If necessary, save it by yourself (the original diagram is slightly larger, click to view a larger one).

Original is not easy, prohibit unauthorized reprint. If my article is helpful to you, please feel free to support me at thumb up/bookmark/follow me