[출처] 김영한 - 데이터 접근 활용 기술 강의
프록시 도입 전
트랜잭션을 처리하기 위한 프록시를 도입하기 전에는 서비스의 로직에서 트랜잭션을 직접 시작했다.
//트랜잭션 시작
TransactionStatus status = transactionManager.getTransaction(new
DefaultTransactionDefinition());
try {
//비즈니스 로직
bizLogic(fromId, toId, money);
transactionManager.commit(status); //성공시 커밋
} catch (Exception e) {
transactionManager.rollback(status); //실패시 롤백
throw new IllegalStateException(e);
}
프록시 도입 후
트랜잭션을 처리하는 객체와 비즈니스 로직 처리하는 서비스 객체를 명확하게 분리할 수 있다.
public class Service {
public void logic() {
//트랜잭션 관련 코드 제거, 순수 비즈니스 로직만 남음
bizLogic(fromId, toId, money);
}
}

@Transactional이 특정 클래스나 메서드에 하나라도 존재하면 트랜잭션AOP는 프록시를 생성 후 스프링 컨테이너에 등록한다.
그리고 실제 service 객체 대신에 프록시를 스프링 빈에 등록하고, 프록시는 내부에 실제 service 객체를 참조하게 된다.
프록시는 실제 객체 service를 상속해서 만들어지기 때문에 다형성을 활용할 수 있다.
따라서 BasicService 대신에 프록시를 주입할 수 있다.

자바에서 별도의 참조가 없으면 this라는 뜻으로 자기 자신의 인스턴스를 가리킨다.
따라서 this.internal()이 실행이 되고, this는 자기 자신을 가리키므로 실제 객체 인스턴스를 의미한다. 따라서 트랜잭션을 적용할 수 없다.
메서드 내부 호출 때문에 트랜잭션 프록시가 적용되지 않는 문제를 해결하기 위해 internal() 메서드를 별도의 클래스로 분리
