Self-invocation(자기 호출)이란?
Self-invocation(자기 호출)은 클래스 내의 메서드가 동일 클래스의 다른 메서드를 호출하는 상황에서 발생
Spring 프레임워크에서 @Transactional 어노테이션을 사용할 때, 이 self-invocation은 문제가 발생할 수 있다.
그 이유는 Spring의 트랜잭션 관리가 AOP(Aspect-Oriented Programming) 기반의 프록시(Proxy)를 사용하기 때문이다.
Self-invocation이 왜 문제가 되는가?
프록시는 트랜잭션 시작, 커밋 또는 롤백을 처리하는데, 자기 호출이 발생할 경우 프록시가 아닌 실제 객체가 메서드를 호출하게된다.
이로 인해 트랜잭션 관리가 적용되지 않고, 예상대로 트랜잭션이 시작되지 않거나 커밋되지 않는 문제가 발생할 수 있다.
해결 방법
- 서비스를 다른 빈으로 분리:
- 트랜잭션이 필요한 메서드를 다른 클래스(Service)로 분리하고, 이를 호출하는 방식으로 문제를 해결할 수 있다.
- 예를 들어, 한 서비스에서 두 개의 메서드가 있다고 가정할 때, 두 메서드를 다른 클래스에서 호출하게 하여 프록시가 트랜잭션을 관리하도록 할 수 있다.
- AOP Context 재정의:
- Spring의 ApplicationContext를 이용해 현재 클래스의 프록시 객체를 얻어, 자기 호출 시 프록시를 통해 메서드를 호출하게 만들 수 있다.
@Autowired로 ApplicationContext를 주입받아 context.getBean(this.getClass()).method()와 같이 호출할 수 있다.
- Spring의 ApplicationContext를 이용해 현재 클래스의 프록시 객체를 얻어, 자기 호출 시 프록시를 통해 메서드를 호출하게 만들 수 있다.
- 프록시 모드 설정 변경:
- Spring에서는 기본적으로 CGLIB(바이트코드 생성 라이브러리)를 통해 프록시 객체를 생성한다.
@Transactional의 프록시 모드를 변경하여, self-invocation 시에도 트랜잭션 처리가 가능하게 할 수 있다.
- Spring에서는 기본적으로 CGLIB(바이트코드 생성 라이브러리)를 통해 프록시 객체를 생성한다.
2. AOP Context재정의 예시
@Service
public class MyService {
@Autowired
private ApplicationContext applicationContext;
@Transactional
public void outerMethod() {
// 이 호출은 트랜잭션이 적용되지 않음
this.innerMethod();
// ApplicationContext를 사용해 프록시 객체로 호출
applicationContext.getBean(this.getClass()).innerMethod();
}
@Transactional
public void innerMethod() {
// 트랜잭션이 적용됨
}
}
'Java & Spring > 트러블슈팅' 카테고리의 다른 글
@Transactional(propagation = Propagation.REQUIRES_NEW) (0) | 2024.10.10 |
---|---|
MultipleBagFetchException(두개의 Fetch Join) (0) | 2024.10.08 |