트랜잭션에 대해 알아보려 하는데, 스프링 AOP를 통해 트랜잭션이 처리되고, AOP는 프록시 패턴을 사용한다.
위 그림에서 처럼 계좌이체, 입출금, 이자계산이라는 로직을 처리할 때,
모두 똑같이 로깅, 보안, 트랜잭션을 처리해줘야한다.
따라서 모든 로직에 똑같은 코드가 반복적으로 삽입될 수 밖에 없다.
하지만 AOP에서는 로깅, 보안, 트랜잭션이라는 공통 관심(Aspect)을 따로 빼내어 계좌이체, 입출금, 이자계산이라는
핵심 관심에 횡단으로 삽입해 주는 것이다.
이렇게 각 객체별로 처리했던 것을 각 관점별로 외부에서 접근을 하는것이 AOP의 핵심이다.
즉 개발자는 계좌이체, 입출금, 이자계산과 같은 핵심 기능을 만들고, 공통적인 관심 기능(로깅, 보안, 트랜잭션)을
처리하는 모듈을 분리해서 개발한 후, 필요한 시점에 자동으로 공통적인 관심 기능이 삽입되도록 하는것이다.
주요 개념
Proxy 패턴이란
어떤 객체를 사용하고자 할 때, 객체를 직접적으로 참조하는 것이 아니라 해당 객체를 대행하는 객체(proxy)를 통해 대상 객체에 접근하는 방식
왜 프록시 방식을 사용하는가
-> 그래서 Spring에서는 Target 클래스 혹은 그 상위 인터페이스를 상속하는 프록시 클래스를 생성하고, 프록시 클래스에서 부가 기능에 관련된 처리를 함
(Target에서 Aspect을 알 필요없이 순수한 비즈니스 로직에 집중 가능)
JDK
CGLib
@Transactional
애노테이션은 Spring AOP의 대표적 예특징
ACID (Atomicity(원자성), Consistency(일관성), Isolation(독립성), Durability(영속성))
스프링에서 트랜잭션 처리 방법
선언적 트랜잭션
서비스 클래스에서 @Transactional을 사용할 경우, 해당 코드 내의 메서드를 호출할 때 영속성 컨텍스트가 생긴다는 뜻이다.
영속성 컨텍스트는 트랜잭션 AOP가 트랜잭션을 시작할 때 생겨나고, 메서드가 종료되어 트랜잭션 AOP가 트랜잭션을 커밋할 경우 영속성 컨텍스트가 flush되면서 해당 내용이 반영된다.
이후 영속성 컨텍스트 역시 종료되는 것이다.
처리 과정
1. Target에 대한 호출이 들어오면 AOP Proxy가 이를 가로채서 가져옴(intercept)
2. AOP Proxy에서 Transaction Advisor가 commit 또는 rollback 등의 트랜잭션 처리
3. 트랜잭션 처리 외에 다른 부가 기능이 있을 경우 해당 Custom Advisor에서 그 처리를 함
4. 각 Advisor에서 부가 기능 처리를 마치면 Target Method를 수행
5. interceptor chain을 따라 caller에게 결과를 다시 전달
코드로 보기
public class TransactionProxy{
private final TransactonManager manager = TransactionManager.getInstance();
...
public void transactionLogic() {
try {
// 트랜잭션 전처리(트랜잭션 시작, autoCommit(false) 등)
manager.begin();
// 다음 처리 로직(타겟 비스니스 로직, 다른 부가 기능 처리 등)
target.logic();
// 트랜잭션 후처리(트랜잭션 커밋 등)
manager.commit();
} catch ( Exception e ) {
// 트랜잭션 오류 발생 시 롤백
manager.rollback();
}
}