자바 reflection에서는 프록시 기능을 지원한다.
프록시는 대리 혹은 가짜라는 의미로
자바에서 Proxy객체는 실제 객체를 감싸며 실제 객체에 대한 요청을 먼저 처리하고 실제객체에 요청을 위임하는 역할을 수행한다. (필요에 따라 proxy객체가 자체적으로 역할을 수행하고 실체 객체에 요청을 넘기지 않을 수도 있다.)
우리는 알게 모르게 Proxy기능을 이미 많이 사용하고 있는데,
- Spring AOP
어떤 객체에 업무를 위임할 때 본 기능을 수행하기 전 부가기능을 수행하고 싶을 때, 그 부가기능을 Proxy가 먼저 수행한 후 실제 객체에 본 업무를 위임하는 방식으로 Proxy를 사용한다.
예를 들어, A객체가 a업무를 수행하기 전 b부가기능이 실행되어야 한다면 b에 대한 책임을 가진 A의 Proxy객체가 이를 먼저 수행한 뒤 실제 A객체의 a기능을 호출하는 식이다.
개발 시점에 AOP를 적용하기 위해 Aspect를 생성하고 joinpoint를 설정하면
런타임시점에 joinpoint객체에 대한 proxy객체가 생성되어 aspect기능을 수행한 뒤 실제 객체에 업무를 위임한다.
- JPA
Entity가 참조하는 일대 다 관계의 객체에 대해선 Lazy 로딩이 default로 설정되어있을 뿐 아니라 일대일 관계에 대해서도 lazy로딩으로 설정하는 경우가 대부분이다.
어플리케이션에서 Entity를 불러올 때 Lazy로딩하는 참조 객체는 null이 아니라 Proxy객체로 생성되어 들어오는데, (영속성 컨텍스트에 참조객체가 있으면 Proxy가 아닌 실제 객체가 들어온다.)
이 Proxy객체는 가만히 있다가 메소드가 호출될 때 DB에서 실제 객체를 로딩하고 참조하여 실제 객체에 호출된 업무를 위임한다.
- Bean 등록
Configure 파일을 생성하여 Bean을 등록할 때마다 항상 드는 의문이 있었는데
Bean등록 메소드는 return값이 매번 new 생성자를 생성하여 새로운 인스턴스를 리턴하는데 그럼에도 싱글통인 이유가 이해가 되지 않았기 때문이다.
정답은 CGLIB를 이용해 바이트 코드를 조작하여 Proxy객체를 생성했기 때문인데, 이 프록시 객체는 스프링 컨테이너에 아직 인스턴스를 생성하지 않은 경우에만 새로운 인스턴스를 생성하고, 아닌 경우 이미 생성된 인스턴스를 가져다주도록 한다.
https://velog.io/@hyungzin0309/Spring-Configuration
- Mock
Test시 실제 객체가 아닌 Mock객체를 사용한다.
Mock역시 Proxy의 일종이며
특정 sub를 검증하기 위한 테스트에서
리턴값을 지정하여 Stubbing하는 등 테스트 환경에 필요하도록 객체를 정의하여 사용한다.
당장 실무나 프로젝트에서 봤던 Proxy의 사용 예시를 생각하고 기술했지만 이 외에도 캐시, 트랜잭션 관리 등 많은 곳에서 Proxy가 사용되고 있다.
생성 시점
런타임시점에 생성된다. 그도 그럴게
롬복같이 개발 생산성을 높여주는 라이브러리는 개발자가 당장 사용해야 하기 때문에 compile시점에 적용되어야 하지만
프록시객체는 실제로 어떻게 동작하든 개발자는 관심을 가질 필요가 없으며 동적으로 생성되어야 하는 경우가 많기 때문에 런타임시점에 생성된다.