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.

Java Web Project
Java Web Project
Java Web Project
How to Package Spring Boot Apps with Maven Profiles and Deploy via a Custom Shell Script

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}"
fi

Packaging 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
:wq

Unzip the package (example for the node profile):

unzip -od eureka-server-0.0.1-node eureka-server-0.0.1-node.zip

Start 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

deploymentmavenSpring Bootshell scriptProfilesAssembly plugin
Java Web Project
Written by

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.

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.