How to Package Spring Boot Apps with Maven Profiles and Deploy via a Custom Shell Script
This guide walks through configuring Maven profiles to produce environment‑specific Spring Boot packages, using the maven‑assembly‑plugin to create a zip bundle, and operating a reusable shell script that can unzip, start, stop, and restart the jar on Linux.
Environment‑specific configuration via Maven profiles
Three Maven profiles ( node, node1, node2) are defined in pom.xml. Each profile sets three properties:
activeProfile – the name of the profile (e.g. node)
package-name – a placeholder ${scripts_packageName} that is substituted into the assembly descriptor and the shell script
boot-main – the fully‑qualified main class (e.g. ${scripts_bootMain})
Activation is true by default, so the profile can be switched in an IDE or on the command line.
<profiles>
<profile>
<id>node</id>
<properties>
<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>Maven Assembly plugin – building a deployment zip
The maven-jar-plugin creates a plain JAR without configuration files. The maven-assembly-plugin then packages the JAR, the environment‑specific conf directory and the launch script into a zip file.
<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>The accompanying assembly.xml defines the zip layout:
<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>Launch script shenniu_publish.sh
The script receives a command ( start, stop, restart, unzip) and performs the following steps:
shenniu_unzip – checks the existence of the zip, runs unzip -od $baseDirPath/$baseZipName $baseZipPath and sets executable permission on the script.
getPid – obtains the PID of a running process that matches ${packageName} using
ps -ef | grep -n $packageName | grep -v grep | awk '{print $2}'.
start – calls stop first, then launches the application based on languageType: java -cp conf:lib/*.jar:${packageName}.jar ${bootMain} (when languageType=javac) java -jar ${packageName}.jar (when languageType=java)
placeholder for a netcore command.
stop – kills the PID if found and verifies the kill succeeded.
The script parses the first argument with a case statement to invoke the appropriate function. If no argument is supplied, usage instructions are printed.
#!/usr/bin/env bash
# variable definitions (filled by Maven)
languageType="javac"
baseZipName="${package-name}-${activeProfile}"
packageName="${package-name}"
mainclass="${boot-main}"
basePath=$(cd `dirname $0`/; pwd)
baseZipPath="${basePath}/${baseZipName}.zip"
baseDirPath="${basePath}"
pid=
function shenniu_unzip() {
echo "--- unzip ---"
if [ ! `find ${baseZipPath}` ]; then
echo "zip not found: ${baseZipPath}"
return
fi
echo "unzip to ${baseDirPath}/${baseZipName}"
unzip -od ${baseDirPath}/${baseZipName} ${baseZipPath}
chmod +x ${baseDirPath}/${baseZipName}/${packageName}
echo "unzip completed"
}
function getPid() {
echo "--- get pid ---"
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
getPid
if [ "${pid}" ]; then
echo "cannot start, process still running"
return
fi
echo "--- start program ---"
read -p "input program type (java,javac,netcore) [${languageType}]: " read_languageType
if [ "${read_languageType}" ]; then
languageType=${read_languageType}
fi
echo "type: ${languageType}"
cd ${baseDirPath}/${baseZipName}
if [ "${languageType}" == "javac" ]; then
nohup java -cp conf:lib/*.jar:${packageName}.jar ${mainclass} > ${baseDirPath}/${packageName}.out 2>&1 &
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 "--- stop program ---"
kill -9 ${pid}
getPid
if [ "${pid}" ]; then
echo "stop failed"
else
echo "stop succeeded"
fi
else
echo "no process to stop"
fi
}
if [ $# -ge 1 ]; then
case $1 in
"start") start ;;
"restart") start ;;
"stop") stop ;;
"unzip") shenniu_unzip ; start ;;
*) echo "${1} no operation" ;;
esac
else
echo "usage: $0 {start|stop|restart|unzip}"
fiPackaging and deployment workflow
Run mvn clean package. Maven builds the JAR and the assembly plugin creates ${package-name}-${activeProfile}.zip.
Copy the zip to the target Linux host.
Convert line endings if the script was edited on Windows:
vim shenniu_publish.sh
:set ff=unix
:wqUnzip the package (example for the node profile):
unzip -od eureka-server-0.0.1-node eureka-server-0.0.1-node.zipStart the service: ./shenniu_publish.sh start The script prints the PID, tails the last 50 lines of the output file, and reports success or failure.
Use ./shenniu_publish.sh stop to terminate, restart to stop then start, and unzip to unzip and start in one step.
All variable values ( package-name, activeProfile, boot-main) are injected from the Maven profile, so the same script works for any environment without manual edits.
Full source, including the Maven configuration, assembly.xml and the launch script, is available at:
https://github.com/shenniubuxing3/springcloud-Finchley.SR2
Java Web Project
Focused on Java backend technologies, trending internet tech, and the latest industry developments. The platform serves over 200,000 Java developers, inviting you to learn and exchange ideas together. Check the menu for Java learning resources.
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.
