Thiết kế Microservices Sạch, Mở Rộng: Hiểu Các Loại Lớp Trong Thiết Kế Thấp
Khi chúng ta chuyển từ thiết kế cấp cao (HLD) đến thiết kế cấp thấp (LLD), công việc kỹ thuật thực sự bắt đầu. LLD là nơi bạn quyết định cách mỗi mô-đun, lớp và phương thức tương tác để cung cấp một hệ thống vững chắc. Một microservice sạch sẽ và dễ bảo trì bắt đầu với việc xác định rõ ràng trách nhiệm của lớp.
Trong các ứng dụng Java và Spring Boot, các lớp thường rơi vào một tập hợp các loại đã được hiểu rõ. Bài viết này sẽ khám phá các loại này—Entity, Manager/Service, Repository, Controller, DTO/VO, Utility, Factory/Builder, và Configuration—cùng với các thực tiễn tốt nhất và ví dụ mà bạn có thể áp dụng ngay lập tức.
1️⃣ Lớp Entity / Domain: Trái Tim Của Mô Hình
Mục đích
Các Entity đại diện cho các đối tượng kinh doanh cốt lõi của bạn. Chúng là danh từ của miền—User, Order, Invoice.
Đặc điểm
- Thường được chú thích với
@Entitykhi sử dụng JPA/Hibernate. - Chứa các trường và mối quan hệ phản ánh cấu trúc cơ sở dữ liệu của bạn.
- Bao gồm logic miền (ví dụ:
order.calculateTotal()), nhưng không bao giờ xử lý sự bền vững trực tiếp.
java
@Entity
public class Order {
@Id @GeneratedValue
private Long id;
@OneToMany(cascade = CascadeType.ALL)
private List<OrderItem> items = new ArrayList<>();
public BigDecimal totalAmount() {
return items.stream()\n .map(OrderItem::amount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
Thực tiễn tốt nhất
- Tuân thủ Thiết Kế Hướng Miền (DDD): mô hình miền phong phú, các bất biến có ý nghĩa.
- Ưu tiên các Giá Trị Đối Tượng không thay đổi (ví dụ:
Money,Address) cho các khái niệm nhỏ, tự chứa.
2️⃣ Lớp Manager / Service: Các Nhà Tổ Chức Kinh Doanh
Mục đích
Dịch vụ (thường được gọi là Managers trong các mã nguồn cũ) thực hiện các trường hợp sử dụng và phối hợp nhiều thực thể và hệ thống bên ngoài.
Điểm chính
- Được chú thích với
@Service. - Xác định ranh giới giao dịch bằng cách sử dụng
@Transactional. - Chứa các quy trình và kiểm tra kinh doanh.
java
@Service
public class OrderService {
private final OrderRepository repository;
private final PaymentGateway paymentGateway;
public OrderService(OrderRepository repository, PaymentGateway paymentGateway) {
this.repository = repository;
this.paymentGateway = paymentGateway;
}
@Transactional
public Order placeOrder(OrderRequest request) {
Order order = new Order(request.items());
paymentGateway.charge(order.totalAmount());
return repository.save(order);
}
}
Thực tiễn tốt nhất
- Tuân thủ Nguyên Tắc Trách Nhiệm Đơn—mỗi dịch vụ chỉ nên bao gồm một khả năng liên kết.
- Tránh các phương thức CRUD tầm thường ở đây; ủy quyền chúng cho các kho lưu trữ.
3️⃣ Lớp Repository / DAO: Cổng Kiểm Soát Dữ Liệu
Các Repository trừu tượng hóa quyền truy cập cơ sở dữ liệu để các dịch vụ không bao giờ chạm vào SQL hoặc chi tiết ORM.
- Được chú thích với
@Repositoryhoặc tạo ra qua các giao diện Spring Data. - Cung cấp các phương thức đơn giản, rõ ràng về ý định:
java
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByCustomerId(Long customerId);
}
4️⃣ Lớp Controller / Resource: Điểm Nhập API
Các Controller mở rộng microservice của bạn ra thế giới bên ngoài—REST, gRPC, hoặc GraphQL.
java
@RestController
@RequestMapping("/orders")
public class OrderController {
private final OrderService service;
public OrderController(OrderService service) { this.service = service; }
@PostMapping
public ResponseEntity<OrderDto> place(@Valid @RequestBody OrderRequest request) {
Order order = service.placeOrder(request);
return ResponseEntity.ok(OrderDto.from(order));
}
}
Hướng dẫn
- Các Controller chỉ xử lý các mối quan tâm về HTTP: phân tích yêu cầu, xác thực, và định dạng phản hồi.
- Ủy quyền logic kinh doanh cho các dịch vụ.
- Ánh xạ các ngoại lệ đến các mã trạng thái thích hợp với
@ControllerAdvice.
5️⃣ DTO, VO, và Mappers: Ranh Giới Dữ Liệu Sạch
- DTO (Data Transfer Object): Đại diện cho các tải trọng cho REST hoặc các cuộc gọi giữa các dịch vụ. Ví dụ:
OrderRequest,OrderResponseDto. - VO (Value Object): Các giá trị miền không thay đổi như
MoneyhoặcCoordinates. - Mapper: Chuyển đổi giữa Entity và DTO. Các công cụ như MapStruct tự động hóa điều này.
java
public record OrderDto(Long id, BigDecimal total) {
public static OrderDto from(Order order) {
return new OrderDto(order.getId(), order.totalAmount());
}
}
6️⃣ Lớp Utility / Helper: Tính Tái Sử Dụng Tinh Khiết
Các lớp Utility bao gồm logic trợ giúp không trạng thái—định dạng ngày, làm sạch chuỗi, v.v.
- Nên được khai báo là final với một constructor riêng tư.
- Chứa chỉ các phương thức tĩnh.
java
public final class DateTimeUtils {
private DateTimeUtils() {}
public static LocalDate todayUtc() { return LocalDate.now(ZoneOffset.UTC); }
}
7️⃣ Lớp Factory và Builder: Tạo Đối Tượng Kiểm Soát
Việc tạo đối tượng phức tạp thuộc về một factory hoặc builder chuyên dụng.
- Factory:
PaymentFactory.createPayment(...)tập trung hóa logic tạo. - Builder: Hữu ích cho các đối tượng không thay đổi với nhiều trường tùy chọn.
java
Order order = Order.builder()
.customerId(123L)
.addItem(item1)
.addItem(item2)
.build();
8️⃣ Lớp Cấu Hình & Hạ Tầng: Hệ Thống Cung Cấp
Các lớp này kết nối các mối quan tâm cắt ngang:
@Configurationcủa Spring cho các bean.- Bảo mật, bộ nhớ đệm, cấu hình nhắn tin (Kafka, RabbitMQ).
- Bộ điều hợp dịch vụ bên ngoài:
EmailGateway,PaymentClient.
java
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("orders");
}
}
Cấu Trúc Gói Đề Xuất
Một microservice sạch sẽ thường tuân theo cấu trúc này:
java
com.example.orderservice
├─ controller // Các điểm cuối REST
├─ service // Logic kinh doanh
├─ repository // Các kho lưu trữ JPA
├─ domain/entity // Các Entity & Giá Trị Đối Tượng
├─ dto // DTO yêu cầu/phản hồi
├─ mapper // Chuyển đổi DTO ↔ Entity
├─ config // Các lớp cấu hình Spring
└─ util // Các lớp Utility
Sự phân tách này khiến các phụ thuộc rõ ràng và mã dễ dàng điều hướng.
Các Nguyên Tắc Thiết Kế Chính Cần Nhớ
- Nguyên Tắc Trách Nhiệm Đơn – mỗi lớp chỉ thay đổi vì một lý do.
- Đảo Ngược Phụ Thuộc – các mô-đun cấp cao phụ thuộc vào các giao diện, không phải các lớp cụ thể.
- Thiết Kế Hướng Miền – phân tách các lớp Miền, Ứng Dụng, và Hạ Tầng.
- Khả Năng Kiểm Tra – giữ cho các lớp nhỏ và tập trung để bạn có thể kiểm tra chúng một cách độc lập.
Kết Luận
Trong LLD, phân loại lớp rõ ràng không chỉ là thẩm mỹ—nó liên quan đến khả năng mở rộng, bảo trì, và tốc độ lâu dài. Bằng cách tôn trọng các loại lớp này và trách nhiệm của chúng, bạn tạo ra các microservice dễ dàng mở rộng, tái cấu trúc và kiểm tra.
Dù bạn đang xây dựng một API nội bộ nhỏ hay một hệ thống phân tán lớn, những nguyên tắc này sẽ giúp bạn cung cấp phần mềm Java/Spring Boot sạch, có thể mở rộng và dễ bảo trì với độ chính xác kỹ thuật.
Chúc bạn thiết kế thành công!