카테고리 없음

spring @Transactional aop 구현해보기

머룽 2023. 4. 20. 09:52
말이 거창하지 실제 Transactional 을 구현하는건 아니다. @Transactional 대충 어떻게 동작하는지 알아보기 위해 aop 를 구현하는 것이다. 실질적으로 Transactional을 구현하는건 아니다. Transaction이라는 어노테이션이 달린 메서드는 aop 를 동작한다고 해보겠다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
@Documented
public @interface Transaction {
}
그리고나서 AOP 동작을 위해 MethodInterceptor 구현해야된다. 실제 여기서 트랜잭션 시작과 끝을 구현하면된다.
public class TransactionInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("Transaction start");
        Object proceed = invocation.proceed();
        System.out.println("Transaction end");
        return proceed;
    }
}

그리고나서 우리는 동적으로 포인트컷을 만들 필요가 없기 때문에 StaticMethodMatcherPointcut 를 구현하면된다.
public class TransactionPointcut extends StaticMethodMatcherPointcut {

    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return method.isAnnotationPresent(Transaction.class);
    }
}
마지막으로 설정 할 것이 있는데 해당 포인트컷과 우리가 실행 시킬 메스드(TransactionInterceptor) 를 매칭 시켜야 된다. 그러기 위해서 AbstractPointcutAdvisor를 구현하자. 실질적으로 구현할 것도 없이 우리가 만든 interceptor와 pointcut 인스턴스만 넘겨주면 된다.
public class TransactionPointcutAdvisor extends AbstractPointcutAdvisor implements Serializable {

    private final TransactionPointcut pointcut = new TransactionPointcut();

    private TransactionInterceptor interceptor;

    public TransactionPointcutAdvisor(TransactionInterceptor interceptor) {
        this.interceptor = interceptor;
    }

    @Override
    public Advice getAdvice() {
        return this.interceptor;
    }

    @Override
    public Pointcut getPointcut() {
        return this.pointcut;
    }
}
그리고 나서 동작시킬 Service 클래스를 두개 만들어보자
@Service
public class AopService {

    @Transaction
    public String service(){
        return "aop";
    }
}

@Service
public class NoAopService {

    public String service() {
        return "noAop";
    }
}

한개는 AOP가 적용되야 되는 메서드이고 다른한개 클래스는 AOP 없는 메서드이다.
@Autowired
private AopService aopService;

@Autowired
private NoAopService noAopService;

@Test
public void test() {
    logger.info("aopService : {}", aopService.getClass());
    logger.info("noAopService : {}", noAopService.getClass());
}
실행을 해보면 다음고 같은 로그가 남을 것이다.
2016-05-13 17:06:35.455  INFO 4504 --- [           main] me.wonwoo.SpringLogTestApplicationTests  : aopService : class me.wonwoo.service.AopService$$EnhancerBySpringCGLIB$$a322247b
2016-05-13 17:06:35.456  INFO 4504 --- [           main] me.wonwoo.SpringLogTestApplicationTests  : noAopService : class me.wonwoo.service.NoAopService
AopService는 프록시 객체가 주입되었다. 하지만 다른 한개는 일반 객체가 주입되었다. 실제로 AopService의 service를 호출하면 Transaction start 와 Transaction end가 찍히는걸 볼수 있다. 이것으로 간단하게 @Transactional aop를 구현해봤다.