Build Tools - Công cụ Build trong Java
Tổng quan về Build Tools
Build tools là những công cụ tự động hóa quá trình biên dịch, đóng gói, và quản lý dependencies trong dự án Java. Chúng đóng vai trò quan trọng trong việc standardize quy trình phát triển và deployment.
Maven
Khái niệm cơ bản
Maven là một project management tool sử dụng Project Object Model (POM) để quản lý build lifecycle, dependencies, và documentation.
Cấu trúc Project Maven
my-app/
├── pom.xml
└── src/
├── main/
│ ├── java/
│ └── resources/
└── test/
├── java/
└── resources/
File pom.xml cơ bản
<?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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- Project Information -->
<groupId>com.example</groupId>
<artifactId>my-application</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>My Application</name>
<description>Example Spring Boot Application</description>
<!-- Properties -->
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.boot.version>3.2.0</spring.boot.version>
<junit.version>5.10.0</junit.version>
</properties>
<!-- Dependencies -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<!-- Test Dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring.boot.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- Build Configuration -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</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>
</configuration>
</plugin>
<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>
</plugins>
</build>
<!-- Profiles -->
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<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>
Maven Lifecycle và Commands
# Compile source code
mvn compile
# Run tests
mvn test
# Package project (tạo JAR/WAR)
mvn package
# Install vào local repository
mvn install
# Deploy lên remote repository
mvn deploy
# Clean project
mvn clean
# Full build cycle
mvn clean install
# Skip tests
mvn clean install -DskipTests
# Run specific profile
mvn clean install -P prod
# Run application
mvn spring-boot:run
Multi-module Maven Project
<!-- Parent POM -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>multi-module-app</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>common</module>
<module>service</module>
<module>web</module>
</modules>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<spring.boot.version>3.2.0</spring.boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Gradle
Khái niệm cơ bản
Gradle là một build automation tool sử dụng Groovy hoặc Kotlin DSL thay vì XML như Maven. Gradle nhanh hơn và linh hoạt hơn Maven.
Cấu trúc Project Gradle
my-app/
├── build.gradle
├── settings.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── src/
├── main/
│ ├── java/
│ └── resources/
└── test/
├── java/
└── resources/
File build.gradle (Groovy)
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'com.example'
version = '1.0.0'
sourceCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
// Spring Boot Starters
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-validation'
// Database
runtimeOnly 'mysql:mysql-connector-java'
runtimeOnly 'com.h2database:h2'
// Utils
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
// Test Dependencies
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation 'org.testcontainers:mysql'
}
tasks.named('test') {
useJUnitPlatform()
// Test configuration
testLogging {
events "passed", "skipped", "failed"
exceptionFormat "full"
}
// Memory settings
minHeapSize = "256m"
maxHeapSize = "2g"
}
// Custom tasks
task copyDependencies(type: Copy) {
from configurations.runtimeClasspath
into 'build/dependencies'
}
task generateDocumentation(type: Javadoc) {
source = sourceSets.main.allJava
classpath = configurations.compileClasspath
destinationDir = file("$buildDir/docs/javadoc")
}
// Build configuration
jar {
archiveBaseName = 'my-application'
archiveVersion = '1.0.0'
enabled = false
}
bootJar {
archiveBaseName = 'my-application'
archiveVersion = '1.0.0'
// Include additional files
from('src/main/resources') {
include 'static/**'
include 'templates/**'
}
}
// Profiles equivalent
if (project.hasProperty('prod')) {
bootRun {
args = ['--spring.profiles.active=prod']
}
} else {
bootRun {
args = ['--spring.profiles.active=dev']
}
}
File build.gradle.kts (Kotlin DSL)
plugins {
java
id("org.springframework.boot") version "3.2.0"
id("io.spring.dependency-management") version "1.1.4"
}
group = "com.example"
version = "1.0.0"
java.sourceCompatibility = JavaVersion.VERSION_17
configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-security")
runtimeOnly("mysql:mysql-connector-java")
compileOnly("org.projectlombok:lombok")
annotationProcessor("org.projectlombok:lombok")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.security:spring-security-test")
}
tasks.withType<Test> {
useJUnitPlatform()
}
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
}
Gradle Commands
# Build project
./gradlew build
# Run tests
./gradlew test
# Run application
./gradlew bootRun
# Clean project
./gradlew clean
# Generate JAR
./gradlew jar
# Generate executable JAR
./gradlew bootJar
# Check dependencies
./gradlew dependencies
# Run specific task
./gradlew copyDependencies
# Run with profile
./gradlew bootRun -Pprod
# Skip tests
./gradlew build -x test
# Continuous build
./gradlew build --continuous
# Build info
./gradlew projects
./gradlew tasks
Multi-project Gradle Setup
// settings.gradle.kts
rootProject.name = "multi-module-app"
include(
"common",
"service",
"web"
)
// Root build.gradle.kts
plugins {
java
id("org.springframework.boot") version "3.2.0" apply false
id("io.spring.dependency-management") version "1.1.4" apply false
}
allprojects {
group = "com.example"
version = "1.0.0"
repositories {
mavenCentral()
}
}
subprojects {
apply(plugin = "java")
java.sourceCompatibility = JavaVersion.VERSION_17
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter")
}
tasks.withType<Test> {
useJUnitPlatform()
}
}
So sánh Maven vs Gradle
Performance
- Gradle: Nhanh hơn nhờ incremental builds, build cache, parallel execution
- Maven: Chậm hơn nhưng ổn định
Flexibility
- Gradle: Rất linh hoạt với Groovy/Kotlin DSL
- Maven: Ít linh hoạt hơn với XML
Learning Curve
- Maven: Dễ học hơn, documentation tốt
- Gradle: Khó học hơn nhưng mạnh mẽ hơn
Ecosystem
- Maven: Ecosystem lớn, nhiều plugin
- Gradle: Ecosystem đang phát triển mạnh
Best Practices
Maven Best Practices
- Sử dụng Properties cho versions
<properties>
<spring.version>5.3.23</spring.version>
<junit.version>5.9.1</junit.version>
</properties>
- Dependency Management
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
- Profile Management
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
</profiles>
Gradle Best Practices
- Sử dụng Gradle Wrapper
./gradlew build # Thay vì gradle build
- Optimize Build Performance
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configureondemand=true
- Version Catalogs (Gradle 7+)
// gradle/libs.versions.toml
[versions]
spring = "6.0.0"
junit = "5.9.1"
[libraries]
spring-core = { module = "org.springframework:spring-core", version.ref = "spring" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
[plugins]
spring-boot = { id = "org.springframework.boot", version = "3.2.0" }
Các vấn đề thường gặp
Maven Issues
- Dependency Conflicts
mvn dependency:tree
mvn dependency:analyze
- Plugin Version Issues
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
</plugin>
Gradle Issues
- Build Cache Issues
./gradlew clean --build-cache
- Dependency Resolution
configurations.all {
resolutionStrategy {
force("com.google.guava:guava:30.1-jre")
}
}
Cả Maven và Gradle đều là những công cụ mạnh mẽ cho việc build Java projects. Việc chọn lựa phụ thuộc vào team size, project complexity, và performance requirements của dự án.