개발을 할 때 기존 기능을 보존 하면서, 확장 해야 하는 경우가 있다. 원본을 어쩔 수 없이 수정 해야 할 때는 피할 수 없지만, 확장만 한다면, Proxy 를 사용 하는 경우 쉽게 확장이 가능 하다. 사용 방법을 알아 보자.
Proxy 는 기존 에 만들었던 Class 를 새로운 Class로 포장 했다고 생각 하면 쉽다.
public class Packing { private Target target; public Packing(Target target) { this.target = target; } // doing... }
위 소스를 주목 하자. 포장지 에 기존 Class 를 담았다. 하지만 먼가가 부족 하다. 함수를 연결해줄 고리가 필요 하다. 그것이 InvocationHandler 이다. java.lang.reflect 패키지에서 제공 하고 있다.
포장지에 연결 고리를 달아보자.
public class Packing implements InvocationHandler { // doing... @Override public Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) throws Throwable { return paramMethod.invoke(paramObject, paramArrayOfObject); } }
invoke 라는 함수를 볼 수 있다. 포장지와, 기존 Class 를 연결 시켜주는 역할을 한다.
paramObject: targetClass (기존 Class) 를 넣는다.
paramMethod: targetClass 에서 실행 하고 싶은 메소드를 넣는다.
paramArrayOfObject: targetClass 에서 실행하고 싶은 메소드의 파라미터 값을 넣는다.
위 3가지 설정을 끝내면 준비 작업은 끝났다. 3가지 정보에 따라 포장지에서 기존 Class 함수를 실행 하게 된다. 샘플을 만들어 보자.
Github: https://github.com/whitelife/whitelife-sample/tree/master/src/main/java/kr/co/whitelife/sample/proxy
- Target
public class Target { public void doProcess() { System.out.println("doProcess....."); } public String doStringProcess(String string) { System.out.println("doStringProcess....."); return string; } }
- Packing
public class Packing implements InvocationHandler { private Target target; public Packing(Target target) { this.target = target; } public void doProcess() { try { System.out.println("Packing doProcess start....."); this.invoke(this.target, this.target.getClass().getDeclaredMethod("doProcess", new Class[]{}), new Object[]{}); System.out.println("Packing doProcess end....."); } catch (Throwable e) { e.printStackTrace(); } } public void doStringProcess(String string) { try { System.out.println("Packing doStringProcess start....."); String result = (String) this.invoke(this.target, this.target.getClass().getDeclaredMethod("doStringProcess", new Class[]{String.class}), new Object[]{string}); System.out.println(result); System.out.println("Packing doStringProcess end....."); } catch (Throwable e) { e.printStackTrace(); } } @Override public Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) throws Throwable { return paramMethod.invoke(paramObject, paramArrayOfObject); } }
- ProxyTest
public class ProxyTest { public static void main(String[] args) { Packing packing = new Packing(new Target()); packing.doProcess(); System.out.println(); packing.doStringProcess("doString"); } }
샘플 작성이 끝났다면 실행 해 보자. 아래와 같은 출력을 볼 수 있다.
Packing doProcess start..... doProcess..... Packing doProcess end..... Packing doStringProcess start..... doStringProcess..... doString Packing doStringProcess end.....
여기 까지 왔다면, 성공 한 것이다. 기존에 각자 사용하던 Class를 Target 으로 생각하고, 포장지를 만들어서 사용하면 된다.
만약 Spring Framework 를 사용하는 경우, 직접 구현할 필요 없이 Spring AOP Around 기능을 사용하면 쉽게 처리가 가능 할 것이다. 위 샘플 코드와 비슷 하기 때문이다.
'Java' 카테고리의 다른 글
Java Html 태그 제거 하기 (0) | 2014.10.29 |
---|---|
Java log4j No appenders could be found for logger 에러 해결 하기 (0) | 2014.10.12 |
Java Clone 사용 하기 (0) | 2014.10.10 |
Java String.split(String regex) 사용 시 '|' 파싱 이 안되는 경우 (1) | 2014.10.08 |
Java HashMap Key 정렬 하기 (0) | 2014.09.24 |