AOP부터 트랜잭션 관리까지: Spring AOP 문제 풀이로 배우기

1. Spring AOP 기본 개념 문제

 

문제: 아래의 코드에서 @Before 어노테이션을 사용하여 Service 클래스의 performTask() 메서드가 호출되기 전에 “메서드가 시작됩니다.“라는 메시지를 출력하도록 AOP 설정을 추가하세요.

@Service
public class Service {
    public void performTask() {
        System.out.println("작업을 수행 중...");
    }
}

 

풀이:

 

@Before 어드바이스를 사용해 performTask() 메서드 실행 전에 메시지를 출력하는 AOP 설정을 추가합니다.

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.Service.performTask(..))")
    public void logBefore() {
        System.out.println("메서드가 시작됩니다.");
    }
}

 

@Aspect@Before를 사용하여 메서드가 실행되기 전에 지정한 코드를 실행합니다.

execution(* com.example.Service.performTask(..))performTask() 메서드를 지정하는 포인트컷입니다.

 

2. AOP와 트랜잭션 관리 문제

 

문제: @Transactional 어노테이션을 사용하여 UserServicecreateUser() 메서드가 데이터베이스에 유저 정보를 저장하는 동안 트랜잭션 처리가 되도록 설정하세요. 예외 발생 시 자동으로 롤백되게 해야 합니다.

@Service
public class UserService {
    public void createUser(User user) {
        // 유저 정보 저장 로직
    }
}

 

풀이:

 

@Transactional을 적용하여 트랜잭션 관리를 추가하고, 예외 발생 시 롤백되도록 설정합니다.

@Service
public class UserService {

    @Transactional
    public void createUser(User user) {
        // 유저 정보 저장 로직
        // 예외 발생 시 롤백 처리
    }
}

 

@Transactional 어노테이션은 createUser() 메서드 내에서 트랜잭션을 시작하며, 메서드가 정상적으로 실행되면 커밋되고, 예외가 발생하면 롤백됩니다.

 

3. AOP Pointcut 표현식 문제

 

문제: 특정 패키지 com.example.controller 내의 모든 메서드에 대해 AOP 로깅을 적용하려고 합니다. @Around 어노테이션을 사용하여 메서드 실행 전후에 로그를 출력하는 AOP 설정을 작성하세요.

 

풀이:

 

execution 표현식을 사용하여 특정 패키지의 모든 메서드에 대해 AOP를 적용할 수 있습니다.

@Aspect
@Component
public class LoggingAspect {

    @Around("execution(* com.example.controller.*.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("메서드 시작: " + joinPoint.getSignature().getName());
        Object result = joinPoint.proceed();  // 메서드 실행
        System.out.println("메서드 종료: " + joinPoint.getSignature().getName());
        return result;
    }
}

 

@Around 어노테이션은 메서드 실행 전과 후에 특정 로직을 실행할 수 있도록 합니다.

ProceedingJoinPoint를 사용하여 메서드 실행을 제어할 수 있습니다.

 

4. AOP와 @AfterReturning 문제

 

문제: ProductServicegetProductById() 메서드가 성공적으로 실행된 후, 반환된 Product 객체의 정보를 로그로 출력하는 AOP 설정을 작성하세요. 메서드의 반환값은 Product 타입입니다.

@Service
public class ProductService {
    public Product getProductById(int id) {
        // 데이터베이스에서 제품 조회 로직
        return new Product(id, "Sample Product");
    }
}

 

풀이:

 

@AfterReturning 어노테이션을 사용하여 메서드가 정상적으로 실행된 후 반환값을 처리하는 방법입니다.

@Aspect
@Component
public class ProductAspect {

    @AfterReturning(pointcut = "execution(* com.example.ProductService.getProductById(..))", returning = "product")
    public void logProduct(Product product) {
        System.out.println("반환된 제품 정보: " + product.getName());
    }
}

 

@AfterReturning은 메서드가 정상적으로 종료된 후 실행되며, 반환값을 참조할 수 있습니다.

returning = "product"를 통해 메서드의 반환값을 logProduct() 메서드의 매개변수로 전달받습니다.

 

5. AOP와 예외 처리 문제

 

문제: OrderServiceprocessOrder() 메서드가 예외를 발생시키는 경우, AOP를 사용하여 예외 메시지를 로그로 출력하는 기능을 추가하세요.

@Service
public class OrderService {
    public void processOrder(int orderId) throws Exception {
        // 주문 처리 로직 중 예외 발생 가능
        throw new Exception("주문 처리 중 오류 발생");
    }
}

 

풀이:

 

@AfterThrowing 어노테이션을 사용하여 메서드에서 예외가 발생할 때 해당 예외를 처리하는 AOP 설정을 추가합니다.

@Aspect
@Component
public class ExceptionAspect {

    @AfterThrowing(pointcut = "execution(* com.example.OrderService.processOrder(..))", throwing = "ex")
    public void logException(Exception ex) {
        System.out.println("예외 발생: " + ex.getMessage());
    }
}

 

@AfterThrowing 어노테이션은 메서드 실행 중 예외가 발생했을 때 실행됩니다.

throwing = "ex"를 통해 예외 객체를 참조하고, 해당 예외 메시지를 로그로 출력할 수 있습니다.

 

6. AOP를 통한 성능 측정 문제

 

문제: 모든 서비스 클래스의 메서드에 대해 AOP를 사용해 메서드의 실행 시간을 측정하는 기능을 추가하세요.

 

풀이:

 

@Around 어노테이션을 사용하여 메서드 실행 전후의 시간을 측정합니다.

 

@Aspect
@Component
public class PerformanceAspect {

    @Around("execution(* com.example..*Service.*(..))")
    public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();  // 메서드 실행
        long end = System.currentTimeMillis();
        System.out.println(joinPoint.getSignature().getName() + " 실행 시간: " + (end - start) + "ms");
        return result;
    }
}

 

@Around를 사용하여 메서드 실행 전후의 시간을 기록하고, 실행 시간을 출력하는 로직을 구현합니다.

 

이러한 문제들을 풀면서 Spring AOP의 다양한 기능을 직접 경험할 수 있습니다. 각 문제는 AOP의 핵심 기능을 다루고 있으므로, 문제를 풀어보며 AOP의 동작 원리와 활용 방법을 익히는 데 도움이 될 것입니다.

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유