Apache Maven for Spring Boot Development
Table of Contents​
- Maven Overview
- Project Structure
- POM.xml Deep Dive
- Essential Maven Commands
- Spring Boot Maven Integration
- Dependency Management
- Maven Profiles
- Build Lifecycle
- Common Plugins
- Best Practices
Maven Overview​
Apache Maven is a build automation and project management tool primarily used for Java projects. It uses a declarative approach based on the Project Object Model (POM).
Key Concepts​
- POM (Project Object Model): XML file containing project information and configuration
- Coordinates: Unique identifier for artifacts (groupId, artifactId, version)
- Repository: Storage location for project artifacts
- Dependency: External JAR files required by your project
- Plugin: Tools that perform specific tasks during the build process
Maven Coordinates​
<groupId>com.company.app</groupId>
<artifactId>my-spring-app</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
Project Structure​
Maven follows a standard directory layout:
my-spring-app/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/company/app/
│ │ │ ├── MySpringAppApplication.java
│ │ │ ├── controller/
│ │ │ ├── service/
│ │ │ ├── repository/
│ │ │ └── model/
│ │ └── resources/
│ │ ├── application.properties
│ │ ├── application.yml
│ │ ├── static/
│ │ └── templates/
│ └── test/
│ ├── java/
│ │ └── com/company/app/
│ └── resources/
├── target/
└── .mvn/
Key Directories​
- src/main/java: Main application source code
- src/main/resources: Configuration files, static resources
- src/test/java: Test source code
- target/: Compiled classes and built artifacts
- .mvn/: Maven wrapper configuration
POM.xml Deep Dive​
The pom.xml
is the heart of any Maven project. Here's a comprehensive Spring Boot example:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- Parent POM for Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<!-- Project Coordinates -->
<groupId>com.company.app</groupId>
<artifactId>my-spring-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<!-- Project Information -->
<name>My Spring Application</name>
<description>Demo project for Spring Boot</description>
<!-- Properties -->
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<spring-cloud.version>2023.0.0</spring-cloud.version>
</properties>
<!-- Dependencies -->
<dependencies>
<!-- Spring Boot Starters -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Database -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Development Tools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- Dependency Management -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- Build Configuration -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<!-- Profiles -->
<profiles>
<profile>
<id>dev</id>
<properties>
<spring.profiles.active>dev</spring.profiles.active>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<spring.profiles.active>prod</spring.profiles.active>
</properties>
</profile>
</profiles>
</project>
Essential Maven Commands​
Basic Commands​
# Clean the project (remove target directory)
mvn clean
# Compile the project
mvn compile
# Run tests
mvn test
# Package the project (create JAR/WAR)
mvn package
# Install artifact to local repository
mvn install
# Deploy artifact to remote repository
mvn deploy
# Clean and package
mvn clean package
# Skip tests during packaging
mvn package -DskipTests
# Run specific test class
mvn test -Dtest=MyTestClass
# Run specific test method
mvn test -Dtest=MyTestClass#testMethod
Spring Boot Specific Commands​
# Run Spring Boot application
mvn spring-boot:run
# Run with specific profile
mvn spring-boot:run -Dspring-boot.run.profiles=dev
# Run with JVM arguments
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-Xmx512m"
# Build executable JAR
mvn clean package spring-boot:repackage
# Generate build info
mvn spring-boot:build-info
Dependency Commands​
# Display dependency tree
mvn dependency:tree
# Analyze dependencies
mvn dependency:analyze
# Download sources
mvn dependency:sources
# Copy dependencies
mvn dependency:copy-dependencies
# Purge local repository
mvn dependency:purge-local-repository
Information Commands​
# Display effective POM
mvn help:effective-pom
# Display effective settings
mvn help:effective-settings
# List active profiles
mvn help:active-profiles
# Describe plugin goals
mvn help:describe -Dplugin=spring-boot
Spring Boot Maven Integration​
Spring Boot Parent POM​
The Spring Boot parent POM provides:
- Default configurations for plugins
- Dependency version management
- Sensible resource filtering
- Plugin configuration
Spring Boot Maven Plugin​
Key features:
- Executable JARs: Creates fat JARs with embedded server
- Run Goal: Run application directly from Maven
- Repackage Goal: Repackage existing JAR/WAR as executable
- Build Info: Generate build information
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.company.app.Application</mainClass>
<layout>JAR</layout>
<excludeDevtools>false</excludeDevtools>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
Dependency Management​
Scopes​
- compile: Default scope, available in all phases
- provided: Available during compilation, not packaged
- runtime: Not needed for compilation, required for execution
- test: Only available during test compilation and execution
- system: Similar to provided, but JAR is explicitly provided
- import: Only used in dependencyManagement for importing POMs
<dependencies>
<!-- Compile scope (default) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Runtime scope -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Test scope -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Optional dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
Version Management​
<properties>
<mysql.version>8.0.33</mysql.version>
<jackson.version>2.15.2</jackson.version>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
Maven Profiles​
Profiles allow you to customize builds for different environments:
<profiles>
<!-- Development Profile -->
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<spring.profiles.active>dev</spring.profiles.active>
<database.url>jdbc:h2:mem:devdb</database.url>
</properties>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</profile>
<!-- Production Profile -->
<profile>
<id>prod</id>
<properties>
<spring.profiles.active>prod</spring.profiles.active>
<database.url>jdbc:mysql://localhost:3306/proddb</database.url>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludeDevtools>true</excludeDevtools>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Activating Profiles​
# Activate specific profile
mvn clean package -Pprod
# Activate multiple profiles
mvn clean package -Ptest,integration
# List active profiles
mvn help:active-profiles -Pprod
Build Lifecycle​
Maven has three built-in build lifecycles:
Default Lifecycle (Main Phases)​
- validate: Validate project structure
- compile: Compile source code
- test: Run unit tests
- package: Create JAR/WAR
- verify: Run integration tests
- install: Install to local repository
- deploy: Deploy to remote repository
Clean Lifecycle​
- pre-clean: Execute processes before cleaning
- clean: Remove all files generated by the build
- post-clean: Execute processes after cleaning
Site Lifecycle​
- pre-site: Execute processes before site generation
- site: Generate project site documentation
- post-site: Execute processes after site generation
- site-deploy: Deploy generated site to web server
Common Plugins​
Spring Boot Maven Plugin​
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
Maven Compiler Plugin​
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
Maven Surefire Plugin (Unit Tests)​
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<includes>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
</includes>
</configuration>
</plugin>
Maven Failsafe Plugin (Integration Tests)​
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<includes>
<include>**/*IT.java</include>
<include>**/*IntegrationTest.java</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
JaCoCo Plugin (Code Coverage)​
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.8</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
Best Practices​
1. Project Structure​
- Follow Maven's standard directory layout
- Keep source code organized in logical packages
- Separate test code from main code
2. Dependency Management​
- Use Spring Boot's dependency management
- Avoid version conflicts by using BOMs
- Regularly update dependencies for security patches
- Use appropriate scopes for dependencies
<!-- Good: Using managed version -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Avoid: Hardcoding versions when parent manages them -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.0</version>
</dependency>
3. Properties Management​
- Use properties for version management
- Keep environment-specific configurations in profiles
- Use meaningful property names
4. Build Configuration​
- Configure plugins explicitly with versions
- Use profiles for environment-specific builds
- Keep build configuration minimal and focused
5. Testing​
- Separate unit tests from integration tests
- Use appropriate test scopes
- Configure test plugins properly
6. Security​
- Regularly scan for vulnerabilities
- Use HTTPS for repository connections
- Avoid storing credentials in POM files
Common Issues and Solutions​
1. Version Conflicts​
# Check for conflicts
mvn dependency:tree -Dverbose
# Exclude transitive dependencies
<dependency>
<groupId>some.group</groupId>
<artifactId>some-artifact</artifactId>
<exclusions>
<exclusion>
<groupId>conflicting.group</groupId>
<artifactId>conflicting-artifact</artifactId>
</exclusion>
</exclusions>
</dependency>
2. Memory Issues​
# Set Maven memory options
export MAVEN_OPTS="-Xmx2048m -XX:MaxPermSize=256m"
3. Encoding Issues​
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
This guide covers the essential Maven concepts and practices for Spring Boot development. Remember to keep your Maven knowledge updated as new versions introduce new features and improvements.