Automate Spring Boot Packaging and Deployment with Maven and a Custom Shell Tool

This guide explains how to configure Maven profiles and the assembly plugin to create a zip package for a Spring Boot application, then use a reusable shell script to unzip, start, stop, and restart the service on Linux, streamlining deployment across multiple environments.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
Automate Spring Boot Packaging and Deployment with Maven and a Custom Shell Tool

This article shares a complete workflow for packaging a Spring Boot application and deploying it with a custom shell script, focusing on a reusable launch tool that simplifies the process.

Key Topics

Using Maven profiles to specify different environment configurations.

Creating a deployment zip with maven-assembly-plugin and maven-jar-plugin.

Introducing the shenniu_publish.sh script for automated unzip, start, stop, and restart operations on Linux.

Maven Profiles Configuration

<profiles>
  <profile>
    <id>node</id>
    <properties>
      <!-- Parameters passed to the script -->
      <activeProfile>node</activeProfile>
      <package-name>${scripts_packageName}</package-name>
      <boot-main>${scripts_bootMain}</boot-main>
    </properties>
    <activation>
      <activeByDefault>true</activeByDefault>
    </activation>
  </profile>
  <profile>
    <id>node1</id>
    <properties>
      <activeProfile>node1</activeProfile>
      <package-name>${scripts_packageName}</package-name>
      <boot-main>${scripts_bootMain}</boot-main>
    </properties>
  </profile>
  <profile>
    <id>node2</id>
    <properties>
      <activeProfile>node2</activeProfile>
      <package-name>${scripts_packageName}</package-name>
      <boot-main>${scripts_bootMain}</boot-main>
    </properties>
  </profile>
</profiles>

The id element selects the directory containing the configuration files for a specific environment. The properties node defines variables ( package-name, boot-main) that can be referenced in other configuration files or the shell script. activeByDefault marks the default profile.

Maven Assembly Plugin for Zip Packaging

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <version>2.6</version>
  <configuration>
    <archive>
      <addMavenDescriptor>false</addMavenDescriptor>
      <manifest>
        <addClasspath>true</addClasspath>
        <classpathPrefix>lib/</classpathPrefix>
        <mainClass>${scripts_bootMain}</mainClass>
      </manifest>
    </archive>
    <excludes>
      <exclude>**/*.yml</exclude>
      <exclude>**/*.properties</exclude>
      <exclude>**/*.xml</exclude>
      <exclude>**/*.sh</exclude>
    </excludes>
  </configuration>
  <executions>
    <execution>
      <id>make-jar</id>
      <phase>compile</phase>
      <goals>
        <goal>jar</goal>
      </goals>
    </execution>
  </executions>
</plugin>

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <version>2.4</version>
  <configuration>
    <descriptors>
      <descriptor>${project.basedir}/src/main/assembly/assembly.xml</descriptor>
    </descriptors>
  </configuration>
  <executions>
    <execution>
      <id>make-assembly</id>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Key points: mainClass specifies the entry point of the Spring Boot application. excludes removes configuration files from the main JAR so they can be packaged separately. descriptor points to the assembly.xml that defines the zip layout.

Assembly Descriptor (assembly.xml)

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
  <id>${activeProfile}</id>
  <formats>
    <format>zip</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <dependencySets>
    <dependencySet>
      <useProjectArtifact>false</useProjectArtifact>
      <outputDirectory>${package-name}-${activeProfile}/lib</outputDirectory>
      <unpack>false</unpack>
    </dependencySet>
  </dependencySets>
  <fileSets>
    <fileSet>
      <directory>${project.basedir}/src/main/profiles/${activeProfile}</directory>
      <outputDirectory>${package-name}-${activeProfile}/conf</outputDirectory>
      <includes>
        <include>**/*</include>
      </includes>
    </fileSet>
    <fileSet>
      <directory>${project.basedir}/src/main/scripts</directory>
      <outputDirectory></outputDirectory>
      <includes>
        <include>**/*</include>
      </includes>
      <fileMode>777</fileMode>
      <directoryMode>777</directoryMode>
      <filtered>true</filtered>
    </fileSet>
    <fileSet>
      <directory>${project.build.directory}</directory>
      <outputDirectory>${package-name}-${activeProfile}/</outputDirectory>
      <includes>
        <include>*.jar</include>
      </includes>
    </fileSet>
  </fileSets>
</assembly>

Important nodes: formats defines the archive type (zip). fileMode sets execution permission (777) for the script files on Linux. filtered enables Maven to replace placeholders (e.g., ${package-name}) with actual values from the profile.

Using the Shell Script

The shenniu_publish.sh script provides four main commands:

unzip : extracts the zip package.

start : launches the Spring Boot jar (supports java -cp and java -jar modes).

stop : terminates the running process.

restart : stops and then starts the application.

#!/usr/bin/env bash
# Variable placeholders are filled by Maven
languageType="javac"   # java, javac, netcore
baseZipName="${package-name}-${activeProfile}"
packageName="${package-name}"
mainclass="${boot-main}"

basePath=$(cd `dirname $0`/; pwd)
baseZipPath="$basePath/$baseZipName.zip"
baseDirPath="$basePath"

function shenniu_unzip() {
  echo "Unzipping $baseZipPath..."
  if [ ! -f "$baseZipPath" ]; then
    echo "Zip not found: $baseZipPath"
    return
  fi
  unzip -od "$baseDirPath/$baseZipName" "$baseZipPath"
  chmod +x "$baseDirPath/$baseZipName/$packageName"
  echo "Unzip completed."
}

function getPid() {
  pid=$(ps -ef | grep -v grep | grep "$packageName" | awk '{print $2}')
  if [ "$pid" ]; then
    echo "Running pid: $pid"
  else
    echo "Not running"
  fi
}

function start() {
  stop
  if [ "$pid" ]; then
    echo "Failed to stop previous process, aborting start"
    return
  fi
  echo "Starting program..."
  read -p "Enter program type (java,javac,netcore) [${languageType}]: " read_languageType
  if [ "$read_languageType" ]; then
    languageType=$read_languageType
  fi
  echo "Selected type: $languageType"
  cd "$baseDirPath/$baseZipName"
  if [ "$languageType" == "javac" ]; then
    if [ "$mainclass" ]; then
      nohup java -cp conf:lib/*.jar:${packageName}.jar $mainclass > $baseDirPath/$packageName.out 2>&1 &
    fi
  elif [ "$languageType" == "java" ]; then
    nohup java -jar $baseDirPath/$baseZipName/${packageName}.jar > /dev/null 2>&1 &
  elif [ "$languageType" == "netcore" ]; then
    nohup $baseDirPath/$baseZipName/${packageName} > /dev/null 2>&1 &
  fi
  getPid
  if [ "$pid" ]; then
    echo "Started"
    tail -n 50 -f $baseDirPath/$packageName.out
  else
    echo "Start failed"
  fi
}

function stop() {
  getPid
  if [ "$pid" ]; then
    echo "Stopping program..."
    kill -9 $pid
    getPid
    if [ "$pid" ]; then
      echo "Stop failed"
    else
      echo "Stop succeeded"
    fi
  fi
}

if [ $# -ge 1 ]; then
  case $1 in
    "start") start ;;
    "restart") start ;;
    "stop") stop ;;
    "unzip") shenniu_unzip ; start ;;
    *) echo "$1: no action" ;;
  esac
else
  echo "Usage: ./shenniu_publish.sh [start|stop|restart|unzip]"
fi

Parameters such as package-name, activeProfile, and boot-main are injected from Maven profiles, so the script itself does not need manual edits.

Deployment Steps

Run mvn clean package -Pnode (or another profile) to generate the zip.

Upload the zip to the target Linux server.

Convert the script to Unix line endings if edited on Windows:

vim shenniu_publish.sh
set ff=unix
:wq

Execute the script, e.g., ./shenniu_publish.sh unzip or ./shenniu_publish.sh start.

The script will unzip the package, set execution permissions, and start the Spring Boot service, displaying logs or reporting errors as needed.

Reference

Git repository with the full project and script: https://github.com/shenniubuxing3/springcloud-Finchley.SR2

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AutomationDeploymentmavenLinuxSpring Bootpackagingshell script
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.