[Java] AOP, 어노테이션을 사용한 프록시 패턴 개선

gyu·2024년 5월 6일

이전에 다이나믹 프록시로 작성했던 예제를 Spring AOP, 어노테이션을 사용해서 개선해보자.

UserService.java

public interface UserService {
    void doAction();
}

UserServiceImpl.java

import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Override
    @TestTransactional
    public void doAction() {
        System.out.println("doAction!");
    }
}

TestTransactional.java(Annotation)

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestTransactional {
}

Spring의 @Transactional 처럼 사용할 테스트용 커스텀 어노테이션인 @TestTransactional을 생성한다.

TransactionAspect.java

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class TransactionAspect {

    @Around("@annotation(TestTransactional)")
    public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Transaction start ");

        try {
            Object result = joinPoint.proceed();
            System.out.println("Transaction commit for " + joinPoint.getSignature());
            return result;
        } catch (Exception e) {
            System.out.println("Transaction rollback for " + joinPoint.getSignature());
            throw e;
        }
    }
}

@Aspect 어노테이션을 추가하여 AOP 담당 객체임을 지정한다.
@Around 안에 Pointcut 표현식은 TestTransactional 어노테이션이 적용된 모든 메서드가 실행될 때 이 어드바이스를 적용한다라는 의미이다.

@Around 사용 시 ProceedingJoinPoint 객체가 매개변수로 제공되며, proceed() 메서드를 호출함으로써 대상 메서드를 실행하고 결과를 반환받을 수 있다. 이 메서드 호출 전후로 필요한 로직을 추가하여 메서드의 실행 과정에 개입할 수 있다.
위 예제에서는 proceed() 메서드 호출 전 트랜잭션 시작, 호출 후에 commit을 수행하며 예외 발생 시 rollback을 수행하도록 작성된 것을 확인할 수 있다.

0개의 댓글