Tách biệt Entity vào Thư viện riêng trên GitHub Packages (AI Writing)
Mô-đun hóa Spring Boot:
Bài viết này hướng dẫn kiến trúc tách các logic nghiệp vụ dùng chung (Entities, Enums, Repositories) thành một thư viện độc lập, đẩy nó lên GitHub Artifact Registry (chế độ Private), và sử dụng lại trong các Microservice Spring Boot khác.
🏗 Tổng quan Kiến trúc
Mục tiêu là tách biệt Tầng dữ liệu (Data Layer) khỏi Tầng dịch vụ (Service Layer).
- Bên thư viện (package
com.demo.lib): Chứa Entities, Enums, và Repositories. Đóng gói thành file JAR và đẩy lên GitHub Packages. - Bên ứng dụng (package
com.demo.app): Ứng dụng Spring Boot chính. Khai báo thư viện trên làm dependency và quét (scan) để nhận diện các Bean.
Phần 1: Tạo Thư viện Chung (com.demo.lib)
Dự án này là một thư viện (library), không phải là một ứng dụng chạy độc lập.
1. Cấu hình Maven (pom.xml)
Chúng ta cần cấu hình 2 điểm quan trọng:
- Distribution Management: Chỉ định nơi upload gói thư viện (GitHub Packages).
- Build Plugin: Tắt tính năng
repackagecủa Spring Boot (để nó không biến thành file executable JAR, giữ nguyên cấu trúc thư viện).
<groupId>com.demo</groupId>
<artifactId>shared-library</artifactId>
<version>1.0.0</version>
<distributionManagement>
<repository>
<id>github</id> <name>GitHub Packages</name>
<url>https://maven.pkg.github.com/USERNAME_GITHUB_CUA_BAN/TEN_REPO_THU_VIEN</url>
</repository>
</distributionManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip> </configuration>
</plugin>
</plugins>
</build>
2. CI/CD cho Thư viện: Tự động Deploy
File: .github/workflows/deploy.yml
name: Publish Library
on:
push:
branches: [ "main" ]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # BẮT BUỘC: Cho phép ghi/upload vào registry
steps:
- name: Checkout Code
uses: actions/checkout@v4
# 1. Cài đặt Java và Tự động tạo file settings.xml
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
server-id: github # Phải khớp với thẻ <id> trong pom.xml
settings-path: ${{ github.workspace }}
# 2. Deploy sử dụng file settings vừa tạo
- name: Publish to GitHub Packages
run: mvn deploy -s ${{ github.workspace }}/settings.xml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
💡 Phân tích Kỹ thuật (Deep Dive): Quy trình Publish
Hỏi: Chúng ta có cần tạo Personal Access Token (PAT) để upload thư viện không? Đáp: Không. Bạn không cần PAT để upload lên registry của chính repository đó. Token mặc định
${{ secrets.GITHUB_TOKEN }}là đủ, miễn là bạn đã khai báo quyềnpermissions: packages: writetrong file YAML. Điều này nâng cấp quyền cho token mặc định để nó có thể ghi dữ liệu.Hỏi:
actions/setup-javacó tự động tạosettings.xmlkhông? Đáp: Có, nhưng chỉ khi bạn khai báoserver-id. Nếu bạn bỏ quaserver-id, action chỉ cài Java mà không tạo file settings. Khi bạn khai báoserver-id: github, nó sẽ sinh ra filesettings.xmlđã được cấu hình sẵn để tìm mật khẩu từ biến môi trường.Hỏi: Tại sao phải có dòng
env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}? Đáp: Để điền giá trị vào filesettings.xml.setup-javatạo ra file settings chứa thẻ<password>${env.GITHUB_TOKEN}</password>. Nó không điền cứng (hardcode) mã bí mật vào file. Do đó, bạn phải đẩy secret vào biến môi trường (environment variable) để Maven có thể đọc được khi chạy lệnh.
Phần 2: Ứng dụng (com.demo.app)
1. Xác thực
Repository của App (người dùng) không thể đọc Repository của Lib (thư viện) bằng token mặc định vì lý do bảo mật (khác repo).
- Tạo PAT (Personal Access Token): Vào GitHub Profile → Settings → Developer Settings → Tokens (Classic). Chọn quyền (scope):
read:packages. - Thêm Secret: Vào Repository của App → Settings → Secrets → Actions. Thêm secret tên là
PACKAGES_READ_TOKENvà dán mã PAT vừa tạo vào.
2. Cấu hình Spring Boot (QUAN TRỌNG)
Mặc định, Spring Boot chỉ quét (scan) các file trong cùng package với App chính (com.demo.app). Nó sẽ bỏ qua các entity trong thư viện (com.demo.lib) nếu bạn không chỉ định rõ.
Application.java
package com.demo.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
@EntityScan(basePackages = {
"com.demo.app", // Quét trong app hiện tại
"com.demo.lib.domain" // Quét thêm entity trong thư viện
})
@EnableJpaRepositories(basePackages = {
"com.demo.app", // Quét trong app hiện tại
"com.demo.lib.repository" // Quét thêm repository trong thư viện
})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
3. CI/CD cho App: Build với thông tin xác thực
File: .github/workflows/build-app.yml
name: Build App
on: [push]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
server-id: github
settings-path: ${{ github.workspace }}
- name: Build with Maven
run: mvn clean package -s ${{ github.workspace }}/settings.xml
env:
# THAY ĐỔI LOGIC: Chúng ta ánh xạ PAT của mình vào biến môi trường này
GITHUB_TOKEN: ${{ secrets.PACKAGES_READ_TOKEN }}
💡 Phân tích Kỹ thuật (Deep Dive): Quy trình Tiêu thụ (Consumption)
Hỏi: Tại sao chúng ta lại tráo đổi Token ở bước Build App? Đáp: Token mặc định
GITHUB_TOKENcó phạm vi giới hạn trong Repository hiện tại. Nó giống như thẻ từ chỉ mở được cửa phòng làm việc của App chứ không mở được kho chứa của Library. Để giải quyết, chúng ta dùng Personal Access Token (PAT) (được lưu trongPACKAGES_READ_TOKEN), đại diện cho một người dùng có quyền truy cập vào cả hai repository.Hỏi: Việc ánh xạ (mapping) hoạt động như thế nào? Đáp:
setup-javatạo ra filesettings.xmlvà mong chờ mật khẩu nằm trong biến${env.GITHUB_TOKEN}.- Trong khối
env:, chúng ta khai báo:GITHUB_TOKEN: ${{ secrets.PACKAGES_READ_TOKEN }}.- Điều này "đánh lừa" Maven: Nó tìm biến "GITHUB_TOKEN" theo cấu hình, nhưng thực tế lại nhận được giá trị PAT của bạn, từ đó có quyền tải thư viện private về.
Tóm tắt & Checklist
| Thành phần | Yêu cầu chính | Lý do |
|---|---|---|
| Library POM | distributionManagement + <repository> |
Chỉ cho Maven biết nơi upload file JAR. |
| Library POM | spring-boot-maven-plugin -> skip: true |
Ngăn chặn đóng gói dạng executable (để giữ dạng thư viện). |
| Library Workflow | permissions: packages: write |
Cấp quyền upload cho token mặc định. |
| App POM | Thẻ <repository> |
Chỉ cho Maven biết nơi tìm dependency private. |
| App Java | @EntityScan, @EnableJpaRepositories |
Bắt buộc Spring quét package com.demo.lib. |
| App Workflow | GITHUB_TOKEN: ${{ secrets.PACKAGES_READ_TOKEN }} |
Dùng PAT để xác thực chéo giữa các repository. |
All rights reserved