뭐요

[Design Pattern] 프록시 패턴 본문

Java

[Design Pattern] 프록시 패턴

욕심만 많은 사람 2023. 3. 17. 13:32

프록시(Proxy) 란?

프록시 패턴

충분히 프록시의 뜻에서 유추해볼 수 있습니다. 프록시 패턴을 사용한다는 것은 내가 해야할 일을 프록시에게 맡겨 대신 수행하도록 하는 것입니다.

좀 더 프로그래밍 관점에서 살펴보면 인터페이스를 하나 두어 실제 서비스를 수행할 클래스와 프록시 클래스 두 개로 나눠 구현합니다. 이후 프록시 클래스에서는 실제 서비스를 수행할 클래스의 객체를 갖고 실제 수행할 서비스의 로직을 수행하도록 합니다.

이러한 형태를 띄고 있기 때문에, 본래 수행되어야 하는 서비스에 대해서는 결과 값이 달라지지 않습니다. 단지 흐름제어만 바꾸는 것입니다.

프록시 패턴의 형태를 요약하면 다음과 같습니다.

  1. 대리자 (프록시)는 실제 서비스와 같은 이름의 메서드를 구현한다. 이때 인터페이스를 사용한다.
  2. 대리자는 실제 서비스에 대한 참조 변수를 갖는다.
  3. 대리자는 실제 서비스의 같은 이름을 가진 메서드를 호출하고 그 값을 클라이언트에게 돌려준다.
  4. 대리자는 실제 서비스의 메서드 호출 전후에도 별도의 로직을 수행할 수도 있다.

(그림1)

(그림2)

예제 코드

(그림1)의 예시를 기반으로 이해하기 쉽게 실제 코드를 작성해보았습니다.

Subject Interface

public interface Subject {
    String request(String details);
}

RealSubject Class

public class RealSubject implements Subject{
    @Override
    public String request(String details) {
        return "해당 과목의 요청사항은 [" + details + "] 입니다.";
    }
}

Proxy Class

public class Proxy implements Subject{
    Subject subject;

    @Override
    public String request(String details) {
        subject = new RealSubject();
        return subject.request(details);
    }
}

Main Class

public class Main {
    public static void main(String[] args){
        Subject subject = new Proxy();
        System.out.println(subject.request("종강 시켜주세요"));
    }
}
해당 과목의 요청사항은 [종강 시켜주세요] 입니다.

Process finished with exit code 0

설명

실제로 수행하고자 하는 서비스는 RealSubject Class의 request() 입니다. 하지만 위의 코드를 보시면 프록시 패턴을 사용했기 때문에 Main Class에서 호출하는 메소드는 Proxy Class의 request() 입니다. Proxy라는 대리자에게 수행하고자 하는 서비스를 대신 수행하도록 흐름제어만 변경해주었습니다.

프록시 패턴의 활용

프록시 패턴이 무엇인지 설명과 예제 코드를 통해 충분히 이해했을 것입니다. 그러면 어디에서 왜 사용하는 걸까요?

Spring AOP

스프링에는 AOP라는 개념이 있습니다. AOP란 Aspect Oriented Programming의 약자로, 관점 지향 프로그래밍 입니다. 즉, 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화 하는 것입니다. 또한 관점을 기준으로 각각 모듈화 한다는 것은 코드들을 부분적으로 나누어서 모듈화 하겠다는 것입니다.

소스코드를 작성하다 보면 계속 반복해서 작성해야 하는 코드들이 존재합니다. 이러한 예시로는 “로그 작성”이 있는데 이러한 반복해서 작성해야 하는 코드를 흩어진 관심사라고 합니다.

흩어진 관심사를 핵심적인 비즈니스 로직에서 분리하는 것이 AOP의 존재 이유 입니다.

AOP의 필요성에 대해 로그 작성이라는 예시를 들었는데 조금 더 구체적으로 알아보겠습니다.

모든 메소드에 대해서 메소드 실행 전에 로그를 남기고 싶은 개발자가 있습니다. 이 개발자는 모든 메소드에다가 처음 부분에 직접 로그를 남겼다가 사수에게 혼이 났습니다.

왜 혼이 났을까요? 이렇게 되면 위에서 말했던, 핵심적인 비즈니스 로직과 부가적인 로직이 분리가 되지 않아 가독성이 떨어져 유지 보수가 힘들게 되었습니다. 이 때 필요한 것이 AOP이고 AOP는 내부적으로 프록시 패턴을 사용한다고 합니다.

위의 예제 코드에서 작성했던 소스 코드를 기반으로 해결해보면 다음과 같습니다.

Proxy Class

import java.time.LocalDate;

public class Proxy implements Subject{
    Subject subject;

    @Override
    public String request(String details) {
        System.out.println("현재 시간 : " + LocalDate.now() + "\n");

        subject = new RealSubject();
        return subject.request(details);
    }
}
현재 시간 : 2023-03-17

해당 과목의 요청사항은 [종강 시켜주세요] 입니다.

Process finished with exit code 0

실제 서비스를 수행하고자 하는 메소드 (RealSubject Class의 request())는 건들이지 않고 request() 메소드가 실행되기 전에 현재 시간을 나타내주었습니다. 물론 스프링에서 사용하는 프록시 패턴이 해당 예제 코드와 일치하지는 않지만 어떤 식으로 프록시 패턴이 사용되는 지는 알게 되었을 거라고 생각합니다.






[출처]
https://www.tutorialspoint.com/design_pattern/proxy_pattern.htm
https://velog.io/@ha0kim/2020-12-28-AOP-%EC%9D%98-%EC%A0%81%EC%9A%A9-%EC%82%AC%EB%A1%80
https://coding-factory.tistory.com/711
https://limkydev.tistory.com/79

'Java' 카테고리의 다른 글

정적 팩토리 메소드  (0) 2023.07.16
입출력 스트림 간단하게 알아보기  (0) 2023.07.16
JAVA stream API 예제로 이해하기  (2) 2023.07.11
Java - Exception 개념과 종류  (0) 2023.04.08
Java 비동기처리  (0) 2023.02.28