노트코드
노트코드
노트코드

블로그 메뉴

  • 홈
  • 이력서
  • 이전 블로그
  • 글쓰기
  • 관리자페이지
  • 분류 전체보기 (57)
    • 코틀린 (2)
      • 실무 프로젝트로 배우는 Kotlin & Sprin.. (2)
    • JAVA (1)
      • 디자인패턴 (1)
      • 객체지향 5대원칙 (0)
    • SPRING (32)
      • JPA (11)
      • 스프링시큐리티 (1)
      • 스프링 (8)
      • QueryDsl (1)
      • 스프링배치 (11)
    • AZURE (0)
    • ETC (10)
      • MAVEN (0)
      • GIT (0)
      • ReMind (3)
      • Exception (1)
      • CS (6)
    • 책 (8)
      • 이것이 자바다 (8)

최근 글

최근 댓글

태그

  • JPA
  • 스프링
전체 방문자
오늘
어제
hELLO · Designed By 정상우.
노트코드

노트코드

SPRING/스프링

[스프링 핵심 원리 - 고급편] 프록시, 프록시 패턴, 데코레이터 패턴

2022. 2. 16. 02:39

클라이언트와 서버 개념에서 클라이언트가 요청한 결과를 서버에 직접 요청하는 것이 아니라 어떤 대리자를 통해서 대신 간접적으로 서버에 요청할 수 있다. 이것을 프록시라고 한다.

 

객체에서 프록시가 되려면, 클라이언트는 서버에 요청을 한 것인지, 프록시에게 요청을 한 것인지 조차 몰라야 한다.

(즉 서버와 프록시는 같은 인터페이스를 사용해야함)

그리고 클라이언트가 사용하는 서버 객체를 프록시 객체로 변경해도 클라이언트 코드를 변경하지 않고 동작해야한다.

프록시의 주요기능

프록시를 통해서 할 수 있는 일은 크게 2가지로 구분할 수 있다.

  • 접근제어
    • 권한에 따른 접근차단
    • 캐싱
    • 지연로딩
  • 부가 기능 추가
    • 원래 서버가 제공하는 기능에 더해서 부가 기능을 수행한다.

프록시 객체가 중간에 있으면 크게 접근 제어와 부가 기능 추가를 수행할 수 있다.

 

프록시 패턴 vs 데코레이터 패턴?

  • 프록시 패턴 : 접근 제어가 목적
  • 데코레이터 패턴: 새로운 기능 추가가 목적

(둘다 프록시를 사용하지만, 의도가 다르다는점이 핵심)

 

 

프록시 패턴

실행코드

 

public class ProxyPatternTest {

    @Test
    void noProxyTest() {
        RealSubject realSubject = new RealSubject();
        ProxyPatternClient client = new ProxyPatternClient(realSubject);
        client.execute();
        client.execute();
        client.execute();
        
        //3초 소요

    }

    @Test
    void cacheProxyTest() {
        RealSubject realSubject = new RealSubject();
        CacheProxy cacheProxy = new CacheProxy(realSubject);
        ProxyPatternClient client = new ProxyPatternClient(cacheProxy);
        client.execute();
        client.execute();
        client.execute();
        
        //1.xx초 소요
    }
}

public class ProxyPatternClient {

    private Subject subject;

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

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

Proxy와, 실제 객체가 참조할 인터페이스

public interface Subject {
    String operation();
}

Subject를 구현한 각각의 Proxy, 실제 객체 클래스

(중요한점은 CacheProxy는 실제 객체 클래스쪽으로 다시 호출해준다는점이 핵심)

@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;

    }
}

@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){
            e.printStackTrace();
        }
    }
}

 

데코레이터 패턴

실행코드

@Slf4j
public class DecoratorPatternTest {

    @Test
    void decorator(){
        RealComponent realComponent = new RealComponent();
        MessageDecorator messageDecorator = new MessageDecorator(realComponent);
        DecoratorPatternClient client = new DecoratorPatternClient(messageDecorator);
        client.execute();
    }
}

@Slf4j
public class DecoratorPatternClient {

    private Component component;

    public DecoratorPatternClient(Component component) {
        this.component = component;
    }

    public void execute(){
        String result = component.operation();
        log.info("result ={}", result);
    }
}

Decorator 패턴을 적용할 인터페이스

public interface Component {
    String operation();
}

Decorator패턴이 적용된 MessageDecorator와 아무것도 적용되지 않은, RealComponent

@Slf4j
public class MessageDecorator implements Component {

    private Component component;

    public MessageDecorator(Component component) {
        this.component = component;
    }

    @Override
    public String operation() {
        log.info("Message Decorator실행");
        String result = component.operation();
        String decoResult = result + "***********";
        log.info("MessageDecorator 꾸미기 적용 전 ={} 후 ={}", result, decoResult);
        return decoResult;

    }
}
// 비교대상
@Slf4j
public class RealComponent implements Component {
    @Override
    public String operation() {
        log.info("RealComponent 실행");
        return "data";
    }
}

Decorator패턴의 체인

MessageDecorator이후 동작시킬 TimeDecorator생성

@Slf4j
public class TimeDecorator implements Component{

    private Component component;

    public TimeDecorator(Component component) {
        this.component = component;
    }

    @Override
    public String operation() {
      log.info("TimeDecorator 실행");
        long startTime = System.currentTimeMillis();
        String result = component.operation();
        long endTime = System.currentTimeMillis();
        long resultTime = endTime - startTime;
        log.info("resultTime ={}", resultTime);
        return result;
    }
}

realComponent -> MessageDecorator -> TimeDecorator -> DecoratorPatternClient순으로 연결

 

 

@Slf4j
public class DecoratorPatternTest {

    @Test
    void decorator2(){
        RealComponent realComponent = new RealComponent();
        MessageDecorator messageDecorator = new MessageDecorator(realComponent);
        TimeDecorator timeDecorator = new TimeDecorator(messageDecorator);
        DecoratorPatternClient client = new DecoratorPatternClient(timeDecorator);
        client.execute();
    }
}

 

 

'SPRING > 스프링' 카테고리의 다른 글

[스프링 핵심 원리 - 고급편]인터페이스 ,클래스 기반의 프록시  (0) 2022.02.17
[스프링 핵심 원리-고급] 템플릿 콜백 패턴  (0) 2022.01.27
[스프링 핵심 원리 -고급] 전략패턴  (0) 2022.01.27
[스프링 핵심 원리-고급] 템플릿 메서드 패턴  (0) 2022.01.25
[스프링 핵심 원리-고급] 쓰레드 로컬 주의사항  (0) 2022.01.22
    'SPRING/스프링' 카테고리의 다른 글
    • [스프링 핵심 원리 - 고급편]인터페이스 ,클래스 기반의 프록시
    • [스프링 핵심 원리-고급] 템플릿 콜백 패턴
    • [스프링 핵심 원리 -고급] 전략패턴
    • [스프링 핵심 원리-고급] 템플릿 메서드 패턴
    노트코드
    노트코드
    노션 블로그에서 티스토리로 이전공사중

    티스토리툴바