I was asked this question the other day:

“Songgo, why does my Spring Boot project package jars that are dependent on other projects always report class missing errors?”

What is the difference between an executable jar and a regular jar? Today, Songo will talk to you about this problem.

There is a plugin

The default jar package in Spring Boot is called executable JAR. This jar is different from ordinary JAR. Ordinary JAR cannot be executed by the java-jar xxx.jar command. Spring Boot into jar can be executed, but can not be relied on by other applications, even if forced to rely on, also can not obtain the class inside. But executable jars are not unique to Spring Boot; Java projects can be packaged as executable Jars themselves.

The MVN package command is also executed for project packaging, why Spring Boot projects are labeled as executable JARS, while ordinary projects are packaged as unexecutable jars?

The spring-boot-Maven-plugin is the default plug-in configuration for the Spring Boot project. The spring-boot-Maven-plugin has five functions, as can be seen from the plug-in command:

The five functions are:

  • Build-info: Generates the build information file of the project, build-info.properties
  • Repackage: This is the default goal, inmvn packageOnce executed, the command is packaged again to generate the executable JAR, and themvn packageRename the generated JAR to*.origin
  • Run: This can be used to run the Spring Boot application
  • Start: Here it ismvn integration-testStage, carry onSpring BootApplication lifecycle management
  • Stop: Here it ismvn integration-testStage, carry onSpring BootApplication lifecycle management

This feature, by default, is repackage, and other features need to be explicitly configured by the developer.

packaging

What repackage does is to do a little extra when you pack:

  1. First of all,mvn packageCommand to package items into onejarthejarJust a regular onejarCan be relied upon by other projects, but cannot be executed
  2. repackageCommand, packaged for the first stepjarPackage it again and make it executablejarBy taking the first stepjarrename*.originalfile

Here’s an example:

To package any Spring Boot project, you can either execute the MVN package command or directly click package in IDEA, as follows:

After successful packaging, the files in target are as follows:

Jar represents the packaged executable JAR, and the second restful 0.1-snapshot.jar. original represents the jar that was renamed during the packaging process. This is a non-executable JAR, but one that can be relied upon by other projects. By unpacking the two files, we can see the difference between the two.

A comparison of the two jars

After decompressing the executable jar, the directory is as follows:

As you can see, the executable jar contains our own code in boot-INF /classes/ and a meta-INF directory that contains a manifest.mf file. Open the manifest.mf file as follows:

Manifest-version: 1.0 implementation-title: restful implementation-version: 0.0.1-SNAPSHOT start-class: org.javaboy.restful.RestfulApplication Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: Boot-inf /lib/ build-jdk-spec: 1.8 spring-boot-version: 2.1.6.RELEASE Created -by: Maven Archiver 3.4.0 main-class: org.springframework.boot.loader.JarLauncherCopy the code

As you can see, a start-class is defined here, which is the entry Class for the executable JAR. Spring-boot-classes represents where our own code is compiled, and spring-boot-lib represents where the project depends on the JAR.

In other words, if you want to build an executable JAR yourself, you need to configure the meta-INF/manifest.mf file in addition to adding the dependencies.

This is the structure of executable jars, but what about the structure of non-executable jars?

We first remove the default suffix. Original, and then rename the file.

When unzipped, the root of the non-executable jar is our classpath. When unzipped, you can see our code directly. It also has a meta-INF/manifest.mf file, but there is no startup class defined in the file.

Manifest-version: 1.0 implementation-title: restful implementation-version: 0.0.1 -snapshot build-jdK-spec: 1.8 Created-By: Maven Archiver 3.4.0Copy the code

Pay attention to

This cannot execute jar and does not package the project’s dependencies.

From this we can see that the two jars, although both are JAR packages, have completely different internal structures, so one can be executed directly and the other can be relied upon by other projects.

Package two jars at a time

Generally speaking, Spring Boot can be packaged directly as an executable JAR. It is not recommended to rely on Spring Boot as a normal JAR for other projects. If there is such a need, it is recommended to separate the dependent parts into a regular Maven project and reference the Maven project in Spring Boot.

If you must package Spring Boot as a normal JAR to be relied on by other projects, it is technically possible. Add the following configuration to the spring-boot-Maven-plugin:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <classifier>exec</classifier>
            </configuration>
        </plugin>
    </plugins>
</build>
Copy the code

Configuration of the classifier said the name of the executable jar, configuration, after the in the plug-in repackage command, will not give MVN package into the jar rename, so, after packaged jar is as follows:

The first JAR represents a JAR that can be relied upon by other projects, and the second jar represents an executable JAR.

Ok, about the Spring Boot JAR problem, we say so much, if you have any questions, welcome to leave a comment.

Pay attention to the public account [Jiangnan little Rain], focus on Spring Boot+ micro service and front and back end separation and other full stack technology, regular video tutorial sharing, after attention to reply to Java, get Songko for you carefully prepared Java dry goods!