-
[Spring] @PostConstruct와 @Transactionallegacy/Spring 2023. 9. 5. 01:47
@PostConstruct와 @Transactional이 동시에 사용되었을 때 트랜잭션이 적용되지 않는다. 그 이유는 두 애너테이션이 호출되는 시점이 다르기 때문이다.
스프링 생명 주기
스프링 컨테이너 생성 -> 스프링 빈 생성 -> 의존 관계 주입 -> 초기화 콜백 -> 사용 -> 소멸 콜백 -> 스프링 컨테이너 종료
@PostConstruct 호출 시점
스프링 빈이 생성 되고 의존 관계가 주입된 후에 호출된다.
@Transactional 호출 시점
초기화 콜백 이후 컨테이너가 초기화된 후에 호출된다.
코드
Hello 클래스가 빈으로 등록되어 있고, initV1() 메서드에 @PostConstruct 애너테이션이 사용되고 있다.
@SpringBootTest @Slf4j public class InitTxTest { @Autowired Hello hello; @Test void init() { } @TestConfiguration static class ConfigClass { @Bean public Hello hello() { System.out.println("Hello 의존 관계 주입"); return new Hello(); } } static class Hello { @PostConstruct @Transactional public void initV1() { log.info("Hello init @PostConstruct tx active={}", TransactionSynchronizationManager.isActualTransactionActive()); } } }
위에서 말했듯이 @PostConstruct는 의존 관계 주입 완료된 후 호출이 되고, @Transactional은 스프링 컨테이너가 초기화된 후 호출된다.
따라서 다음과 같은 결과를 얻을 수 있다.
- @Autowired를 통해 의존 관계가 주입시에 "Hello 의존 관계 주입"이 먼저 출력이 된다.
- 의존 관계 주입이 끝났기때문에 초기화 콜백이 일어난다. 이때 @PostConstruct가 호출된다. 따라서 "Hello init @PostConstruct.."가 출력된다.
- 스프링 컨테이너가 초기화된다. "Started InitTxTest..."가 출력된다.
@PostConstruct와 @Transactional 호출 시점이 다르다.
@PostConstruct는 의존관계 주입이 완료된 후 호출되고, @Transactional은 스프링 컨테이너가 초기화된 시점에 호출된다. 따라서 두 애너테이션을 동시에 사용하면 @PostConstruct가 먼저 호출되기 때문에 트랜잭션이 정상적으로 처리되지 않는다.
트랜잭션의 경우 AOP 기술을 사용한다. AOP의 경우에는 스프링 컨테이너가 완전히 초기화되어야 사용할 수 있다.
따라서 @PostConstruct로 인해 스프링 컨테이너가 올라오지 않은 상태에서 @Transactional을 사용할 수 없다.
참고
https://www.inflearn.com/questions/26902/postconstruct%EC%99%80-transactional-%EB%B6%84%EB%A6%AC