의문
private 메서드는 @Transactional을 적용할 수 없다. 뭔가 예상이 가지만 그래도 한번 알아보자!!
먼저 @Transactional 부터 살펴보자!
@Transactional
평소에 저희가 자주 사용하는 @Transactional에는 AOP가 적용되어있습니다.
이를 스프링 트랜잭션 AOP라고 합니다.
스프링 트랜잭션 AOP는 @Transactional이 붙여진 메서드가 실행되기 전에 begin을 호출하고 메서드가 종료한 뒤에 commit을 호출합니다!
어떻게 할 수 있는 걸까요??
답은 프록시입니다!!
Spring에는 두가지 프록시 구현체가 있는 데 Springboot에서는 CGLIb를 사용하기 때문에 CGLIb를 기준으로 설명하겠습니다!
아래는 에코노베이션 동아리에서 진행중인 도토링 프로젝트의 회원가입 코드의 일부입니다.
@Transactional
public void saveMento(MentoSignupRequestDTO mentoSignupRequestDTO, List<Certification> certifications){
Mento mento = Mento.createMento(...);
mentoRepository.save(mento);
}
코드에서 알 수 있듯이 트랜잭션이 적용되어있습니다!
위 saveMento 메서드를 호출하면 아래와 같은 일들이 벌어집니다.
(MentoService는 필자가 구현한 Service 클래스이고, MentoServiceProxy는 CGLIb가 만들어준 것이다.)
아래는 CGLIb가 Enhancer 클래스를 바탕으로 Proxy를 생성하는 예시이다.
// 1. Enhancer 객체를 생성
Enhancer enhancer = new Enhancer();
// 2. setSuperclass() 메소드에 프록시할 클래스 지정
enhancer.setSuperclass(MentoService.class);
enhancer.setCallback(NoOp.INSTANCE);
// 3. enhancer.create()로 프록시 생성
Object mentoServiceProxy = enhancer.create();
// 4. 프록시를 통해서 간접 접근
MentoService mentoService = (MentoService)mentoServiceProxy;
mentoService.saveMento(mentoSignupRequestDTO);
class MentoServiceProxy{
MentoService mentoSerivce;
@Override
public void saveMento(MentoSignupRequestDTO mentoSignupRequestDTO, List<Certification> certifications){
// begin 실행
mentoService.saveMento(MentoSignupRequestDTO mentoSignupRequestDTO, List<Certification> certifications);
// commit 실행
}
}
- setCallback 메서드는 프록시 클래스가 메서드를 사용할 수 있게 도와주는 클래스이다!
즉, @Transactional을 적용하면, 타켓을 구현한 프록시 객체를 통해서 공통적인 전후 과정을 처리해주는 것을 알 수 있습니다.
결론
아마 다들 눈치채셨겠지만, private 메서드가 트랜잭션이 적용이 안 되는 이유는 타켓 객체의 메서드를 호출할 수 없기때문입니다.
생각보다 간단한 결론이었지만, 이 과정을 통해서 프록시와 CGLIb에 대해서 공부할 수 있었습니다!!
'스터디 > Spring' 카테고리의 다른 글
@ExceptionHanlder의 동작 원리(Feat.HandlerExceptionResolver) (0) | 2024.01.15 |
---|---|
DTO에 대한 고민 (0) | 2023.07.17 |
Mocktio - Spring 단위 테스트 (0) | 2023.05.10 |
Mockito when-thenReturn 사용 시 WrongTypeOfReturnValue 오류 (0) | 2023.05.10 |
필터와 인터셉터 (0) | 2023.04.07 |