Proxy란?

GreatCloud·2025년 12월 16일

백엔드

목록 보기
4/14

Spring Framework를 활용하여 포트폴리오를 만들던 도중에 @Transactional 어노테이션이 commit, rollback 기능을 제공하는지에 대한 의문점에서 시작하여 내부 구조를 확인하다보니 Proxy에 대한 이해가 부족한 것을 알게되었다.
정보처리기사 시험을 준비하며 프록시라는 개념을 외우기만 하였고 직접 정리를 하며 이해를 하기 위한 글이다.

프록시란?

대리인이라는 뜻의 프록시가 무엇인지 명확하게 알아보자

사장님(원본 객체)
    ↑
비서(프록시, 대리인)
    ↑
고객(호출자)

고객이 사장님에게 전화 -> 비서가 받음 -> 비서는 사장에게 전달 -> 비서가 고객에게 답변

비서가 할 수 있는 일:

  • 통화 시간 기록
  • 중요한 전화만 연결
  • 통화 내용 녹음
  • 통화 전후로 추가 작업

내가 요청한 일:

  • 사장님에게 핵심만 전달

비서가 하는 일

  • 통화 시간 기록
  • 중요한 전화만 연결
  • 통화 내용 녹음
  • 사장님에게 핵심만 전달
  • 통화 전후로 추가 작업

결론

핵심 로직 외의 부가적인 작업들의 중복 작성을 피하기 위해
공통된 작업들을 가지고 있는 대리자 객체를 만들고 해당 대리자 객체에 내가 작성한 핵심 로직을 추가하는 것이며
정리하자면

  1. 프록시 = 진짜인 척하는 가짜 객체
  2. 가짜가 부가 작업 다 하고, 진짜한테 핵심만 시킴
  3. 진짜 코드는 깔끔하게 유지 가능

그럼 이제 @Transactional 어노테이션이 어떻게 동작하는 지 알 수 있다

@Transactional이 붙은 메소드

@Service
public class UserService {
    
    @Transactional  // ←
    public void createUser(User user) {
        userRepository.save(user);  // 핵심 로직만 작성
    }
}

그리고 Spring이 뒤에서 하는 일

// Spring이 자동으로 프록시 생성
public class UserService$$SpringProxy {
    private UserService realService;
    
    public void createUser(User user) {
        // 추가된 부가 작업: 트랜잭션 시작
        transactionManager.begin();
        
        try {
            realService.createUser(user);  // 내가 작성한 핵심 로직
            
            // 추가된 부가 작업: 커밋
            transactionManager.commit();
        } catch (Exception e) {
            // 추가된 부가 작업: 롤백
            transactionManager.rollback();
            throw e;
        }
    }
}

AOP(Aspect-Oriented Programming)

Proxy에 대해 알았으니 APO에 대해서도 확실하게 이해할 수있다
AOP='프록시 자동 생성 기술'이라고 볼 수 있다.
여러개의 AOP 어노테이션 추가

@Service
public class UserService {
    
    @Transactional        // Spring이 트랜잭션 프록시 생성
    @Cacheable           // Spring이 캐싱 프록시 생성
    @Async               // Spring이 비동기 프록시 생성
    @Logging             // 내가 만든 커스텀 프록시
    public void createUser(User user) {
        userRepository.save(user);  // 나는 핵심만 작성
    }

Spring이 자동으로 Proxy를 만들어준다

public class UserService$$MultiProxy {
    private UserService realService;
    
    public void createUser(User user) {
        log.info("로깅");                    // @Logging
        Object cached = cache.get("key");    // @Cacheable
        if (cached != null) return cached;
        
        CompletableFuture.runAsync(() -> {   // @Async
            transactionManager.begin();      // @Transactional
            
            try {
                realService.createUser(user);  // 핵심!
                transactionManager.commit();
            } catch (Exception e) {
                transactionManager.rollback();
            }
        });
    }
}
profile
모르는 것에 부끄러워 말고 아는 것에 자만하지 말 것

0개의 댓글