- 프록시 패턴이란???
- Proxy는 대리자라는 의미를 갖고 있다.
- 비서를 거쳐 사장과 커뮤니케이션하는 개념
- 객체 사용을 위해 직접 참조하지 않고, 해당 객체를 바라보는 객체를 생성해 실제 객체의 생성을 미룬다.
- 프록시 사용 이유는?
- 객체 지향의 원칙인 OCP(Open-Closed Principle)을 지키기 위해서이다.
- 자기 자신에 대한 수정에는 열려 있고 외부의 접근에 대해서는 닫혀 있어야 한다는 원칙
- 프록시 패턴의 장점
- 객체 생성 전에도 프록시를 통해 참조가 가능하다.
- 실제 객체의 public, protected를 숨길 수 있다.(인터페이스로 대체)
- 실제 객체에 대한 사전 처리가 가능하다.
- 프록시 패턴의 단점
- 자주 사용될 경우, 가짜 객체가 생성되는 것이기에 성능 저하가 발생할 수 있다.
- 로직이 복잡해져 가독성이 떨어질 수 있다.
- 프록시 패턴의 종류
- 가상 프록시 - 필요 시점까지 객체 생성 연기하지만 참조를 통해 객체를 이용할 수 있다.
- 원격 프록시 - 클라우드 환경의 Google Docs의 동작 원리처럼, 다른 주소 공간에 있는 객체를 프록시가 참조하도록 해 마치 같은 공간에 있는 것처럼 동작하게 한다.
- 보호 프록시 - 실제 객체에 대한 접근 제어를 위해 사용하는 패턴
프록시 구현 예제
영화라는 객체를 두고 그 안의 변수로 story라는 것을 두었습니다.
public interface Movie {
void displayStory();
}
public class Real_Movie implements Movie {
private String story;
public Real_Movie(String story) {
this.story=story;
loadFromMemory();
}
private void loadFromMemory() {
System.out.println("story = " + story);
}
@Override
public void displayStory() {
System.out.println("실제 정보: "+ story);
}
}
public class Proxy_Movie implements Movie {
private String story;
private Real_Movie real_movie;
public Proxy_Movie(String story) {
this.story=story;
}
@Override
public void displayStory() {
//실제 객체가 비어 있다면 데이터 주입
if(real_movie==null) {
real_movie = new Real_Movie(story);
}
real_movie.displayStory();
}
}
public class Proxy {
public static void main(String[] args) {
Movie movie1 = new Proxy_Movie("영화:명량");
Movie movie2 = new Proxy_Movie("영화:스파이더맨");
movie1.displayStory();
System.out.println();
movie2.displayStory();
}
}
아래 결과물과 같이 Proxy 메서드에서는 직접적으로 Real_Movie에 접근하지 않고도 프록시를 통해 메서드를 호출할 수 있습니다.
스프링에서의 프록시 패턴 활용
- Transaction
- 위 어노테이션에 프록시가 활용된다.
- 프록시를 통해 create 메소드의 원자성을 보장해준다.
@Service public class BookManager { @Autowired private BookRepository repository; @Transactional public Book create(String author) { System.out.println(repository.getClass().getName()); return repository.create(author); } }
- AOP(Aspect Oriented Programming) - 관점을 추출해 모듈화하는 기술
- 프록시 패턴을 구체화하는 기술
- JDK Proxy
- CGLib
- JDK Proxy
- 인터페이스를 기반으로 동적으로 프록시를 생성해준다.
- InvocationHandler라는 인터페이스 제공
- 인터페이스가 기반이기 때문에 인터페이스가 필수
- 리플렉션 사용
- 리플렉션은 클래스의 구체적인 타입을 몰라도 접근 가능하게 하는 API
- CGLIB
- JDK Proxy는 인터페이스가 필수라는 단점을 개선하고 상속으로 해결한다.
- CGLIB은 그 부분을 개선해 구체 클래스만 있어도 동적 프록시를 생성
- MethodInterceptor 인터페이스 제공
- 제약 사항
- 부모 클래스의 기본 생성자가 있어야 한다.(@NoArgsConstructor)
- 메서드나 클래스에 final이 붙으면 상속이나 오버라이딩이 불가능
- 프록시 팩토리
- 위 두 기술의 혼합 사용을 위해 도입
- 인터페이스 유무에 따라 프록시 기술 선택
- 프록시 패턴을 구체화하는 기술
- 지연 로딩
- 지연 로딩에도 프록시 기술이 사용된다. 즉시로딩은 프록시를 사용하지 않는다.
- 데이터 조회시 기본 동작
- 데이터 요청
- 멤버 객체를 타겟으로 하는 멤버 프록시가 초기화된다(처음 사용시)
- 영속성 컨텍스트에 이미 있다면 멤버 객체 반환
- 없다면 DB 조회 및 멤버 객체 생성 후 반환
[추가 공부할 사항]
AOP 개념
위빙
트랜잭션 동작 원리
Spring cache @Cacheable method ignored when called from within the same class
[참고 문헌]
[Design Pattern] 프록시 패턴(Proxy Pattern)에 대하여
[Spring] AOP 2. 동적 프록시와 스프링이 지원하는 프록시
'기술면접 > 디자인 패턴' 카테고리의 다른 글
[디자인 패턴] 커맨드 패턴 (0) | 2022.04.05 |
---|---|
[디자인 패턴] 전략 패턴 (0) | 2022.04.05 |
[디자인 패턴] 싱글톤 패턴 (0) | 2022.04.01 |
댓글