Backend

99 Ngày Java — Ngày 86: Maven

SSite Admin
21 tháng 10, 2026 3 phút đọc 4 lượt xem
99 Ngày Java — Ngày 86: Maven

Một dự án Java thật có hàng chục thư viện, mỗi thư viện lại kéo theo thư viện khác. Maven giải quyết hai việc: mô tả dự án cùng phụ thuộc trong một file pom.xml, và chạy build theo một vòng đời cố định mà mọi dự án đều tuân theo. Hiểu bốn khái niệm tọa độ, scope, lifecycle và BOM là đủ để đọc gần như mọi POM.

Maven

1. POM và tọa độ

Mỗi artifact được định danh bằng ba giá trị: groupId, artifactId và version. Maven dùng bộ ba này để tải thư viện từ Maven Central về kho cục bộ ~/.m2. Dự án theo cấu trúc quy ước: mã nguồn ở src/main/java, test ở src/test/java, tài nguyên ở src/main/resources. Thuộc tính maven.compiler.release bảo đảm bytecode và API đều đúng phiên bản Java đích.

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>vn.motdev</groupId>
  <artifactId>orders</artifactId>
  <version>1.0.0</version>

  <properties>
    <maven.compiler.release>21</maven.compiler.release>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
</project>

2. Dependency scope

Scope quyết định thư viện có mặt ở classpath nào. compile là mặc định: có ở mọi nơi và được đóng gói. provided có lúc biên dịch nhưng môi trường chạy tự cung cấp, ví dụ Servlet API. runtime không cần lúc biên dịch, ví dụ driver JDBC. test chỉ có khi biên dịch và chạy test. Chọn sai scope thường không gây lỗi ngay mà làm gói phình to hoặc thiếu lớp lúc chạy.

<dependencies>
  <dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.7.4</version>
    <scope>runtime</scope>
  </dependency>
  <dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.11.3</version>
    <scope>test</scope>
  </dependency>
</dependencies>

3. Phụ thuộc bắc cầu và xung đột phiên bản

Khai báo một thư viện là kéo theo cả cây phụ thuộc của nó. Khi hai nhánh cần hai phiên bản khác nhau của cùng một artifact, Maven chọn phiên bản gần gốc cây nhất, không phải phiên bản mới nhất. Kết quả có thể là một phiên bản cũ thiếu phương thức mà thư viện khác cần, và lỗi NoSuchMethodError chỉ xuất hiện lúc chạy. Lệnh dependency:tree cho thấy chính xác phiên bản nào thắng và vì sao.

./mvnw dependency:tree -Dincludes=com.fasterxml.jackson.core
./mvnw dependency:analyze   # declared but unused, used but undeclared

4. Lifecycle và BOM

Vòng đời mặc định gồm các phase theo thứ tự: validate, compile, test, package, verify, install, deploy. Gọi một phase là chạy mọi phase đứng trước nó. Plugin gắn goal vào phase; đó là nơi công việc thật sự diễn ra. BOM là một POM chỉ chứa phiên bản: import nó vào dependencyManagement thì các dependency cùng họ không cần ghi version nữa và luôn khớp nhau.

  • Dùng Maven Wrapper (./mvnw) để cả đội và CI build cùng một phiên bản Maven.

  • mvn verify là lệnh kiểm tra đầy đủ trước khi đẩy code; install chỉ cần khi dự án khác trên máy dùng artifact này.

  • Không ghi version rải rác: gom vào BOM hoặc properties.

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.junit</groupId>
      <artifactId>junit-bom</artifactId>
      <version>5.11.3</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

Maven đổi sự linh hoạt lấy tính dự đoán được: ai đọc POM cũng biết build chạy thế nào. Ngày 87 xem lựa chọn còn lại, Gradle.

Tài liệu đối chiếu

  • https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html

  • https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html

S

Site Admin

Engineer and writer. Building things with TypeScript and distributed systems.

Bình luận (0)

Bạn cần đăng nhập bằng Google để bình luận.

Hãy là người bình luận đầu tiên.

Bài viết liên quan

99 Ngày Spring — Ngày 86: gRPC với Spring

File proto là hợp đồng, stub sinh tự động, status code và deadline, cùng tiêu chí chọn gRPC hay REST.

21 thg 10, 20263 phút5
99 Ngày Spring — Ngày 85: GraphQL với Spring

Schema-first, @QueryMapping và @MutationMapping, bài toán N+1 với @BatchMapping và những giới hạn cần đặt cho production.

20 thg 10, 20263 phút5
99 Ngày Java — Ngày 85: Module System (JPMS)

module-info.java, requires và exports, strong encapsulation, opens cho reflection, jlink và khi nào nên dùng module.

20 thg 10, 20263 phút4