클래스의 다형성을 이용한 프록시(proxy) 적용

종원유·2022년 3월 14일
0

Spring

목록 보기
9/10
post-thumbnail

객체 기반 프록시

Class의 다형성을 이용하여 기존 코드 수정없이 객체로 프록시를 적용하는 방법을 정리하고자 한다.

다형성

  • 자바 언어에서 다형성은 인터페이스나 클래스를 구분하지 않고 모두 적용된다.
  • 해당 타입과 그 타입의 하위 타입은 모두 다형성의 대상이 된다.

인터페이스가 없어도 객체의 다형성을 이용하여 프록시가 가능하다.

객체에 프록시 적용

프록시를 적용할 코드

//Service
@Slf4j
public class ConcreteLogic {

    public String operation(){
        log.info("ConcreteLogic 실행");
        return "data";
    }
}

//Client
public class ConcreteClient {

    private ConcreteLogic concreateLogic;

    public ConcreteClient(ConcreteLogic concreateLogic) {
        this.concreateLogic = concreateLogic;
    }

    public void execute(){
        concreateLogic.operation();
    }
}
  • 테스트 코드

	//테스트 코드 
    @Test
    void noProxy(){
        ConcreteLogic concreateLogic = new ConcreteLogic();
        ConcreteClient client = new ConcreteClient(concreateLogic);
        client.execute();
    }
  • 출력 결과

프록시 적용

//프록시
@Slf4j
public class TimeProxy extends ConcreteLogic {
    private ConcreteLogic concreateLogic;

    public TimeProxy(ConcreteLogic concreateLogic) {
        this.concreateLogic = concreateLogic;
    }

    @Override
    public String operation(){
        log.info("TimeDecorator 실행");
        long startTime = System.currentTimeMillis();

        String result = concreateLogic.operation();

        long endTime = System.currentTimeMillis();
        long resultTime = endTime - startTime;
        log.info("TimeDecorator 종료 resultTome={}ms", resultTime);
        return result;
    }
}
  • 테스트 코드

    @Test
    void addProxy(){
        ConcreteLogic concreteLogic = new ConcreteLogic();
        TimeProxy timeProxy = new TimeProxy(concreteLogic);
        ConcreteClient client = new ConcreteClient(timeProxy);
        client.execute();
    }
  • 출력결과

구조를 보면

  • 적용 전
    Client -> ConcreteLogic

구조에서 TimeProxy를 도입함으로써

  • 적용 후
    Client -> TimeProxy -> ConcereteLogic

구조로 프록시를 도입함으로써 ConreteLogic 로직의 실행 전, 후에 추가로 로그를 남기도록 추가 기능을 적용하였다.

정리

위처럼 인터페이스가 아닌 객체로 프록시를 적용할 경우 중요한 부분을 정리하자면,

  • 상속을 이용하여 기존 비즈니스 로직(ConcereteLogic)의 타입을 대체(TimeProxy)할 수 있도록 한다.
  • 비즈니스 로직을 @Override하여 대체 코드 작성을 통하여 추가 기능을 적용한다.

이상으로 Class의 다형성을 이용하여 기존 코드 수정없이 프록시를 적용하는 방법을 정리하였다. 인터페이스를 꼭 사용하지 않아도 프록시를 도입할 수 있다는 점을 알아두자.

추가

자바 기본 문법에 의해 자식 클래스 생성 시 항상 super()로 부모 클래스의 생성자를 호출해야 한다.
이 부분을 생략할 경우 기본 생성자가 호출된다.
하지만 기본 생성자가 없고 파라미터를 필수로 받는 생성자만 존재할 경우는 아래와 같은 작업이 필요하다.


//Service
@Slf4j
public class ConcreteLogic {
	
    private final String test;
    
    ConcreteLogic(String test){
    	this.test = test;
    }

    public String operation(){
        log.info("ConcreteLogic 실행");
        return "data";
    }
}

proxy는 어차피 target으로 실제 구현체를 참조하고 있고, 프록시의 상위 클래스로 의존하는 ConcreteLogic 클래스는 타입을 대체하기 위해서 상속했을 뿐 전혀 사용하지 않는다.

//프록시
@Slf4j
public class TimeProxy extends ConcreteLogic {
    private ConcreteLogic concreateLogic;

    public TimeProxy(ConcreteLogic concreateLogic) {
    	super(null);	//상위 ConcreteLogic 생성
        this.concreateLogic = concreateLogic;
    }

    @Override
    public String operation(){
        log.info("TimeDecorator 실행");
        long startTime = System.currentTimeMillis();

        String result = concreateLogic.operation();

        long endTime = System.currentTimeMillis();
        long resultTime = endTime - startTime;
        log.info("TimeDecorator 종료 resultTome={}ms", resultTime);
        return result;
    }
}

따라서

super(null);	//상위 ConcreteLogic 생성

super(null)로 타입 대체를 위한 프록시 상위 클래스의 생성자에 null을 넘긴다.

profile
개발자 호소인

0개의 댓글