0

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).

  1. 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.
  2. 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:

  1. Distribution Management: Chỉ định nơi upload gói thư viện (GitHub Packages).
  2. Build Plugin: Tắt tính năng repackage của Spring Boot (để nó không biến thành file executable JAR, giữ nguyên cấu trúc thư viện).
<!-- end list -->
<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ền permissions: packages: write trong 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-java có tự động tạo settings.xml không? Đáp: Có, nhưng chỉ khi bạn khai báo server-id. Nếu bạn bỏ qua server-id, action chỉ cài Java mà không tạo file settings. Khi bạn khai báo server-id: github, nó sẽ sinh ra file settings.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 file settings.xml. setup-java tạ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).

  1. Tạo PAT (Personal Access Token): Vào GitHub Profile → Settings → Developer Settings → Tokens (Classic). Chọn quyền (scope): read:packages.
  2. Thêm Secret: Vào Repository của App → Settings → Secrets → Actions. Thêm secret tên là PACKAGES_READ_TOKEN và 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_TOKEN có 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 trong PACKAGES_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:

  1. setup-java tạo ra file settings.xml và mong chờ mật khẩu nằm trong biến ${env.GITHUB_TOKEN}.
  2. Trong khối env:, chúng ta khai báo: GITHUB_TOKEN: ${{ secrets.PACKAGES_READ_TOKEN }}.
  3. Đ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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí