이번 포스팅에서는 Spring 에서 제공해주는 @Transactional 어노테이션의 동작과정에 대한 공부한 것을 기록합니다.
@Transactional 은 Spring 에서 제공해주는 어노테이션입니다.
- @Transactional이 제공하는 기능은 해당 어노테이션이 붙은 시점의 작업단위를 하나의 트랜잭션 단위로 묶어 관리할 수 있도록 합니다.
- 어노테이션은 단지 주석일 뿐이고, 실제로 런타임 시에 어떠한 일이 일어나 해당 어노테이션이 우리가 원하는 기능을 제공해주는지 일련의 과정을 살펴보고자 합니다.
Spring 에서 어노테이션을 처리하는 방법이 몆가지 있다고 하는데, 이번 포스팅에서는 @Transactional 이 목표이기 때문에 해당 내용은 넘어가겠습니다.
@Transactional 은 AOP 기반으로 처리됩니다.
Spring AOP(Aspect Oriented Programming)란
✔️ AOP : 관점 지향 프로그래밍
- 객체 지향 프로그래밍(OOP)에서는 주요 관심사(역할, 책임,, 등) 에 따라 클래스를 분리합니다.
- 이렇게 설계된 하나의 클래스는 SRP, 즉 하나의 책임만을 갖도록 설계되므로 프로그래밍적으로 필요한 부가기능(로그, 보안, 트랜잭션)들을 포함하는 로직을 부가기능으로 분리하고 다시 해당 관점으로 각각 모듈화하는 것을 AOP기법이라고 합니다.
→ Spring 에서는 Proxy 객체를 이용하여 몆가지 기능을 AOP 관점으로 지원하고 있습니다.
✔️Spring AOP에서 프록시 객체가 생성되는 방식에는 두 가지가 있습니다.
- JDK 동적 프록시 (JDK Dynamic Proxy): 인터페이스 기반의 프록시를 생성합니다. 대상 빈이 하나 이상의 인터페이스를 구현하고 있는 경우, Spring은 JDK 동적 프록시를 사용합니다.
- CGLIB 프록시: 클래스 기반의 프록시를 생성합니다. 대상 빈이 인터페이스를 구현하고 있지 않거나, 특정 상황에서는 CGLIB을 사용하여 프록시를 생성합니다.
📌 @Transactional 어노테이션 붙은 클래스도 스프링 컨테이너에서 빈이 초기화될 때 Proxy 객체가 생성되어
런타임 시, 실제 호출될떄는 Proxy 객체를 호출하게 됩니다.
@Transactional 살펴보기
- @Traget : 해당 어노테이션을 사용할 대상 범위를 지정
- ElementType.Type : 클래스, 인터페이스(주석 인터페이스 포함), 열거형 또는 레코드 선언
- ElementType.MEHOD : 메소드 선언
- @Retention : 해당 어노테이션의 정보 유지 범위 지정
- @Inherited : 부모 클래스에 해당 어노테이션이 적용되었다면 자식 클래스에게도 상속
- @Documented : 어노테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 하는 어노테이션 설정이다.
- @Reflective : 주석이 달린 요소에 리플렉션이 필요함을 의미합니다. 해당 주석이 달린 요소에 대한 proccessor 를 트리거하고, 기본적으로 해당 주석이달린 요소에 등록하거나 필요한 경우 검색하여 동작합니다.
@Transactional 동작과정
@Transactional 이 붙은 객체를 호출했을 때를 디버깅하면 아래와 같은 순서로 작업이 진행되는 걸 확인할 수 있었습니다.
- @Transactional 이 붙은 타켓 객체(TicketService) 가 호출될 때 Target Object 를 상속한 Proxy 객체가 대신 호출된다.
- Cglib Proxy Interceptor 객체에서 Proxy 객체의 Target 객체의 인터셉터를 호출한다.
- Target 객체의 interceptor 객체 (Trasactionalnterceptor) 에서 구현된 부가기능 (Transaction) 로직을 수행한다.
- 구현된 트랜잭션 로직안에서 타켓 객체의 비지니스로직을 수행하고, 정상적으로 처리되면 commit 한다.
정리
- @Transactional 붙은 객체는 스프링 컨체이너에서 빈이 초기화 될때 Proxy 객체가 생성된다.
- Proxy 객페는 target 객체가 interface 냐 class 냐에 따라 jdk or cglib 형식의 proxy 객체가 생성된다.
- client 가 target 객체를 호출하면, 상속(cglib) 혹은 구현(jdk proxy - DI)로 주입된 proxy 객체가 대신 호출된다.
- proxy 객체에서 부가기능가 주기능을 수행하고 클라이언트에게 응답한다.
맞겠지..!??!
끝!
'Spring > Spring Boot' 카테고리의 다른 글
Spring Boot 에서 Redis Cache 사용하기 (2) | 2024.07.02 |
---|---|
Spring 에서 Redis 사용하기 (설정, In-memory DB, Transaction) (0) | 2024.07.01 |
Spring Rest Docs Enum class 문서화 하기 (0) | 2024.03.19 |
[Spring] FCM 푸시 알림 연동하기 (AOS, IOS) (2) | 2024.01.07 |
[Spring Security] 존재하지 않는 API 호출 시 404 대신 401 or 403 을 반환할 때 (2) | 2023.07.15 |