Tìm Hiểu Sâu: Java Modules và Công Cụ Build

Xây dựng các ứng dụng Java chuyên nghiệp đòi hỏi nhiều hơn việc chỉ viết code—bạn cần các công cụ build mạnh mẽ để quản lý dependencies, biên dịch dự án, chạy tests, và đóng gói sản phẩm. Trong bài tìm hiểu sâu này, chúng ta sẽ khám phá Maven và Gradle, hai công cụ build chiếm ưu thế trong hệ sinh thái Java, và tìm hiểu về hệ thống module Java 9+.
Đây là Giai đoạn 3 trong lộ trình Java của chúng ta: làm chủ hệ sinh thái build hỗ trợ phát triển Java doanh nghiệp.
Tại Sao Công Cụ Build Quan Trọng
Các dự án Java hiện đại có yêu cầu phức tạp:
- Quản lý Dependencies: Quản lý hàng chục hoặc hàng trăm thư viện
- Tự động hóa Build: Biên dịch, testing và đóng gói nhất quán
- Dự án Đa Module: Tổ chức codebase lớn
- Tích hợp IDE: Trải nghiệm phát triển liền mạch
- Tích hợp CI/CD: Build và deployment tự động
Nếu không có công cụ build, bạn sẽ phải tải JAR thủ công, quản lý classpaths, và viết các shell script phức tạp. Maven và Gradle giải quyết các vấn đề này một cách tinh tế.
Maven: Convention Over Configuration
Maven đã là tiêu chuẩn de facto cho Java builds từ năm 2004. Nó tuân theo triết lý nghiêm ngặt "convention over configuration" với cấu trúc dự án được chuẩn hóa.
Cấu Trúc Dự Án
Maven áp dụng một layout thư mục chuẩn:
my-app/
├── pom.xml # Project Object Model (cấu hình build)
├── src/
│ ├── main/
│ │ ├── java/ # Mã nguồn ứng dụng
│ │ └── resources/ # File cấu hình, properties
│ └── test/
│ ├── java/ # Mã nguồn test
│ └── resources/ # Tài nguyên test
└── target/ # Output build (được tạo)Cấu trúc này là phổ quát—mọi dự án Maven trông giống nhau, giúp dễ dàng điều hướng các codebase chưa quen.
Hiểu Về pom.xml
File pom.xml là trái tim của dự án Maven. Đây là một ví dụ toàn diệ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 Coordinates (Maven GAV) -->
<groupId>com.chanhle</groupId>
<artifactId>my-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<!-- Project Metadata -->
<name>My Application</name>
<description>A sample Java application</description>
<!-- Properties (for version management) -->
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Dependency Versions -->
<spring.boot.version>3.2.1</spring.boot.version>
<junit.version>5.10.1</junit.version>
</properties>
<!-- Dependencies -->
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<!-- Lombok (compile-time only) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<!-- JUnit 5 (test scope) -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- Build Configuration -->
<build>
<plugins>
<!-- Maven Compiler Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
<!-- Maven Surefire Plugin (for tests) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.3</version>
</plugin>
<!-- Spring Boot Maven Plugin -->
<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>
</plugins>
</build>
</project>Maven Coordinates: GAV
Mọi artifact Maven được xác định bởi ba tọa độ (GAV):
- GroupId: Tổ chức/namespace (ví dụ:
com.chanhle) - ArtifactId: Tên dự án (ví dụ:
my-app) - Version: Số version (ví dụ:
1.0.0-SNAPSHOT)
Dependency Scopes
Maven cung cấp một số dependency scopes:
| Scope | Build | Test | Runtime | Mô tả |
|---|---|---|---|---|
compile | ✅ | ✅ | ✅ | Scope mặc định, có sẵn ở mọi nơi |
provided | ✅ | ✅ | ❌ | Được cung cấp bởi runtime (ví dụ: servlet API) |
runtime | ❌ | ✅ | ✅ | Không cần cho compilation (ví dụ: JDBC drivers) |
test | ❌ | ✅ | ❌ | Chỉ dành cho testing (ví dụ: JUnit) |
system | ✅ | ✅ | ✅ | Các file JAR local (tránh nếu có thể) |
import | N/A | N/A | N/A | Import quản lý dependency từ BOM |
Ví dụ:
<!-- Compile scope (mặc định) -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.3-jre</version>
</dependency>
<!-- Provided scope (ví dụ: Lombok) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<!-- Test scope (ví dụ: thư viện testing) -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.8.0</version>
<scope>test</scope>
</dependency>Maven Build Lifecycle
Maven có ba vòng đời tích hợp, mỗi vòng có các phases:
1. Default Lifecycle (Build & Deploy)
# Các phase chính (theo thứ tự):
mvn validate # Validate cấu trúc dự án
mvn compile # Biên dịch mã nguồn
mvn test # Chạy unit tests
mvn package # Tạo JAR/WAR
mvn verify # Chạy integration tests
mvn install # Cài đặt vào repository local (~/.m2/repository)
mvn deploy # Deploy lên repository remote2. Clean Lifecycle
mvn clean # Xóa thư mục target/3. Site Lifecycle
mvn site # Tạo tài liệu dự ánPhase Chaining:
Mỗi phase thực thi tất cả các phase trước đó:
mvn package # Chạy: validate → compile → test → package
mvn clean install # Chạy: clean → validate → compile → test → package → installMaven Plugins
Plugins mở rộng chức năng của Maven. Đây là các plugin cần thiết:
Compiler Plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>21</source>
<target>21</target>
<compilerArgs>
<arg>--enable-preview</arg> <!-- Bật preview features -->
</compilerArgs>
</configuration>
</plugin>JAR Plugin (với Manifest):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.chanhle.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>Shade Plugin (Fat JAR):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.chanhle.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>Maven Profiles
Profiles cho phép cấu hình theo môi trường cụ thể:
<profiles>
<!-- Development Profile -->
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<env>development</env>
<database.url>jdbc:postgresql://localhost:5432/dev_db</database.url>
</properties>
</profile>
<!-- Production Profile -->
<profile>
<id>prod</id>
<properties>
<env>production</env>
<database.url>jdbc:postgresql://prod-server:5432/prod_db</database.url>
</properties>
<build>
<plugins>
<!-- Bật code obfuscation trong production -->
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.6.0</version>
</plugin>
</plugins>
</build>
</profile>
</profiles>Sử dụng:
mvn clean install # Sử dụng dev profile (mặc định)
mvn clean install -Pprod # Kích hoạt prod profileGradle: Linh Hoạt và Mạnh Mẽ
Gradle là công cụ build hiện đại nhấn mạnh vào tính linh hoạt và hiệu suất. Đây là công cụ build mặc định cho Android và ngày càng phổ biến cho Java phía server.
Lợi Thế Chính
- Hiệu suất: Incremental builds, build cache, thực thi song song
- Linh hoạt: Build scripts theo chương trình (Groovy hoặc Kotlin DSL)
- Ngắn gọn: Ít verbose hơn Maven XML
- Mạnh mẽ: Có thể mô hình hóa logic build phức tạp
Cấu Trúc Dự Án
Gradle sử dụng cùng cấu trúc thư mục như Maven nhưng thêm:
my-app/
├── build.gradle # Cấu hình build (Groovy)
├── settings.gradle # Cài đặt multi-project
├── gradlew # Gradle Wrapper (Unix)
├── gradlew.bat # Gradle Wrapper (Windows)
├── gradle/
│ └── wrapper/
│ └── gradle-wrapper.properties
├── src/
│ ├── main/java/
│ └── test/java/
└── build/ # Output build (như target/)Groovy DSL vs Kotlin DSL
Gradle hỗ trợ hai DSL:
Groovy DSL (build.gradle):
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.1'
}
group = 'com.chanhle'
version = '1.0.0-SNAPSHOT'
java {
sourceCompatibility = JavaVersion.VERSION_21
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}Kotlin DSL (build.gradle.kts):
plugins {
java
id("org.springframework.boot") version "3.2.1"
}
group = "com.chanhle"
version = "1.0.0-SNAPSHOT"
java {
sourceCompatibility = JavaVersion.VERSION_21
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
compileOnly("org.projectlombok:lombok:1.18.30")
annotationProcessor("org.projectlombok:lombok:1.18.30")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks.test {
useJUnitPlatform()
}Khuyến nghị: Sử dụng Kotlin DSL cho type safety và autocomplete của IDE.
Gradle Configuration Scopes
Gradle sử dụng tên khác cho dependency scopes:
| Gradle | Tương đương Maven | Mô tả |
|---|---|---|
implementation | compile | Có sẵn tại compile và runtime |
api | compile | Giống implementation nhưng transitive |
compileOnly | provided | Chỉ compile-time |
runtimeOnly | runtime | Chỉ runtime |
testImplementation | test | Test compile và runtime |
testCompileOnly | test (provided) | Chỉ test compile |
testRuntimeOnly | test (runtime) | Chỉ test runtime |
Quan trọng: Sử dụng implementation thay vì api trừ khi bạn cần transitive exposure.
Gradle Tasks
Tasks là đơn vị công việc trong Gradle:
# Liệt kê tất cả tasks
./gradlew tasks
# Các tasks phổ biến
./gradlew clean # Xóa build/
./gradlew compileJava # Biên dịch nguồn
./gradlew test # Chạy tests
./gradlew build # Full build (compile + test + package)
./gradlew bootRun # Chạy Spring Boot app
./gradlew bootJar # Tạo JAR thực thiCustom Gradle Tasks
Bạn có thể định nghĩa custom tasks trong build.gradle:
task hello {
doLast {
println 'Hello, Gradle!'
}
}
task copyResources(type: Copy) {
from 'src/main/resources'
into 'build/custom-resources'
}
task printClasspath {
doLast {
configurations.runtimeClasspath.each { println it }
}
}Chạy custom tasks:
./gradlew hello
./gradlew copyResourcesGradle Wrapper
Gradle Wrapper (gradlew) là một game-changer:
- Tính nhất quán Version: Mọi developer sử dụng cùng phiên bản Gradle
- Không cần cài đặt: Tự động tải Gradle
- CI/CD Ready: Không cần cài Gradle trong môi trường CI
Luôn sử dụng wrapper:
./gradlew build # Unix/Linux/macOS
gradlew.bat build # WindowsKhởi tạo wrapper:
gradle wrapper --gradle-version=8.5Tìm Hiểu Sâu Về Quản Lý Dependencies
Transitive Dependencies
Khi bạn khai báo một dependency, bạn cũng nhận được các dependencies của nó (transitive dependencies).
Ví dụ:
<!-- Bạn khai báo Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Maven tự động bao gồm:
- spring-boot-starter
- spring-boot
- spring-core
- spring-web
- spring-webmvc
- tomcat-embed-core
- jackson-databind
- ... và nhiều hơn nữa
-->Xem dependency tree:
# Maven
mvn dependency:tree
# Gradle
./gradlew dependenciesVersion Conflicts
Khi nhiều dependencies yêu cầu các phiên bản khác nhau của cùng một thư viện, bạn gặp phải xung đột version.
Chiến lược giải quyết của Maven:
- Nearest Definition: Sử dụng version gần nhất với dự án của bạn trong dependency tree
- First Declaration: Nếu cách đều, sử dụng version được khai báo đầu tiên
Chiến lược giải quyết của Gradle:
- Highest Version: Mặc định, sử dụng version cao nhất
Ép buộc Version Cụ thể (Maven):
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.3-jre</version>
</dependency>
</dependencies>
</dependencyManagement>Ép buộc Version Cụ thể (Gradle):
configurations.all {
resolutionStrategy {
force 'com.google.guava:guava:32.1.3-jre'
}
}Dependency Exclusions
Loại trừ transitive dependencies bạn không muốn:
Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Sử dụng Jetty thay thế -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>Gradle:
dependencies {
implementation('org.springframework.boot:spring-boot-starter-web') {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
}
implementation 'org.springframework.boot:spring-boot-starter-jetty'
}Bill of Materials (BOM)
BOM quản lý các version cho các dependencies liên quan:
Maven:
<dependencyManagement>
<dependencies>
<!-- Spring Boot BOM -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.2.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Version kế thừa từ BOM -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>Gradle:
dependencies {
// Import BOM
implementation platform('org.springframework.boot:spring-boot-dependencies:3.2.1')
// Version kế thừa từ BOM
implementation 'org.springframework.boot:spring-boot-starter-web'
}Dự Án Đa Module
Các dự án lớn thường được chia thành các modules để tổ chức tốt hơn.
Maven Multi-Module Project
Cấu trúc dự án:
my-app/
├── pom.xml # Parent POM
├── my-app-core/
│ └── pom.xml
├── my-app-api/
│ └── pom.xml
└── my-app-web/
└── pom.xmlParent POM (pom.xml):
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.chanhle</groupId>
<artifactId>my-app-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<!-- Modules -->
<modules>
<module>my-app-core</module>
<module>my-app-api</module>
<module>my-app-web</module>
</modules>
<!-- Common Properties -->
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
</properties>
<!-- Dependency Management for Children -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>Child Module POM (my-app-api/pom.xml):
<project>
<modelVersion>4.0.0</modelVersion>
<!-- Parent Reference -->
<parent>
<groupId>com.chanhle</groupId>
<artifactId>my-app-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>my-app-api</artifactId>
<dependencies>
<!-- Internal Dependency -->
<dependency>
<groupId>com.chanhle</groupId>
<artifactId>my-app-core</artifactId>
<version>${project.version}</version>
</dependency>
<!-- External Dependencies (version từ parent) -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>Build tất cả modules:
mvn clean install # Từ thư mục parent
mvn clean install -pl my-app-api # Build module cụ thểGradle Multi-Module Project
Cấu trúc dự án:
my-app/
├── build.gradle
├── settings.gradle # Khai báo subprojects
├── my-app-core/
│ └── build.gradle
├── my-app-api/
│ └── build.gradle
└── my-app-web/
└── build.gradlesettings.gradle:
rootProject.name = 'my-app'
include 'my-app-core', 'my-app-api', 'my-app-web'Root build.gradle:
plugins {
id 'java' apply false
}
subprojects {
apply plugin: 'java'
group = 'com.chanhle'
version = '1.0.0-SNAPSHOT'
repositories {
mavenCentral()
}
java {
sourceCompatibility = JavaVersion.VERSION_21
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1'
}
test {
useJUnitPlatform()
}
}Subproject build.gradle (my-app-api/build.gradle):
dependencies {
// Internal dependency
implementation project(':my-app-core')
// External dependencies
implementation 'org.springframework.boot:spring-boot-starter-web:3.2.1'
}Java 9+ Module System (JPMS)
Java Platform Module System (JPMS) cung cấp đóng gói mạnh mẽ hơn và dependencies rõ ràng.
module-info.java
Mỗi module có file module-info.java tại source root:
Cấu trúc dự án:
my-app/
└── src/main/java/
├── module-info.java # Module descriptor
└── com/chanhle/myapp/
└── Main.javamodule-info.java cơ bản:
module com.chanhle.myapp {
// Các modules mà module này phụ thuộc vào
requires java.base; // Ngầm định, tất cả modules yêu cầu điều này
requires java.sql; // Truy cập JDBC
requires com.google.gson; // Thư viện bên thứ ba
// Packages mà module này exports (làm public)
exports com.chanhle.myapp;
exports com.chanhle.myapp.api;
// Packages được export chỉ cho các modules cụ thể
exports com.chanhle.myapp.internal to com.chanhle.myapp.web;
// Mở packages cho reflection (ví dụ: cho frameworks)
opens com.chanhle.myapp.model to com.fasterxml.jackson.databind;
// Service provider interface
uses com.chanhle.myapp.spi.PluginService;
// Service implementation
provides com.chanhle.myapp.spi.PluginService
with com.chanhle.myapp.impl.DefaultPluginService;
}Module Directives
| Directive | Mô tả |
|---|---|
requires | Khai báo dependency vào module khác |
requires transitive | Transitive dependency (người gọi cũng có quyền truy cập) |
requires static | Optional dependency (chỉ compile-time) |
exports | Làm package public cho tất cả modules |
exports...to | Qualified export (chỉ cho modules cụ thể) |
opens | Cho phép truy cập reflection |
opens...to | Qualified opens |
uses | Khai báo service consumer |
provides...with | Khai báo service provider |
Automatic Modules
Các JAR không modular trên module path trở thành "automatic modules":
module com.chanhle.myapp {
// Tham chiếu automatic module bằng tên JAR
requires commons.lang3; // commons-lang3-3.12.0.jar → commons.lang3
}Best Practice: Sử dụng modular JARs khi có sẵn.
Ví dụ Module: Spring Boot
module-info.java cho Spring Boot app:
module com.chanhle.myapp {
requires spring.boot;
requires spring.boot.autoconfigure;
requires spring.web;
requires spring.context;
// Mở package cho component scanning của Spring
opens com.chanhle.myapp to spring.core, spring.beans, spring.context;
opens com.chanhle.myapp.controller to spring.core, spring.beans, spring.web;
// Export API packages
exports com.chanhle.myapp.api;
}Lưu ý: Nhiều frameworks (Spring, Hibernate) sử dụng reflection, yêu cầu directives opens.
Maven vs Gradle: So Sánh
| Tính năng | Maven | Gradle |
|---|---|---|
| Cấu hình | XML (verbose) | Groovy/Kotlin (ngắn gọn) |
| Hiệu suất | Chậm hơn | Nhanh hơn (incremental builds, caching) |
| Linh hoạt | Dựa trên convention | Rất linh hoạt |
| Đường cong học tập | Dễ hơn cho người mới | Ban đầu khó hơn |
| Tốc độ Build | Cơ bản | Nhanh hơn 2-10 lần |
| Incremental Builds | Hạn chế | Xuất sắc |
| Dependency Cache | Chỉ local | Local + remote |
| Multi-Module | Tốt | Xuất sắc |
| Android | Không hỗ trợ | Mặc định |
| Chấp nhận Doanh nghiệp | Rất cao | Tăng trưởng nhanh |
| Hỗ trợ IDE | Xuất sắc | Xuất sắc |
Khi Nào Sử Dụng Maven
- Sự quen thuộc của Team: Team biết Maven rất tốt
- Dự án đơn giản: Ứng dụng Java tiêu chuẩn
- Tiêu chuẩn công ty: Tổ chức bắt buộc Maven
- Hệ sinh thái trưởng thành: Thư viện plugin mở rộng
Khi Nào Sử Dụng Gradle
- Hiệu suất quan trọng: Codebase lớn cần builds nhanh
- Cần linh hoạt: Logic build phức tạp
- Đa ngôn ngữ: Dự án trộn Java, Kotlin, Groovy
- Android Development: Bắt buộc cho Android
- Cách tiếp cận hiện đại: Bắt đầu dự án greenfield mới
Tích Hợp Spring Boot
Cả Maven và Gradle đều có hỗ trợ Spring Boot xuất sắc.
Spring Boot với Maven
pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>Lệnh:
mvn spring-boot:run # Chạy ứng dụng
mvn package # Tạo JAR thực thi
java -jar target/my-app-1.0.0-SNAPSHOT.jar # Chạy JARSpring Boot với Gradle
build.gradle:
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.1'
id 'io.spring.dependency-management' version '1.1.4'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}Lệnh:
./gradlew bootRun # Chạy ứng dụng
./gradlew bootJar # Tạo JAR thực thi
java -jar build/libs/my-app-1.0.0-SNAPSHOT.jar # Chạy JARThiết Lập Dự Án Chuyên Nghiệp
Hãy tạo một dự án Java chuyên nghiệp từ đầu với các best practices.
1. Khởi tạo với Maven
mvn archetype:generate \
-DgroupId=com.chanhle \
-DartifactId=my-app \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.4 \
-DinteractiveMode=false
cd my-app2. Khởi tạo với Gradle
mkdir my-app && cd my-app
gradle init --type java-application --dsl kotlin --test-framework junit-jupiter3. Template pom.xml Chuyên Nghiệp
<?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>
<groupId>com.chanhle</groupId>
<artifactId>my-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>My Professional App</name>
<description>Production-ready Java application</description>
<url>https://github.com/yourusername/my-app</url>
<properties>
<!-- Java Version -->
<java.version>21</java.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Dependency Versions -->
<spring.boot.version>3.2.1</spring.boot.version>
<lombok.version>1.18.30</lombok.version>
<junit.version>5.10.1</junit.version>
<mockito.version>5.8.0</mockito.version>
<assertj.version>3.24.2</assertj.version>
<!-- Plugin Versions -->
<maven.compiler.plugin.version>3.11.0</maven.compiler.plugin.version>
<maven.surefire.plugin.version>3.2.3</maven.surefire.plugin.version>
<jacoco.version>0.8.11</jacoco.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>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Compiler -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<!-- Testing -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
</plugin>
<!-- Code Coverage -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</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>
<!-- Spring Boot Plugin -->
<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>
</plugins>
</build>
</project>4. Template build.gradle.kts Chuyên Nghiệp
plugins {
java
id("org.springframework.boot") version "3.2.1"
id("io.spring.dependency-management") version "1.1.4"
jacoco
}
group = "com.chanhle"
version = "1.0.0-SNAPSHOT"
java {
sourceCompatibility = JavaVersion.VERSION_21
}
configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
}
}
repositories {
mavenCentral()
}
dependencies {
// Spring Boot
implementation("org.springframework.boot:spring-boot-starter-web")
// Lombok
compileOnly("org.projectlombok:lombok")
annotationProcessor("org.projectlombok:lombok")
// Testing
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.assertj:assertj-core:3.24.2")
}
tasks.test {
useJUnitPlatform()
finalizedBy(tasks.jacocoTestReport)
}
tasks.jacocoTestReport {
dependsOn(tasks.test)
reports {
xml.required.set(true)
html.required.set(true)
}
}
tasks.bootJar {
archiveFileName.set("${project.name}-${project.version}.jar")
}Best Practices
1. Quản Lý Version
Sử dụng Properties/Variables:
<!-- Maven -->
<properties>
<spring.version>6.1.2</spring.version>
</properties>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>// Gradle
ext {
springVersion = '6.1.2'
}
dependencies {
implementation "org.springframework:spring-core:$springVersion"
}2. Dependency Locking
Maven Versions Plugin:
mvn versions:display-dependency-updates
mvn versions:use-latest-releasesGradle Dependency Locking:
./gradlew dependencies --write-locks3. Reproducible Builds
- Pin tất cả versions (không dùng
LATEST,RELEASE, hoặc version ranges) - Sử dụng dependency lock files
- Commit lock files vào version control
- Sử dụng Gradle wrapper (
gradlew) hoặc Maven wrapper
4. Tổ Chức Multi-Module
Cấu trúc enterprise điển hình:
my-app/
├── my-app-domain/ # Domain models
├── my-app-service/ # Business logic
├── my-app-repository/ # Data access
├── my-app-api/ # REST controllers
└── my-app-web/ # Web application5. Tránh Dependency Hell
- Sử dụng BOM để căn chỉnh version
- Loại trừ transitive dependencies gây xung đột
- Xem lại dependency tree thường xuyên
- Giữ dependencies cập nhật (security patches)
6. Quản Lý Repository
Sử dụng private repository (Nexus, Artifactory) cho:
- Builds nhanh hơn (cache local)
- Bảo mật (scan dependencies)
- Kiểm soát (chỉ các thư viện được phê duyệt)
- Độ tin cậy (mirrors của Maven Central)
Xử Lý Sự Cố Thường Gặp
Maven: Không Tìm Thấy Dependency
# Xóa cache local
rm -rf ~/.m2/repository
# Ép buộc cập nhật
mvn clean install -UGradle: Vấn Đề Build Cache
# Xóa build cache
./gradlew clean --no-build-cache
# Xóa global cache
rm -rf ~/.gradle/cachesVersion Conflicts
# Maven: Tìm các version xung đột
mvn dependency:tree -Dverbose
# Gradle: Tìm các version xung đột
./gradlew dependencyInsight --dependency guavaCác Bước Tiếp Theo
Bây giờ bạn đã có nền tảng vững chắc về các công cụ build Java! Để tiếp tục hành trình của bạn:
- Thực hành: Thiết lập dự án Spring Boot đa module
- Khám phá Plugins: Maven Shade, Gradle Shadow cho fat JARs
- Tích hợp CI/CD: GitHub Actions, Jenkins với Maven/Gradle
- Học Testing: Unit tests, integration tests, coverage reports
- Bảo mật Dependency: OWASP Dependency Check, Snyk
Trong bài viết tiếp theo, chúng ta sẽ đi sâu vào Java Testing với JUnit 5, Mockito, và AssertJ.
Thuộc series Lộ Trình Học Java
Quay lại: Giai Đoạn 3: Core Java APIs
Các Deep Dive Liên Quan:
- Java Collections Framework
- Streams & Lập Trình Hàm
- Exception Handling Best Practices
- Java Generics Giải Thích
Bước Tiếp Theo: Bắt Đầu Với Spring Boot
📬 Đăng ký nhận bản tin
Nhận những bài viết mới nhất qua email mỗi tuần. Không spam, hủy đăng ký bất cứ lúc nào.
Chúng tôi tôn trọng quyền riêng tư của bạn. Hủy đăng ký bất cứ lúc nào.
💬 Comments
Đăng nhập để bình luận
Chúng tôi sẽ không đăng bất cứ điều gì mà không có sự cho phép của bạn.