어노테이션·리플렉션·동적 프록시: Spring 과 MyBatis 가 움직이는 원리
@Transactional을 붙이면 왜 트랜잭션이 걸릴까요. MyBatis 매퍼는 인터페이스만 있는데 어떻게 SQL 이 실행될까요. 답은 둘 다 같습니다. 실행 중에 클래스 구조를 읽는 리플렉션과, 인터페이스 호출을 가로채는 동적 프록시입니다. 이번 레슨은 순수 JDK 만으로 미니 컨테이너와 미니 MyBatis 를 만들어 그 원리를 재현합니다.
1. 왜 배우는가
실무 코드의 절반은 어노테이션입니다. @Service, @Autowired, @Transactional, @Select 를 붙이면 동작이 바뀌지만, 어노테이션 자체는 아무 일도 하지 않습니다. 누군가 실행 중에 "이 클래스에 이 어노테이션이 있는가" 를 읽고 행동해야 합니다. 그 누군가가 프레임워크이고, 읽는 도구가 리플렉션입니다.
원리를 모르면 함정을 피할 수 없습니다. 같은 클래스 안에서 this.transfer() 를 부르면 @Transactional 이 무시되는 문제는 실무에서 가장 자주 보는 트랜잭션 버그입니다. 프록시가 어떻게 끼어드는지 알면 이 버그는 한눈에 보입니다.
이 레슨의 코드는 약 300줄입니다. 그 안에 DI 컨테이너, 트랜잭션 프록시, 매퍼 프록시, resultMap 이 전부 들어 있습니다. Spring 은 이것을 수십만 줄로 튼튼하게 만든 것이고, 뼈대는 같습니다.