All JAR packages of JAVA project are packaged, run and deployed as a one-stop solution

1, Scene description

  • The modular management of parent-child project can solve most scenarios and problems of module version and dependency between modules

  • Using spring boot plug-in for project packaging and deployment can solve 90% of the problems of continuous project integration and deployment

  • In the process of project development, with the continuous complexity of business and the continuous increase of modules, one packaging and deployment method may be difficult to meet. Therefore, we need to master the packaging and deployment methods of different projects to deal with changing scenarios and requirements

2, Packaging method

Scenario 1: packaging and deployment of conventional MAVEN scattered projects
  1. Create a new Maven parent-child project (this mode is generally a scene of a separate and scattered module. Here, for the convenience of demonstration, create a parent-child project)

    example
        - example-common
            - CommonUtil.java
            - pom.xml
        - example-service
            - ServiceApplication.java
            - pom.xml
    - pom.xml        
    

    P.S

    • Example is the parent project of example common and example service

    • Example service depends on the example common module

    • No Maven packaged plug-ins are added to the pom files of all modules

    • Parent project pom

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <!-- Module coordinate information GAV -->
          <groupId>com.rambo</groupId>
          <artifactId>example</artifactId>
          <packaging>pom</packaging>
          <version>V1.0.0.1</version>
      
          <name>${project.artifactId}</name>
          <description>Parent child module example project - Basic Parent project</description>
      
          <!-- Sub module list -->
          <modules>
              <module>example-common</module>
              <module>example-service</module>
          </modules>
      
          <properties>
              <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
              <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
              <java.version>1.8</java.version>
              <maven.compiler.source>1.8</maven.compiler.source>
              <maven.compiler.target>1.8</maven.compiler.target>
          </properties>
      
          <build>
              <finalName>${project.artifactId}</finalName>
          </build>
      </project>
      
    • Example common module pom

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <!-- Parent project GAV -->
          <parent>
              <artifactId>example</artifactId>
              <groupId>com.rambo</groupId>
              <version>V1.0.0.1</version>
          </parent>
      
          <!-- Module of the project AV -->
          <artifactId>example-common</artifactId>
          <version>V1.0.0.1</version>
          <packaging>jar</packaging>
      
          <name>${project.artifactId}</name>
          <description>Example general module without startup class - general tools</description>
      </project>
      
    • Example service module pom

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <!-- Parent project GAV -->
          <parent>
              <artifactId>example</artifactId>
              <groupId>com.rambo</groupId>
             <version>V1.0.0.1</version>
          </parent>
      
          <!-- Module of the project AV -->
          <artifactId>example-service</artifactId>
          <version>V1.0.0.1</version>
          <packaging>jar</packaging>
      
          <name>example-service</name>
          <description>Sample service module with startup class -- sample service</description>
      
          <dependencies>
              <!-- Example common tool module -->
              <dependency>
                  <groupId>com.rambo</groupId>
                  <artifactId>example-common</artifactId>
                  <version>V1.0.0.1</version>
              </dependency>
          </dependencies>
      </project>
      
  2. The example codes of example common and example service are as follows

    • Example common module

      public class CommonUtil {
          public static void info() {
              System.out.println("This is info from CommonUtil.class");
          }
      }
      
    • Example service module

      public class ServiceApplication {
          public static void main(String[] args) {
              CommonUtil.info();
          }
      }
      
  3. Execute Maven packaging command at the same level of pom file of parent project

    • Packaging command

      mvn -package
      
    • Manifest of two modules MF file contents are as follows

      Manifest-Version: 1.0
      Archiver-Version: Plexus Archiver
      Built-By: rambo
      Created-By: Apache Maven 3.6.3
      Build-Jdk: 1.8.0_271
      
  4. Put the jar package typed in the previous step in the same directory, and execute the following command to start the program

    • Execute command

      java -classpath example-common.jar:example-service.jar com.rambo.service.ServiceApplication
      
    • Operation results

       ~/WorkSpace/example/example-service/target/ java -classpath example-common.jar:example-service.jar com.rambo.service.ServiceApplication 
      This is info from CommonUtil.class
       ~/WorkSpace/example/example-service/target/ 
      
    • Command interpretation

      • Syntax: Java - classpath XXX jar:yyy. jar:zzz. jar mainClassName

      • java -classpath: fixed part

      • xxx.jar:yyy.jar:zzz.jar: multiple dependent jars are separated by:

      • mainClassName: the class name of the class where the main method is located

Scenario 2: conventional MAVEN centralized project packaging and deployment
  1. The example project is also a parent-child project created in step 1

  2. The reason for this is the use scenario of centralized project packaging: after the project is created, modules will not be added or deleted at will (the implication is that the creation and dependency of modules A and B are fixed)

  3. Add the following plug-ins to the example service module pom file

    <build>
        <plugins>
            <!-- use maven-jar-plugin Plug in customization MANIFEST.MF file -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <finalName>${project.artifactId}</finalName>
                    <archive>
                        <manifest>
                            <!-- set up MANIFEST.MF Main startup class in file -->
                            <mainClass>com.rambo.service.ServiceApplication</mainClass>
                            <!-- Will need to rely on JAR Packages, adding to MANIFEST.MF In the file -->
                            <addClasspath>true</addClasspath>
                            <!-- rely on JAR Folder prefix read by package -->
                            <classpathPrefix>lib</classpathPrefix>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
    
  4. Execute Maven packaging command at the same level of pom file of parent project

    • Packaging command

      mvn -package
      
    • Example common module manifest MF file contents are as follows

      Manifest-Version: 1.0
      Archiver-Version: Plexus Archiver
      Built-By: rambo
      Created-By: Apache Maven 3.6.3
      Build-Jdk: 1.8.0_271
      
    • Example service module manifest MF file contents are as follows

      Manifest-Version: 1.0
      Archiver-Version: Plexus Archiver
      Built-By: rambo
      Class-Path: lib/example-common-V1.0.0.1.jar
      Created-By: Apache Maven 3.6.3
      Build-Jdk: 1.8.0_271
      Main-Class: com.rambo.service.ServiceApplication
      
  5. Put the dependent jar package typed in the previous step in the lib folder of the same directory as example service, and execute the following command to start the program

     ~/WorkSpace/example/example-service/target/ cp ../../example-common/target/example-common.jar .
     ~/WorkSpace/example/example-service/target/ mv example-common.jar example-common-V1.0.0.1.jar
     ~/WorkSpace/example/example-service/target/ mkdir lib                                        
     ~/WorkSpace/example/example-service/target/ mv example-common-V1.0.0.1.jar lib               
     ~/WorkSpace/example/example-service/target/ java -jar example-service.jar
    This is info from CommonUtil.class
     ~/WorkSpace/example/example-service/target/ 
    
Scenario 3: packaged deployment with spring boot plug-in
  1. In the first two packaging deployment methods, the main program and dependent jars are generally scattered and separated, which will be troublesome in cloud environment deployment. Many dependent packages need to be uploaded (or uniformly compressed and decompressed on the ECS). Single machine deployment is good, and distributed deployment will be very tired

  2. To solve the above problems, we can type fat jar to solve them

  3. In the example service module with startup class, replace the Maven jar plugin plug-in with the spring boot Maven packaged plug-in

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.5.2</version>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    
  4. Execute Maven packaging command at the same level of pom file of parent project

    • Packaging command

      mvn -package
      
    • Example common module manifest MF file contents are as follows

      Manifest-Version: 1.0
      Archiver-Version: Plexus Archiver
      Built-By: rambo
      Created-By: Apache Maven 3.6.3
      Build-Jdk: 1.8.0_271
      
    • Example service module manifest MF file contents are as follows

      Manifest-Version: 1.0
      Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
      Archiver-Version: Plexus Archiver
      Built-By: rambo
      Spring-Boot-Layers-Index: BOOT-INF/layers.idx
      Start-Class: com.rambo.service.ServiceApplication
      Spring-Boot-Classes: BOOT-INF/classes/
      Spring-Boot-Lib: BOOT-INF/lib/
      Spring-Boot-Version: 2.5.2
      Created-By: Apache Maven 3.6.3
      Build-Jdk: 1.8.0_271
      Main-Class: org.springframework.boot.loader.JarLauncher
      
  5. Through this packaging method, the JAR of example service can be run directly, and an example service can be seen in its peer directory JAR. Original file

     ~/WorkSpace/example/example-service/target/ pwd                                
    /Users/rambo/WorkSpace/example/example-service/target
     ~/WorkSpace/example/example-service/target/ java -jar example-service.jar      
    This is info from CommonUtil.class
     ~/WorkSpace/example/example-service/target/ 
    

    P.S

    Why can I run it directly? Because the JAR package printed by spring boot Maven plug-in is a fat jar, which contains all the dependent JAR packages, and then through manifest MF's JarLauncher starts the application

  6. About example service jar. Original and example service Jar understanding

    • see. Dependency of original file

       ~/WorkSpace/example/example-service/target/ jar tf example-service.jar.original
      META-INF/
      META-INF/MANIFEST.MF
      com/
      com/rambo/
      com/rambo/service/
      application.yml
      com/rambo/service/ServiceApplication.class
      META-INF/maven/
      META-INF/maven/com.rambo/
      META-INF/maven/com.rambo/example-service/
      META-INF/maven/com.rambo/example-service/pom.xml
      META-INF/maven/com.rambo/example-service/pom.properties
       ~/WorkSpace/example/example-service/target/ 
      
    • View jar dependencies

       ~/WorkSpace/example/example-service/target/ jar tf example-service.jar         
      META-INF/
      META-INF/MANIFEST.MF
      org/
      org/springframework/
      org/springframework/boot/
      org/springframework/boot/loader/
      org/springframework/boot/loader/ClassPathIndexFile.class
      org/springframework/boot/loader/ExecutableArchiveLauncher.class
      org/springframework/boot/loader/JarLauncher.class
      org/springframework/boot/loader/LaunchedURLClassLoader$DefinePackageCallType.class
      org/springframework/boot/loader/LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class
      org/springframework/boot/loader/LaunchedURLClassLoader.class
      org/springframework/boot/loader/Launcher.class
      org/springframework/boot/loader/MainMethodRunner.class
      org/springframework/boot/loader/PropertiesLauncher$1.class
      org/springframework/boot/loader/PropertiesLauncher$ArchiveEntryFilter.class
      org/springframework/boot/loader/PropertiesLauncher$ClassPathArchives.class
      org/springframework/boot/loader/PropertiesLauncher$PrefixMatchingArchiveFilter.class
      org/springframework/boot/loader/PropertiesLauncher.class
      org/springframework/boot/loader/WarLauncher.class
      org/springframework/boot/loader/archive/
      org/springframework/boot/loader/archive/Archive$Entry.class
      org/springframework/boot/loader/archive/Archive$EntryFilter.class
      org/springframework/boot/loader/archive/Archive.class
      org/springframework/boot/loader/archive/ExplodedArchive$AbstractIterator.class
      org/springframework/boot/loader/archive/ExplodedArchive$ArchiveIterator.class
      org/springframework/boot/loader/archive/ExplodedArchive$EntryIterator.class
      org/springframework/boot/loader/archive/ExplodedArchive$FileEntry.class
      org/springframework/boot/loader/archive/ExplodedArchive$SimpleJarFileArchive.class
      org/springframework/boot/loader/archive/ExplodedArchive.class
      org/springframework/boot/loader/archive/JarFileArchive$AbstractIterator.class
      org/springframework/boot/loader/archive/JarFileArchive$EntryIterator.class
      org/springframework/boot/loader/archive/JarFileArchive$JarFileEntry.class
      org/springframework/boot/loader/archive/JarFileArchive$NestedArchiveIterator.class
      org/springframework/boot/loader/archive/JarFileArchive.class
      org/springframework/boot/loader/data/
      org/springframework/boot/loader/data/RandomAccessData.class
      org/springframework/boot/loader/data/RandomAccessDataFile$1.class
      org/springframework/boot/loader/data/RandomAccessDataFile$DataInputStream.class
      org/springframework/boot/loader/data/RandomAccessDataFile$FileAccess.class
      org/springframework/boot/loader/data/RandomAccessDataFile.class
      org/springframework/boot/loader/jar/
      org/springframework/boot/loader/jar/AbstractJarFile$JarFileType.class
      org/springframework/boot/loader/jar/AbstractJarFile.class
      org/springframework/boot/loader/jar/AsciiBytes.class
      org/springframework/boot/loader/jar/Bytes.class
      org/springframework/boot/loader/jar/CentralDirectoryEndRecord$1.class
      org/springframework/boot/loader/jar/CentralDirectoryEndRecord$Zip64End.class
      org/springframework/boot/loader/jar/CentralDirectoryEndRecord$Zip64Locator.class
      org/springframework/boot/loader/jar/CentralDirectoryEndRecord.class
      org/springframework/boot/loader/jar/CentralDirectoryFileHeader.class
      org/springframework/boot/loader/jar/CentralDirectoryParser.class
      org/springframework/boot/loader/jar/CentralDirectoryVisitor.class
      org/springframework/boot/loader/jar/FileHeader.class
      org/springframework/boot/loader/jar/Handler.class
      org/springframework/boot/loader/jar/JarEntry.class
      org/springframework/boot/loader/jar/JarEntryCertification.class
      org/springframework/boot/loader/jar/JarEntryFilter.class
      org/springframework/boot/loader/jar/JarFile$1.class
      org/springframework/boot/loader/jar/JarFile$JarEntryEnumeration.class
      org/springframework/boot/loader/jar/JarFile.class
      org/springframework/boot/loader/jar/JarFileEntries$1.class
      org/springframework/boot/loader/jar/JarFileEntries$EntryIterator.class
      org/springframework/boot/loader/jar/JarFileEntries.class
      org/springframework/boot/loader/jar/JarFileWrapper.class
      org/springframework/boot/loader/jar/JarURLConnection$1.class
      org/springframework/boot/loader/jar/JarURLConnection$JarEntryName.class
      org/springframework/boot/loader/jar/JarURLConnection.class
      org/springframework/boot/loader/jar/StringSequence.class
      org/springframework/boot/loader/jar/ZipInflaterInputStream.class
      org/springframework/boot/loader/jarmode/
      org/springframework/boot/loader/jarmode/JarMode.class
      org/springframework/boot/loader/jarmode/JarModeLauncher.class
      org/springframework/boot/loader/jarmode/TestJarMode.class
      org/springframework/boot/loader/util/
      org/springframework/boot/loader/util/SystemPropertyUtils.class
      BOOT-INF/
      BOOT-INF/classes/
      BOOT-INF/classes/com/
      BOOT-INF/classes/com/rambo/
      BOOT-INF/classes/com/rambo/service/
      BOOT-INF/classes/application.yml
      BOOT-INF/classes/com/rambo/service/ServiceApplication.class
      META-INF/maven/
      META-INF/maven/com.rambo/
      META-INF/maven/com.rambo/example-service/
      META-INF/maven/com.rambo/example-service/pom.xml
      META-INF/maven/com.rambo/example-service/pom.properties
      BOOT-INF/lib/
      BOOT-INF/lib/example-common-V1.0.0.1.jar
      BOOT-INF/lib/lombok-1.18.20.jar
      BOOT-INF/lib/spring-boot-jarmode-layertools-2.5.2.jar
      BOOT-INF/classpath.idx
      BOOT-INF/layers.idx
       ~/WorkSpace/example/example-service/target/ 
      
  7. As can be seen from the above results, in terms of the dependencies packaged by example service, boot-inf / lib / example-common-v1 0.0.1. JAR has been included in the JAR package, so you can directly use Java - JAR example-service JAR can be run directly

  8. About the structure and operation mode of fat jar, please look forward to the next article.

Click here Obtain the sample materials and backup pictures above, and extract the password: 7aaa

Keywords: Java Maven Spring Boot jar

Added by jmcneese on Tue, 18 Jan 2022 11:47:18 +0200