[Spring] @Transactional, AOP Proxy

호호빵·2022년 9월 26일
0

Spring

목록 보기
16/24
  • 트랜잭션이 어떻게 동작하나요?
    -> Spring 트랜잭션은 AOP Proxy 통해 처리됩니다.
  • 트랜잭션에 대해 알아보려 하는데, 스프링 AOP를 통해 트랜잭션이 처리되고, AOP는 프록시 패턴을 사용한다.

    • AOP란
    • Spring AOP는 왜 프록시를 사용하는가
    • @Transactional의 동작 원리

AOP(Aspect Oriented Programming)

  • Aspect(관점)이란 흩어진 관심사들을 하나로 모듈화 한 것을 의미
  • OOP에서는 SRP원칙에 따라 하나의 책임만을 갖게 설계되지만 클래스를 설계하다보면 로깅, 보안, 트랜잭션 등 여러 클래스에서 공통적으로 사용되는 부가 기능들이 생김. 비즈니스 로직은 아니지만 반복적으로 여러 곳에서 쓰이는 것을 흩어진 관심사(Cross Cutting Concerns)라 함
  • 흩어진 관심사를 별도의 클래스로 모듈화하여 OOP를 더 잘 지킬 수 있게 해주는 것
위 그림에서 처럼 계좌이체, 입출금, 이자계산이라는 로직을 처리할 때, 
모두 똑같이 로깅, 보안, 트랜잭션을 처리해줘야한다.
따라서 모든 로직에 똑같은 코드가 반복적으로 삽입될 수 밖에 없다.

하지만 AOP에서는 로깅, 보안, 트랜잭션이라는 공통 관심(Aspect)을 따로 빼내어 계좌이체, 입출금, 이자계산이라는 
핵심 관심에 횡단으로 삽입해 주는 것이다.

이렇게 각 객체별로 처리했던 것을 각 관점별로 외부에서 접근을 하는것이 AOP의 핵심이다.
즉 개발자는 계좌이체, 입출금, 이자계산과 같은 핵심 기능을 만들고, 공통적인 관심 기능(로깅, 보안, 트랜잭션)을 
처리하는 모듈을 분리해서 개발한 후, 필요한 시점에 자동으로 공통적인 관심 기능이 삽입되도록 하는것이다. 
 

주요 개념

  • Aspect : 반복되어 사용되는 로직, Advice + PointCut으로 AOP의 기본 모듈
  • Advice : 반복 로직의 구현체, Target에 제공할 부가 기능을 담고 있는 모듈
  • Target : Advice가 부가 기능을 제공할 대상(적용될 비즈니스 로직)
  • JointPoint : Advice가 적용될 위치
    -> (메서드 진입 지점, 생성자 호출 시점, 필드에서 값을 꺼내올 때 등 다양한 시점에 적용 가능)
  • PointCut : Target을 지정하는 정규 표현식


Spring AOP

  • 기본적으로 proxy 방식으로 동작

    Proxy 패턴이란
    어떤 객체를 사용하고자 할 때, 객체를 직접적으로 참조하는 것이 아니라 해당 객체를 대행하는 객체(proxy)를 통해 대상 객체에 접근하는 방식

왜 프록시 방식을 사용하는가

  • 프록시 객체없이 Target 객체를 사용하고 있다면 Aspect 클래스에 정의된 부가 기능을 사용하기 위해 직접 Aspect 클래스를 호출해야함
  • 여러 곳에서 반복적을 Aspect를 호출해야하고 이로 인해 유지보수성이 떨어짐.

-> 그래서 Spring에서는 Target 클래스 혹은 그 상위 인터페이스를 상속하는 프록시 클래스를 생성하고, 프록시 클래스에서 부가 기능에 관련된 처리를 함
(Target에서 Aspect을 알 필요없이 순수한 비즈니스 로직에 집중 가능)


JDK Dynamic Proxy와 CGLib Proxy

  • 인터페이스를 구현한 타겟에서는 JDK Dynamic Proxy를,
    인터페이스를 구현하지 않은 타겟은 CGLIB를 사용

JDK

  • Target의 상위 인터페이스를 상속받아 프록시 만듦.
    (인터페이스를 구현한 클래스가 아니면 의존 불가능)

CGLib

  • Target 클래스를 상속받아 프록시 만듦.
  • 인터페이스를 구현하지 않고 구체 클래스에 의존하기 때문에 런타임 에러가 발생할 확률 적음
  • 여러 성능적 이점으로 인해 Spring Boot에서는 CGLib 사용방식을 기본으로 채택


@Transactional

  • 트랜잭션 처리를 위한 @Transactional 애노테이션은 Spring AOP의 대표적 예

Transaction

  • 데이터베이스의 상태를 변화(SELECT, INSERT, DELETE, UPDATE)시키기 위해 수행하는 작업의 단위, 한꺼번에 모두 수행되어야하는 일련의 연산을 말합니다.
  • 하나의 트랜젝션은 Commit(성공)되거나 Rollback(비정상적으로 종료되어, 모든 연산을 취소)됩니다.

특징
ACID (Atomicity(원자성), Consistency(일관성), Isolation(독립성), Durability(영속성))

  • 원자성 : 한 트랜잭션 내에서 실행한 작업들은 하나로 간주. 즉, 모두 성공 또는 모두 실패.
  • 일관성 : commit될 경우 언제나 일관성 있는 데이터베이스 상태로 변환됩니다.(상태 유지)
  • 독립성 : 동시에 실행되는 트랜잭션들이 서로 영향을 미치지 않도록 격리해야함
  • 영속성 : 트랜잭션을 성공적으로 마치면 결과가 항상 저장되어야 한다.

스프링에서 트랜잭션 처리 방법

  • 선언적 트랜잭션

    • 어노테이션 방식으로 @Transactional을 선언하여 사용하는 방법이 일반적
    • 클래스, 메서드위에 @Transactional 이 추가되면, 이 클래스에 트랜잭션 기능이 적용된 프록시 객체가 생성
    • 프록시 객체는@Transactional이 포함된 메소드가 호출 될 경우, PlatformTransactionManager를 사용하여 트랜잭션을 시작하고, 정상 여부에 따라 Commit 또는 Rollback 한다.
  • 서비스 클래스에서 @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();
        }
    }

결론

  • AOP는 흩어진 관심사를 별도의 클래스로 모듈화하는 프로그래밍 방법을 말하며, OOP를 더욱 잘 지킬 수 있도록 도움을 준다.
  • Spring AOP는 프록시 객체를 자동으로 생성해주어, Aspect/Advice에 직접적으로 의존하지 않게 해준다.
  • @Transactional 도 Spring AOP 중 하나로 프록시 방식으로 동작한다.
    • 원본 클래스/인터페이스를 상속 받아 프록시를 생성하기 때문에 접근 제어가 private으로 되어 있으면 안된다.
    • 객체 외부에서 처음으로 진입하는 메서드에 트랜잭션 처리가 되어 있어야, 해당 요청을 프록시 객체가 대신 처리할 수 있다. 따라서 트랜잭션은 객체 외부에서 처음 진입하는 메서드를 기준으로 동작한다.


프록시 패턴이란
트랜잭션, AOP, Proxy

profile
하루에 한 개념씩

0개의 댓글