Spring Boot Packaging with Maven Assembly Plugin and shenniu_publish.sh Deployment Script
This article explains how to use Maven profiles and the Maven Assembly Plugin to create environment‑specific Spring Boot zip packages and provides a reusable shell script (shenniu_publish.sh) for extracting, starting, stopping, and restarting the packaged JAR on Linux, improving deployment efficiency.
Hello everyone, I'm Chen. In this article I share how to package a Spring Boot application and deploy it with a shell script tool, focusing on a reusable shell program to simplify work.
Profiles for Different Environments
Typically a program has multiple deployment environments such as development, test, UAT, and production. You can distinguish configuration files either by setting profile.active=uat in application.yml or, more conveniently, by defining Maven profiles that map to different configuration directories. The article uses the second method.
<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>
... (additional profiles node1, node2) ...
</profiles>The id node specifies the directory that contains the environment‑specific configuration files. The properties node defines values (e.g., ${package-name} ) that can be referenced in other configuration files or scripts. activeByDefault selects the default profile.
Creating a Release Zip with Maven Assembly Plugin
For a Spring Boot JAR you may want to keep configuration files and third‑party dependencies outside the JAR and package them into a zip for easy upload to Linux. This is achieved with maven-assembly-plugin together with maven-jar-plugin :
<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-a-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 : the entry point of the Java application (e.g., com.sm.EurekaServerApplication ).
excludes : removes configuration files from the main JAR so they can be packaged separately.
descriptor : points to the assembly.xml that defines the zip structure.
assembly.xml Configuration
<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, tar, etc.).
fileMode : sets executable permission (777) for scripts such as shenniu_publish.sh on Linux.
filtered : enables Maven property substitution inside the script (e.g., ${package-name} ).
After configuring Maven, you can select the desired profile in IntelliJ IDEA and generate the zip package.
shenniu_publish.sh – Shell Deployment Tool
The script provides functions to unzip the package, detect the running PID, start, stop, and restart the Java service, and handle command‑line arguments.
#!/usr/bin/env bash
# Variable parameters
languageType="javac" # support java, javac, netcore
baseZipName="${package-name}-${activeProfile}" # zip name
packageName="${package-name}" # jar name without .jar
mainclass="${boot-main}" # main class for java -cp
basePath=$(cd `dirname $0`/; pwd)
baseZipPath="${basePath}/${baseZipName}.zip"
baseDirPath="${basePath}"
pid=
function shenniu_unzip() {
echo "Unzipping..."
if [ ! `find ${baseZipPath}` ]; then
echo "Zip not found: ${baseZipPath}"
else
unzip -od ${baseDirPath}/${baseZipName} ${baseZipPath}
chmod +x ${baseDirPath}/${baseZipName}/${packageName}
echo "Unzip completed."
fi
}
function getPid() {
pid=`ps -ef | grep -n ${packageName} | grep -v grep | 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, cannot start"
else
read -p "Enter program type (java,javac,netcore) [default: ${languageType}]: " read_languageType
if [ ${read_languageType} ]; then
languageType=${read_languageType}
fi
echo "Program 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
fi
}
function stop() {
getPid
if [ ${pid} ]; then
echo "Stopping..."
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} has no action" ;;
esac
else
echo "Commands: unzip (extract+start), start, stop, restart"
echo "Example: ./shenniu_publish.sh start"
fiTo use the script on Linux, upload the zip, unzip it (or let the script do it), convert the script to Unix line endings with vim ( set ff=unix ), and then run ./shenniu_publish.sh start . The script will start the JAR, display logs, and you can stop or restart with the corresponding commands.
The full source code is available at https://github.com/shenniubuxing3/springcloud-Finchley.SR2 .
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.