말이 거창하지 실제 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를 구현해봤다.