Automating Java Application Deployment with Jenkins: A Complete CI/CD Pipeline Guide
👋 Hey there! I’m Shohanur Rahman!
I’m a backend developer with over 5.5 years of experience in building scalable and efficient web applications. My work focuses on Java, Spring Boot, and microservices architecture, where I love designing robust API solutions and creating secure middleware for complex integrations.
💼 What I Do Backend Development: Expert in Spring Boot, Spring Cloud, and Spring WebFlux, I create high-performance microservices that drive seamless user experiences. Cloud & DevOps: AWS enthusiast, skilled in using EC2, S3, RDS, and Docker to design scalable and reliable cloud infrastructures. Digital Security: Passionate about securing applications with OAuth2, Keycloak, and digital signatures for data integrity and privacy. 🚀 Current Projects I’m currently working on API integrations with Spring Cloud Gateway and designing an e-invoicing middleware. My projects often involve asynchronous processing, digital signature implementations, and ensuring high standards of security.
📝 Why I Write I enjoy sharing what I’ve learned through blog posts, covering everything from backend design to API security and cloud best practices. Check out my posts if you’re into backend dev, cloud tech, or digital security!
In modern software development, automation is key to delivering quality software quickly and reliably. In this post, I'll walk you through a production-ready Jenkins pipeline that automates the entire lifecycle of a Java application—from source code checkout to deployment on a Windows server with automated service management.
Overview
This Jenkins declarative pipeline demonstrates a complete CI/CD workflow for a Maven-based Java application. It handles:
✅ Source code checkout from GitHub
✅ Maven build and testing
✅ Artifact archiving
✅ Automated deployment to a Windows server
✅ Windows service management
✅ Email notifications for build status
Let's break down each component and understand how this pipeline works.
Pipeline Configuration
Agent and Parameters
pipeline {
agent any
parameters {
string(name: 'BRANCH', defaultValue: 'master', description: 'Branch to build')
}
agent any: The pipeline can run on any available Jenkins agentParameters: Allows users to specify which Git branch to build (defaults to
master), providing flexibility for building feature branches or releases
Tools and Environment
tools {
maven 'maven'
}
environment {
PROJECT_NAME = 'Jenkin Demo'
SERVICE_NAME = 'Jenkin Demo'
VERSION = "${env.BUILD_ID}"
DEPLOY_DIR = 'D:\\Applications\\jenkins-demo'
}
Tools: Configures Maven as the build tool (must be pre-configured in Jenkins Global Tool Configuration)
Environment Variables: Centralizes configuration for project name, deployment directory, and versioning
Stage 1: Checkout
stage('Checkout') {
steps {
script {
echo "Checking out branch: ${params.BRANCH}"
checkout([
$class: 'GitSCM',
branches: [[name: "*/${params.BRANCH}"]],
userRemoteConfigs: [[
url: 'https://github.com/Shohanur-Rahman_lmig/jenkins-demo.git',
credentialsId: 'GitHub-Password'
]]
])
}
}
}
What it does:
Clones the repository from GitHub
Checks out the specified branch (from the pipeline parameter)
Uses stored credentials (
GitHub-Password) for authentication
Key Feature: Dynamic branch selection allows the same pipeline to build any branch without modification.
Stage 2: Build
stage('Build') {
steps {
echo "Building application with Maven..."
bat "mvn -Dmaven.test.failure.ignore=true clean package"
}
post {
success {
junit '**/target/surefire-reports/TEST-*.xml'
echo "Archiving JAR files..."
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
}
What it does:
Executes Maven build with
clean packagelifecycleRuns unit tests (continues even if some tests fail with
-Dmaven.test.failure.ignore=true)Archives test results using JUnit plugin
Saves the generated JAR file as a build artifact
Why it matters: Test results are captured for visibility, and artifacts are preserved for traceability and potential rollback scenarios.
Stage 3: Deploy
This is where the magic happens—automated deployment to a Windows server with intelligent service management.
stage('Deploy') {
steps {
script {
echo "Deploying to: ${env.DEPLOY_DIR}"
// Create directory if it doesn't exist
bat "if not exist \"${env.DEPLOY_DIR}\" mkdir \"${env.DEPLOY_DIR}\""
// Copy JAR to deployment directory
bat "copy /Y target\\*.jar \"${env.DEPLOY_DIR}\\\""
// Windows service control
def serviceName = env.SERVICE_NAME ?: 'Jenkin Demo'
def status = powershell(script: "Get-Service -Name '${serviceName}' | Select-Object -ExpandProperty Status", returnStdout: true).trim()
if (status == "") {
error "Service '${serviceName}' is not installed on this machine."
} else if (status.equalsIgnoreCase("Running")) {
powershell "Restart-Service -Name '${serviceName}' -Force"
} else {
powershell "Start-Service -Name '${serviceName}'"
}
echo "JAR deployed and Windows service handled."
}
}
}
Deployment Steps:
Directory Creation: Ensures the deployment directory exists
Artifact Copy: Copies the built JAR file to the deployment location
Service Management:
Checks if the Windows service exists
If running → Restarts the service
If stopped → Starts the service
If not installed → Throws an error
Smart Service Handling: The pipeline intelligently manages the application service state, ensuring zero-downtime deployments when possible.
Post-Build Notifications
Success Notification
success {
echo "Pipeline succeeded! Sending success email..."
emailext (
subject: "SUCCESS: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]'",
body: """
<h2>Build Success!</h2>
<p><b>Project:</b> ${env.PROJECT_NAME}</p>
<p><b>Build Number:</b> ${env.BUILD_NUMBER}</p>
<p><b>Branch:</b> ${params.BRANCH}</p>
<p><b>Build URL:</b> <a href="${env.BUILD_URL}">${env.BUILD_URL}</a></p>
""",
mimeType: 'text/html',
from: 'no-reply@libertyinsurance.com.my',
recipientProviders: [buildUser(), requestor()]
)
}
Failure Notification
failure {
echo "Pipeline failed! Sending failure email..."
emailext (
subject: "FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]'",
body: """
<h2 style="color: red;">Build Failed!</h2>
<p><b>Project:</b> ${env.PROJECT_NAME}</p>
<p><b>Build Number:</b> ${env.BUILD_NUMBER}</p>
<p><b>Failed Stage:</b> Check Jenkins console for details</p>
""",
mimeType: 'text/html',
from: 'no-reply@libertyinsurance.com.my',
recipientProviders: [buildUser(), requestor()]
)
}
Benefits:
Team members are immediately notified of build status
HTML formatting makes emails easy to read
Direct links to Jenkins console for troubleshooting
Notifies the user who triggered the build
Key Features and Best Practices
✅ Parameterized Builds
The pipeline accepts branch names as parameters, making it reusable across different branches without code changes.
✅ Automated Testing
Maven tests run automatically, and results are captured for quality metrics.
✅ Artifact Management
JAR files are archived with fingerprinting for version tracking and audit trails.
✅ Windows Integration
Native Windows batch commands and PowerShell integration for seamless Windows server deployment.
✅ Error Handling
The pipeline validates service existence before attempting restarts, preventing silent failures.
✅ Communication
Automated email notifications keep the team informed without manual intervention.
Prerequisites
To use this pipeline, you'll need:
Jenkins Plugins:
Pipeline
Git Plugin
Maven Integration
Email Extension Plugin
JUnit Plugin
Jenkins Configuration:
Maven tool configured in Global Tool Configuration
GitHub credentials stored with ID
GitHub-PasswordEmail server (SMTP) configured
Windows Server Setup:
Java Runtime Environment
Windows service for the application (pre-installed)
Jenkins agent with PowerShell execution permissions
Usage
Create a new Pipeline job in Jenkins
Copy this script into the Pipeline definition
Configure the following:
Update the GitHub repository URL
Adjust
DEPLOY_DIRto your deployment pathUpdate email sender and recipient settings
Run the pipeline and select your target branch
Improvements and Extensions
This pipeline can be enhanced with:
Multi-environment deployment (DEV, QA, PROD) using conditional logic
Docker containerization for platform-independent deployment
Slack notifications in addition to email
Rollback capability using archived artifacts
Integration testing stage before deployment
Blue-green deployment for zero-downtime releases
Conclusion
This Jenkins pipeline demonstrates how automation transforms software delivery from manual, error-prone processes into reliable, repeatable workflows. By automating checkout, build, test, deployment, and notification stages, teams can focus on writing code rather than managing infrastructure.
The combination of Maven for builds, PowerShell for Windows service management, and email notifications creates a robust CI/CD pipeline suitable for enterprise Java applications running on Windows servers.
Ready to automate your deployments? Start with this pipeline template and customize it to fit your specific needs!
Have questions or suggestions? Feel free to reach out or leave a comment below!