[Spring/AOP] 프록시 객체가 아닌 내부 호출 시 트랜잭션이 적용되지 않는 이슈

2023. 11. 6. 18:00· Spring
목차
  1. 💋 문제 상황
  2. 💋 문제 해결
  3. 💋 참고자료
반응형

 

반응형

💋 문제 상황

 

아래와 같이 서비스 객체가 있다.

 

external() 메서드는 트랜잭셔널 어노테이션이 적용되어 있지 않고,

internal() 메서드는 트랜잭셔널 어노테이션이 적용되어 있다.

 

@Slf4j
@Service
static class CallService {

	public void external() {
		log.info("call external");
		printInfo();
		internal();
	}

	@Transactional
	public void internal() {
		log.info("call internal");
		printInfo();
	}

	private void printInfo() {
		final boolean txActive = TransactionSynchronizationManager.isActualTransactionActive();
		log.info("tx active={}", txActive);
	}
}

 

printInfo()는 트랜잭션과 관련된 설정을 확인하기 위해서 추가했다.

TransactionSynchronizationManager.isActualTransactionActive();를 호출하면 직접적으로 현재 트랜잭션이 설정된 상태인지를 확인할 수 있다.

 

@Slf4j
@SpringBootTest
public class InternalCallV1Test {

	@Autowired
	private CallService callService;

	@Test
	void printProxy() {
		log.info("callService class={}", callService.getClass());
//		 callService class=class springtx.springtx.apply.InternalCallV1Test$CallService$$EnhancerBySpringCGLIB$$538b5402
	}

	@Test
	void internalCall() {
		callService.internal();
//		 tx active=true
	}

	@Test
	void externalCall() {
		callService.external();
//		call internal
//		tx active=false
	}
}

 

internalCall() 호출 시, 빈으로 등록된 CallService는 실제 CallService 객체가 아니라, CallService$$EnhancerBySpringCGLIB$$538b5402 의 프록시가 적용된 클래스다.

 

프록시 객체에서는 internalCall()를 호출하기 전, 후에 트랜잭션과 관련된 코드들을 AOP를 통해 적용해 놓았다.

 

externalCall() 를 호출하면 역시 프록시 객체의 externalCall()를 호출하는데, 이 메서드에는 트랜잭션 어노테이션이 적용되어 있지 않다. 따라서, 그냥 곧바로 실제(target) CallService 객체의 externalCall() 이 호출된다.

 

그런데 해당 메서드 내부에서 internal() 메서드를 호출하고 있다.

 

	public void external() {
		log.info("call external");
		printInfo();
		internal();
	}

 

이 메서드는 CallService$$EnhancerBySpringCGLIB$$538b5402 가 아니라, 그냥 직접 CallService 의 internal() 메서드를 호출한다. 해당 클래스에 트랜잭션 어노테이션이 붙어 있어서, 트랜잭션이 적용되는 것처럼 보이지만, AOP를 적용한 프록시 객체가 아니기 때문에 실제로는 적용되지 않는다.

 

💋 문제 해결

 

InternalService 클래스를 별도로 만들고 internal() 메서드를 옮긴다.

 

@Slf4j
@Service
class InternalService {

	@Transactional
	public void internal() {
		log.info("call internal");
		printTxInfo();
	}

	private void printTxInfo() {
		boolean txActive =
TransactionSynchronizationManager.isActualTransactionActive();
		log.info("tx active={}", txActive);
	} 
}

 

이렇게 메서드 내부 호출을 외부 호출로 변경하면 해결할 수 있다.

 

@Slf4j
@RequiredArgsConstructor
@Service
class CallService {

  private final InternalService internalService;

  public void external() {
	log.info("call external");
	printTxInfo();
	internalService.internal();
	}

  private void printTxInfo() {
	  boolean txActive =
TransactionSynchronizationManager.isActualTransactionActive();
	  log.info("tx active={}", txActive);
	} 
}

 

이제 InternalService 를 호출하게 되면, 의존성 주입 받은 프록시 InternalService 객체를 호출하게 된다. 해당 프록시의 internal() 메서드에는 트랜잭션 관련 코드가 있으므로 트랜잭션 프록시가 적용된다.

 

 

💋 참고자료

  • 김영한 개발자 인프런 강의

 

도움이 되었다면, 공감/댓글을 달아주면 깃짱에게 큰 힘이 됩니다!🌟
비밀댓글과 메일을 통해 오는 개인적인 질문은 받지 않고 있습니다. 꼭 공개댓글로 남겨주세요!

 

 

반응형

'Spring' 카테고리의 다른 글

[Spring] 스프링 설정파일에서 @Value로 API KEY 등 변수 가져오기  (0) 2024.02.08
[Spring/DB] 예외 발생 시 트랜잭션은 commit될까, rollback될까?  (0) 2023.11.11
[Spring/DB] JDBC, SQL Mapper(JdbcTemplate, MyBatis), ORM(JPA - Hybernate): 차이점과 등장 배경, 장단점에 대하여  (2) 2023.06.16
[Spring] 빈 스코프(Scope): 싱글톤, 프로토타입, 웹 관련 스코프  (0) 2023.06.15
[Spring] 빈 생명주기 콜백: 인터페이스(InitializingBean, DisposableBean), 설정 파일(initMethod, destroyMethod), 어노테이션(@PostConstruct, @PreDestroy)  (2) 2023.06.14
  1. 💋 문제 상황
  2. 💋 문제 해결
  3. 💋 참고자료
'Spring' 카테고리의 다른 글
  • [Spring] 스프링 설정파일에서 @Value로 API KEY 등 변수 가져오기
  • [Spring/DB] 예외 발생 시 트랜잭션은 commit될까, rollback될까?
  • [Spring/DB] JDBC, SQL Mapper(JdbcTemplate, MyBatis), ORM(JPA - Hybernate): 차이점과 등장 배경, 장단점에 대하여
  • [Spring] 빈 스코프(Scope): 싱글톤, 프로토타입, 웹 관련 스코프
깃짱
깃짱
연새데학교 컴퓨터과학과 & 우아한테크코스 5기 백엔드 스타라이토 깃짱
반응형
깃짱
깃짱코딩
깃짱
전체
오늘
어제
  • 분류 전체보기
    • About. 깃짱
    • Weekly Momentum
      • 2024
    • PROJECT
      • AIGOYA LABS
      • Stamp Crush
      • Sunny Braille
    • 우아한테크코스5기
    • 회고+후기
    • Computer Science
      • Operating System
      • Computer Architecture
      • Network
      • Data Structure
      • Database
      • Algorithm
      • Automata
      • Data Privacy
      • Graphics
      • ETC
    • WEB
      • HTTP
      • Application
    • C, C++
    • JAVA
    • Spring
      • JPA
      • MVC
    • AI
    • MySQL
    • PostgreSQL
    • DevOps
      • AWS
      • 대규모 시스템 설계
    • frontend
      • HTML+CSS
    • NextJS
    • TEST
    • Industrial Engineering
    • Soft Skill
    • TIL
      • 2023
      • 2024
    • Linux
    • Git
    • IntelliJ
    • ETC
      • 日本語

블로그 메뉴

  • 홈
  • 깃허브

인기 글

최근 글

태그

  • 상속과조합
  • 예외
  • lamda
  • 함수형프로그래밍
  • 조합
  • Composition
  • 우테코
  • 스트림
  • 상속
  • 우아한테크코스5기
  • 람다
  • 우아한테크코스
  • Java
  • 우테코5기
  • 람다와스트림
  • 레벨로그
  • Stream
  • 컴포지션
  • TDD
  • OOP
hELLO · Designed By 정상우.v4.2.0
깃짱
[Spring/AOP] 프록시 객체가 아닌 내부 호출 시 트랜잭션이 적용되지 않는 이슈
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.