스프링/6. 스프링 DB-2

44. 트랜잭션 AOP 주의사항 -초기화 시점

sdafdq 2023. 10. 15. 13:44

스프링 초기화 시점, 에는 트랜잭션 AOP가 적용이 되지 않을 수도 있다.

 

Custom init() 저 부분 인 듯?

 

그러니까, @PostConstruct가 의존성 주입 이후 우리가 뭔가 초기화? 작업같은 거 해 두고 싶을 때 저거 붙인 메소드 만들면 알아서 실행이 되는데,

 

만약 

@PostConstruct

@Transactional

이렇게 있으면 @Transactional이 적용이 되지 않을 수도 있다.

 

 

순서가 @PostConstruct 등 초기화가 모두 된 다음에 프록시로써 쓸 수 있다.

@SpringBootTest
public class InitTxTest {
    @Autowired
    Hello hello;

    @Test
    public void initTx(){
    }


    @TestConfiguration
    static class InitTxTestConfig{
        @Bean
        public Hello hello(){
            return new Hello();
        }
    }

    @Slf4j
    static class Hello{
        @PostConstruct
        @Transactional
        public void initV1(){
            boolean isActive = TransactionSynchronizationManager.isActualTransactionActive();
            log.info("@PostConstruct Transaction active = {}", isActive);
        }

        @EventListener(ApplicationReadyEvent.class)
        @Transactional
        public void initV2(){
            boolean isActive = TransactionSynchronizationManager.isActualTransactionActive();
            log.info("@EventListener Transaction active = {}", isActive);
        }
    }
}

테스트. 

@PostConstruct나 @EventListener(ApplicationReadyEvent.class)는 모두 특정 순간에 자동으로 호출 되므로,

그냥 실행만 할 수 있도록 빈 @Test를 넣음.

 

@PostConstruct 때는 저거 @Transactional을 붙여놨지만 false로 나옴.

 

@EventListener(ApplicationReadyEvent.class)는 말 그대로 애플리케이션 준비, 즉 사용할 준비가 끝났을 때 발생하는 이벤트인데(프록시, 초기화 등 모든 설정이 끝나고 딱 사용할 준비)

저 때는 true가 나옴.

 

2023-10-15T13:30:03.188+09:00  INFO 21664 --- [main] j.LocalContainerEntityManagerFactoryBean :

Initialized JPA EntityManagerFactory for persistence unit 'default'

 

2023-10-15T13:30:03.204+09:00  INFO 21664 --- [ main] hello.springtx.apply.InitTxTest$Hello    :

@PostConstruct Transaction active = false


2023-10-15T13:30:03.399+09:00  INFO 21664 --- [main] hello.springtx.apply.InitTxTest          :

Started InitTxTest in 2.957 seconds (process running for 4.259)


2023-10-15T13:30:03.470+09:00 TRACE 21664 --- [ main] o.s.t.i.TransactionInterceptor           :

Getting transaction for [hello.springtx.apply.InitTxTest$Hello.initV2]


2023-10-15T13:30:03.471+09:00  INFO 21664 --- [main] hello.springtx.apply.InitTxTest$Hello    :

@EventListener Transaction active = true


2023-10-15T13:30:03.471+09:00 TRACE 21664 --- [main] o.s.t.i.TransactionInterceptor           :

Completing transaction for [hello.springtx.apply.InitTxTest$Hello.initV2]

 

여기 보면 대충 이해가 됨.

뭐 일단 컨테이너? 빈? 이런 거 JPA EntityManager 관련해서 초기화 되고,

 

@PostConstruct가 실행이 됨. 이 때는 @Transactional 적용 안되고 false

 

그 다음, 완전히 InitTxTest 클래스가 초기화가 되고, 시작됨.

 

그 후 @EventListener(ApplicationReadyEvent.class) 가 이제 모둔 준비가 됐고, 사용할 준비가 되었으니 바로 실행 되는데,

먼저 트랜잭셔널 얻었다고, 프록시가 가로채서 시작됨.

그리고 @EventListener(ApplicationReadyEvent.class) 가 실행되고,

또 프록시가 가로채서 트랜잭션을 안정적으로 끝냄.

 

그래서 

뭔가 시작할 때 프록시 환경에서 뭔가를 하고 싶으면 @EventListener(ApplicationEadyEvent.class)를,

아니면 그냥 프록시 환경 말고 객체(빈)가 만들어 진 직후 하고 싶은 것이 있으면 @PostConstruct에서

 

 

객체 생성 -> @PostConstruct -> 빈 등록 및 모든 초기작업 완료 -> 실행 가능 -> @EventListener(ApplicationEadyEvent.class)