스프링/스프링 핵심 원리 - 고급편

29. 프록시 패턴

sdafdq 2024. 1. 19. 15:11
public interface Subject {
    String operation();
}

이렇게 먼저 클라이언트 - 서버의 관계라고 치면 서버의 인터페이스를 먼저 만들고,

 

@Slf4j
public class RealSubject implements Subject{
    @Override
    public String operation() {
        log.info("실제 객체 호출");
        sleep(1000);
        return "data";
    }

    private void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

서버의 기능 구현. 그냥 대략 1초정도 데이터 가져오는데 걸렸다고 가정한 거임.

 

그리고 프록시는,

 

@Slf4j
public class CacheProxy implements Subject{

    private Subject target;
    private String cacheValue;

    public CacheProxy(Subject target) {
        this.target = target;
    }

    @Override
    public String operation() {
        log.info("프록시 호출");
        if(cacheValue == null){
            cacheValue = target.operation();
        }
        return cacheValue;
    }
}

이렇게 원본 객체(암묵적으로 target 이라고 함)를 가지고 있으면서, 그 앞뒤로 필요한 로직을 붙인 상태.

 

즉 프록시는 원본을 가지고 있으면서, 원본의 핵심 로직에 필요한 처리를 앞뒤로 한다.

 

public class ProxyPatternClient {
    private Subject subject;

    public ProxyPatternClient(Subject subject) {
        this.subject = subject;
    }

    public void execute(){
        subject.operation();
    }
}

클라이언트 입장에서는 그냥 이렇게 서버를 받고, 서버의 기능만 실행한다.

원본이 호출되는건지, 프록시를 통해서 호출 되는건지 모른다.

 

 

그리고 프록시의 의도는 전에 말했듯 접근제어.

이번엔 접근 제어 중 최적화를 위한 캐싱 이었음.

 

 

 

@Test
void cacheProxyTest(){
    RealSubject realSubject = new RealSubject();
    CacheProxy cacheProxy = new CacheProxy(realSubject);
    ProxyPatternClient client = new ProxyPatternClient(cacheProxy);

    client.execute();
    client.execute();
    client.execute();
}

이렇게 밖에서 의존관계 주입