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();
}
구조를 보면
구조에서 TimeProxy를 도입함으로써
구조로 프록시를 도입함으로써 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을 넘긴다.