Skip to main content

Command Palette

Search for a command to run...

Bài 3: Annotation trong Lập trình AOP (Aspect-Oriented Programming)

Published
5 min readView as Markdown

1. Giới thiệu về AOP (Aspect-Oriented Programming)

AOP là một mô hình lập trình bổ sung cho lập trình hướng đối tượng (OOP). Trong OOP, chúng ta tổ chức mã nguồn theo các lớp và đối tượng, trong khi đó, AOP giúp tách biệt các mối quan tâm ngang (cross-cutting concerns) ra khỏi mã nguồn chính, chẳng hạn như logging, transaction management, security, v.v.

1.1. AOP là gì?

AOP cho phép bạn mô tả các hành vi mà bạn muốn áp dụng ở nhiều nơi trong ứng dụng mà không cần phải thay đổi mã nguồn của các thành phần đó. Điều này đạt được bằng cách sử dụng các "aspect" (khía cạnh) để đóng gói các mối quan tâm ngang và áp dụng chúng một cách tự động.

1.2. Tại sao cần AOP?

AOP rất hữu ích trong việc tách biệt các mối quan tâm ngang, giúp mã nguồn sạch sẽ, dễ bảo trì và giảm thiểu sự trùng lặp. Các trường hợp sử dụng phổ biến của AOP bao gồm logging, bảo mật, quản lý giao dịch, và xử lý lỗi.

2. Spring AOP với Annotation

Spring AOP là một phần của Spring Framework cung cấp các tính năng AOP. Nó sử dụng Proxy-based AOP, trong đó các proxy được tạo động để áp dụng các aspect vào đối tượng đích.

2.1. Các Annotation AOP trong Spring
  • @Aspect: Đánh dấu một lớp là aspect.

  • @Before: Chạy phương thức advice trước khi phương thức mục tiêu được thực thi.

  • @After: Chạy phương thức advice sau khi phương thức mục tiêu hoàn thành.

  • @AfterReturning: Chạy phương thức advice sau khi phương thức mục tiêu trả về kết quả.

  • @AfterThrowing: Chạy phương thức advice sau khi phương thức mục tiêu ném ra ngoại lệ.

  • @Around: Chạy phương thức advice xung quanh phương thức mục tiêu.

2.2. Cách cấu hình Spring AOP

Để sử dụng Spring AOP, trước tiên bạn cần thêm các thư viện cần thiết vào dự án của bạn. Nếu bạn đang sử dụng Maven, thêm các dependency sau vào pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

Sau đó, bật hỗ trợ AOP trong ứng dụng của bạn bằng cách sử dụng annotation @EnableAspectJAutoProxy trong lớp cấu hình chính:

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}

3. Ví dụ về Spring AOP với Annotation

3.1. Tạo Aspect với Annotation

Giả sử chúng ta muốn log thông tin trước khi thực thi bất kỳ phương thức nào trong một lớp dịch vụ.

3.1.1. Định nghĩa Aspect
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {
    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);

    @Before("execution(* com.example.service.*.*(..))")
    public void logBeforeMethodExecution() {
        logger.info("A method is about to be executed.");
    }
}
3.1.2. Giải thích:
  • @Aspect: Đánh dấu lớp này là một aspect.

  • @Component: Đăng ký lớp này như một bean trong Spring container.

  • @Before("execution(* com.example.service..(..))"): Định nghĩa một pointcut và advice. Pointcut execution(* com.example.service.*.*(..)) chỉ ra rằng advice này sẽ được áp dụng cho tất cả các phương thức trong gói com.example.service.

3.2. Tạo Service để áp dụng Aspect
import org.springframework.stereotype.Service;

@Service
public class MyService {
    public void performTask() {
        System.out.println("Performing task");
    }
}
3.3. Cấu hình ứng dụng
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class AopDemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(AopDemoApplication.class, args);
        MyService myService = context.getBean(MyService.class);
        myService.performTask();
    }
}

4. Các loại Advice trong Spring AOP

4.1. @Before

Advice được thực thi trước khi phương thức mục tiêu được gọi.

@Before("execution(* com.example.service.*.*(..))")
public void logBeforeMethodExecution() {
    logger.info("A method is about to be executed.");
}
4.2. @After

Advice được thực thi sau khi phương thức mục tiêu hoàn thành.

@After("execution(* com.example.service.*.*(..))")
public void logAfterMethodExecution() {
    logger.info("A method has been executed.");
}
4.3. @AfterReturning

Advice được thực thi sau khi phương thức mục tiêu trả về kết quả.

@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
public void logAfterReturning(Object result) {
    logger.info("Method returned with result: " + result);
}
4.4. @AfterThrowing

Advice được thực thi sau khi phương thức mục tiêu ném ra ngoại lệ.

@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "error")
public void logAfterThrowing(Throwable error) {
    logger.error("Method threw an exception: ", error);
}
4.5. @Around

Advice được thực thi xung quanh phương thức mục tiêu, cho phép kiểm soát toàn bộ quá trình thực thi của phương thức.

@Around("execution(* com.example.service.*.*(..))")
public Object logAroundMethodExecution(ProceedingJoinPoint joinPoint) throws Throwable {
    logger.info("Method execution starts: " + joinPoint.getSignature());
    Object result = joinPoint.proceed(); // Tiếp tục thực thi phương thức mục tiêu
    logger.info("Method execution ends: " + joinPoint.getSignature());
    return result;
}

Tổng kết

Trong bài viết này, chúng ta đã tìm hiểu về lập trình hướng khía cạnh (AOP) trong Spring Framework, cách sử dụng các annotation để tạo các aspect và áp dụng các advice cho phương thức mục tiêu. Chúng ta đã thấy cách cấu hình và triển khai AOP trong một ứng dụng Spring, cùng với các ví dụ thực tế minh họa. Bài viết tiếp theo sẽ tập trung vào việc sử dụng Annotation trong Hibernate và JPA để quản lý các thực thể (entity) và ánh xạ (mapping) chúng tới cơ sở dữ liệu.

More from this blog

devngu

169 posts