Spring/Spring Boot

@Transactional 동작과정 살펴보기 (with. Spring AOP)

민돌v 2024. 6. 16. 17:40
이번 포스팅에서는 Spring 에서 제공해주는 @Transactional 어노테이션의 동작과정에 대한 공부한 것을 기록합니다.

 

@Transactional 은 Spring 에서 제공해주는 어노테이션입니다.

  • @Transactional이 제공하는 기능은  해당 어노테이션이 붙은 시점의 작업단위를 하나의 트랜잭션 단위로 묶어 관리할 수 있도록 합니다.
  • 어노테이션은 단지 주석일 뿐이고, 실제로 런타임 시에 어떠한 일이 일어나 해당 어노테이션이 우리가 원하는 기능을 제공해주는지 일련의 과정을 살펴보고자 합니다.

 

Spring 에서 어노테이션을 처리하는 방법이 몆가지 있다고 하는데, 이번 포스팅에서는 @Transactional 이 목표이기 때문에 해당 내용은 넘어가겠습니다.

@Transactional 은 AOP 기반으로 처리됩니다.


Spring AOP(Aspect Oriented Programming)란

✔️ AOP : 관점 지향 프로그래밍

  • 객체 지향 프로그래밍(OOP)에서는 주요 관심사(역할, 책임,, 등) 에 따라 클래스를 분리합니다.
  • 이렇게 설계된 하나의 클래스는 SRP, 즉 하나의 책임만을 갖도록 설계되므로 프로그래밍적으로 필요한 부가기능(로그, 보안, 트랜잭션)들을 포함하는 로직을 부가기능으로 분리하고 다시 해당 관점으로 각각 모듈화하는 것을 AOP기법이라고 합니다.

→ Spring 에서는 Proxy 객체를 이용하여 몆가지 기능을 AOP 관점으로 지원하고 있습니다.

 

✔️Spring AOP에서 프록시 객체가 생성되는 방식에는 두 가지가 있습니다.

  1. JDK 동적 프록시 (JDK Dynamic Proxy): 인터페이스 기반의 프록시를 생성합니다. 대상 빈이 하나 이상의 인터페이스를 구현하고 있는 경우, Spring은 JDK 동적 프록시를 사용합니다.
  2. CGLIB 프록시: 클래스 기반의 프록시를 생성합니다. 대상 빈이 인터페이스를 구현하고 있지 않거나, 특정 상황에서는 CGLIB을 사용하여 프록시를 생성합니다.

 

📌 @Transactional 어노테이션 붙은 클래스도 스프링 컨테이너에서 빈이 초기화될 때 Proxy 객체가 생성되어
런타임 시, 실제 호출될떄는 Proxy 객체를 호출하게 됩니다.

CGLIB으로 생성된 TicketService 프록시 객체

 


@Transactional 살펴보기

  • @Traget : 해당 어노테이션을 사용할 대상 범위를 지정
    • ElementType.Type : 클래스, 인터페이스(주석 인터페이스 포함), 열거형 또는 레코드 선언
    • ElementType.MEHOD : 메소드 선언
  • @Retention : 해당 어노테이션의 정보 유지 범위 지정
  • @Inherited : 부모 클래스에 해당 어노테이션이 적용되었다면 자식 클래스에게도 상속
  • @Documented : 어노테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 하는 어노테이션 설정이다.
  • @Reflective : 주석이 달린 요소에 리플렉션이 필요함을 의미합니다. 해당 주석이 달린 요소에 대한 proccessor 를 트리거하고, 기본적으로 해당 주석이달린 요소에 등록하거나 필요한 경우 검색하여 동작합니다.

 


@Transactional 동작과정

@Transactional 이 붙은 객체를 호출했을 때를 디버깅하면 아래와 같은 순서로 작업이 진행되는 걸 확인할 수 있었습니다.

  1. @Transactional 이 붙은 타켓 객체(TicketService) 가 호출될 때 Target Object 를 상속한 Proxy 객체가 대신 호출된다.
  2. Cglib Proxy Interceptor 객체에서 Proxy 객체의 Target 객체의 인터셉터를 호출한다.
  3. Target 객체의 interceptor 객체 (Trasactionalnterceptor) 에서 구현된 부가기능 (Transaction) 로직을 수행한다.
  4. 구현된 트랜잭션 로직안에서 타켓 객체의 비지니스로직을 수행하고, 정상적으로 처리되면 commit 한다.

 


정리

  1. @Transactional 붙은 객체는 스프링 컨체이너에서 빈이 초기화 될때 Proxy 객체가 생성된다.
  2. Proxy 객페는 target 객체가 interface 냐 class 냐에 따라 jdk or cglib 형식의 proxy 객체가 생성된다.
  3. client 가 target 객체를 호출하면, 상속(cglib) 혹은 구현(jdk proxy - DI)로 주입된 proxy 객체가 대신 호출된다.
  4. proxy 객체에서 부가기능가 주기능을 수행하고 클라이언트에게 응답한다.

맞겠지..!??!

끝!