Giới thiệu
Nếu bạn đã làm việc với Spring Framework, chắc hẳn bạn đã từng trải nghiệm sức mạnh của lập trình hướng khía cạnh (AOP). AOP giúp bạn tách biệt các mối quan tâm chéo như ghi log, caching, bảo mật và quản lý giao dịch ra khỏi logic ứng dụng, giúp mã nguồn trở nên dễ bảo trì và đọc hiểu hơn.
Vậy nếu bạn có thể mang trải nghiệm AOP thanh lịch đó vào các ứng dụng NestJS của mình? Hãy cùng khám phá nestjs-saop – một thư viện mang AOP kiểu Spring vào hệ sinh thái NestJS với hỗ trợ TypeScript hoàn chỉnh.
nestjs-saop là gì?
nestjs-saop là thư viện AOP toàn diện cho NestJS, cung cấp:
- ✅ Tất cả các loại lời khuyên AOP: Tất cả 5 loại lời khuyên kiểu Spring (Around, Before, After, AfterReturning, AfterThrowing)
- ✅ Hỗ trợ TypeScript đầy đủ: Đảm bảo an toàn kiểu với generics và interfaces
- ✅ Tích hợp liền mạch với NestJS: Hoạt động hoàn hảo với hệ thống module của NestJS
- ✅ Mô hình Decorator: API dựa trên decorator quen thuộc và dễ tiếp cận
- ✅ Cấu hình linh hoạt: Tùy chỉnh cao với hỗ trợ các tùy chọn tùy chỉnh
Thiết lập nhanh
Cài đặt gói:
npm install nestjs-saop
Đăng ký module AOP trong ứng dụng của bạn:
typescript
import { AOPModule } from 'nestjs-saop';
@Module({
imports: [
AOPModule.forRoot(),
],
})
export class AppModule {}
Tạo Decorator AOP đầu tiên của bạn
Hãy cùng tạo một decorator để ghi log, thể hiện tất cả các loại lời khuyên AOP:
typescript
import { AOPDecorator, Aspect } from 'nestjs-saop';
@Aspect()
export class LoggingDecorator extends AOPDecorator {
around({ method, options }) {
return (...args: any[]) => {
console.log('🔄 Around: Trước khi thực thi phương thức');
const result = method.apply(this, args);
console.log('🔄 Around: Sau khi thực thi phương thức');
return result;
};
}
before({ method, options }) {
return (...args: any[]) => {
console.log('▶️ Before: Phương thức được gọi với', args);
};
}
after({ method, options }) {
return (...args: any[]) => {
console.log('⏹️ After: Phương thức đã hoàn thành');
};
}
afterReturning({ method, options, result }) {
return (...args: any[]) => {
console.log('✅ AfterReturning: Phương thức trả về', result);
};
}
afterThrowing({ method, options, error }) {
return (...args: any[]) => {
console.error('❌ AfterThrowing: Phương thức ném ra lỗi', error.message);
};
}
}
Đăng ký decorator của bạn như một provider:
typescript
@Module({
providers: [LoggingDecorator],
})
export class AppModule {}
Ví dụ thực tế
1. Decorator Caching thông minh
typescript
@Aspect()
export class CachingDecorator extends AOPDecorator {
private cache = new Map();
around({ method, options }) {
return (...args: any[]) => {
const key = `${method.name}:${JSON.stringify(args)}`;
// Cache hit
if (this.cache.has(key)) {
console.log('💡 Cache hit!');
return this.cache.get(key);
}
// Cache miss - thực thi phương thức
console.log('💭 Cache miss, đang thực thi phương thức...');
const result = method.apply(this, args);
// Lưu vào cache với TTL
this.cache.set(key, result);
if (options.ttl) {
setTimeout(() => this.cache.delete(key), options.ttl);
}
return result;
};
}
}
// Sử dụng
@Injectable()
export class UserService {
@CachingDecorator.around({ ttl: 300000 }) // 5 phút
async getUserById(id: string): Promise<User> {
return await this.userRepository.findById(id);
}
}
2. Giám sát hiệu suất
typescript
@Aspect()
export class PerformanceDecorator extends AOPDecorator {
around({ method, options }) {
return (...args: any[]) => {
const start = Date.now();
try {
const result = method.apply(this, args);
const duration = Date.now() - start;
if (duration > options.threshold) {
console.warn(`⚠️ Phương thức chậm phát hiện: ${method.name} (${duration}ms)`);
}
return result;
} catch (error) {
const duration = Date.now() - start;
console.error(`💥 Phương thức thất bại: ${method.name} (${duration}ms)`);
throw error;
}
};
}
}
// Sử dụng
@Injectable()
export class DataService {
@PerformanceDecorator.around({ threshold: 1000 })
async processLargeDataset(data: any[]): Promise<ProcessedData> {
// Hoạt động tốn kém của bạn ở đây
return await this.complexProcessing(data);
}
}
3. Xử lý lỗi với logic thử lại
typescript
@Aspect()
export class RetryDecorator extends AOPDecorator {
afterThrowing({ method, options, error }) {
return (...args: any[]) => {
console.error(`🔄 Phương thức ${method.name} thất bại:`, error.message);
if (options.retryCount < options.maxRetries) {
console.log(`🔄 Đang thử lại... (${options.retryCount + 1}/${options.maxRetries})`);
// Thực hiện exponential backoff
const delay = Math.pow(2, options.retryCount) * 1000;
setTimeout(() => {
// Logic thử lại ở đây
method.apply(this, args);
}, delay);
}
};
}
}
// Sử dụng
@Injectable()
export class ApiService {
@RetryDecorator.afterThrowing({ maxRetries: 3, retryCount: 0 })
async callExternalAPI(endpoint: string): Promise<any> {
const response = await fetch(endpoint);
if (!response.ok) {
throw new Error(`API call failed: ${response.status}`);
}
return response.json();
}
}
Sức mạnh của TypeScript 💪
Một trong những tính năng mạnh mẽ nhất của nestjs-saop chính là hỗ trợ TypeScript hoàn chỉnh. Định nghĩa các loại tùy chọn tùy chỉnh để cải thiện trải nghiệm lập trình viên:
typescript
interface LoggingOptions {
level: 'debug' | 'info' | 'warn' | 'error';
includeTimestamp: boolean;
logArgs: boolean;
}
@Aspect()
export class TypedLoggingDecorator extends AOPDecorator<LoggingOptions> {
before({ method, options }) {
return (...args: any[]) => {
const timestamp = options.includeTimestamp
? `[${new Date().toISOString()}] `
: '';
const argsLog = options.logArgs
? ` với args: ${JSON.stringify(args)}`
: '';
console.log(
`${timestamp}${options.level.toUpperCase()}: ${method.name}${argsLog}`
);
};
}
}
// Sử dụng với an toàn kiểu hoàn toàn
@Injectable()
export class UserService {
@TypedLoggingDecorator.before({
level: 'info', // ✅ An toàn kiểu
includeTimestamp: true, // ✅ An toàn kiểu
logArgs: false // ✅ An toàn kiểu
})
async createUser(userData: CreateUserDto): Promise<User> {
return await this.userRepository.create(userData);
}
}
Kết hợp nhiều Decorators
Bạn có thể xếp chồng nhiều decorators trên một phương thức để tạo ra những sự kết hợp mạnh mẽ:
typescript
@Injectable()
export class PaymentService {
@LoggingDecorator.before({ level: 'info', logArgs: true })
@PerformanceDecorator.around({ threshold: 2000 })
@CachingDecorator.around({ ttl: 60000 })
@RetryDecorator.afterThrowing({ maxRetries: 3 })
async processPayment(paymentData: PaymentDto): Promise<PaymentResult> {
// Phương thức này được cải tiến với:
// 1. Ghi log trước khi thực thi
// 2. Giám sát hiệu suất
// 3. Khả năng caching
// 4. Tự động thử lại khi thất bại
return await this.paymentGateway.process(paymentData);
}
}
Thứ tự thực thi AOP
Các loại lời khuyên thực thi theo thứ tự cụ thể này:
- 🔄 Around (trước khi phương thức thực thi)
- ▶️ Before
- Thực thi phương thức
- ⏹️ After
- ✅ AfterReturning HOẶC ❌ AfterThrowing
- 🔄 Around (sau khi phương thức thực thi)
Kết luận
Thư viện nestjs-saop mang sức mạnh và sự thanh lịch của AOP kiểu Spring vào hệ sinh thái NestJS. Dù bạn cần ghi log, caching, giám sát hiệu suất hay xử lý lỗi, thư viện này giúp bạn triển khai các mối quan tâm chéo một cách sạch sẽ và hiệu quả.
Sự kết hợp giữa cú pháp kiểu Spring quen thuộc, hỗ trợ TypeScript hoàn chỉnh và tích hợp liền mạch với NestJS khiến đây là lựa chọn hoàn hảo để xây dựng các ứng dụng doanh nghiệp dễ bảo trì.
Hãy thử nghiệm nó trong dự án NestJS tiếp theo của bạn – mã nguồn của bạn sẽ cảm ơn bạn! 🚀
📚 Tài nguyên:
- Kho lưu trữ GitHub
- Gói npm
- Tài liệu hướng dẫn
Bạn đã có kinh nghiệm gì về AOP trong phát triển backend chưa? Bạn đã thử triển khai các mối quan tâm chéo trong NestJS chưa? Hãy chia sẻ suy nghĩ của bạn trong phần bình luận bên dưới! 💬