프록시, 다이나믹 프록시는 접근을 제어하기 위함인가? 기능을 확장하기 위함인가?? 사실 둘다 아닌가?? 아니, 애초에 기능을 확장하기 위해 프록시를 써도, 자동적으로 접근을 제어하게된다.
지난 포스팅에서 구현했던 프록시를, Dynamic Proxy로 구현해보자.
JDK Dynamic Proxy는 자바의 리플렉션을 이용해 구현한다.
즉, 개발자가 직접 구현할 때도 자바의 리플렉션을 이용해야 한다는 소리이다.
java.lang.reflect패키지
java.lang.relfect 패키지에 Proxy 클래스가 제공된다.
Class Proxy
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.
이 Proxy클래스를 이용해서 Dynamic Proxy를 구현해보자.
Java API이 reflect 패키지의 Proxy클래스 설명을 보면 아래와 같이 프록시 클래스를 생성하는 예시가 나와있다.
To create a proxy for some interface Foo:
InvocationHandler handler = new MyInvocationHandler(...);
Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
newInstance(handler);
or more simply:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class<?>[] { Foo.class },
handler);
우선, 간단한 방법인 아래의 방법으로 진행해보자.
newProxyInstance
newProxyInstance
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
Parameters:
- loader - the class loader to define the proxy class
- interfaces - the list of interfaces for the proxy class to implement
- h - the invocation handler to dispatch method invocations to
Returns:
- a proxy instance with the specified invocation handler of a proxy class that is defined by the specified class loader and that implements the specified interfaces
일단 프록시 객체를 반환하는데... 구체화된 invocation handler를 호출하는 메소드를 가진?... 뭔소리 일까...일단 Invocation handler가 무엇인지 알아야 겠다.
InvocationHandler
InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
끝의 두문장이 핵심인것 같다. 프록시 객체의 메소드가 호출되면, invocation handler의 invoke메소드를 호출한다... 의 느낌인데, 그 뜻은 프록시 객체가 구현하는 메소드는 invocation handler의 invoke를 통해 구현한다고 보면 될것 같다.
Object invoke(Object proxy,
Method method,
Object[] args)
throws Throwable
Java8 API의 invoke메소드 설명을 봤지만, 명확히 이해하긴 힘든것 같다.. (추가적인 블로그 글을 참고해 다이나믹 프록시를 완성했다.)
다이나믹 프록시 코드
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyClient {
public static void main(String[] args) {
User user = (User)Proxy.newProxyInstance(ProxyClient.class.getClassLoader(),new Class<?>[] { User.class }
,new InvocationHandler() {
User targetUser = new TargetUser();
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("pre workout invoked by Proxy");
Object invokedMethod = method.invoke(targetUser, args);
System.out.println("post relax invoked by Proxy");
return invokedMethod;
}
});
user.useSomething();
}
}
기존 User 인터페이스와 TargetUser클래스는 그대로다. 단 프록시 객체를 동적으로 생성하기 때문에, 이전코드의 프록시 클래스였던 UserProxy 클래스는 더이상 필요없다.
java.lang.reflect패키지의 Proxy클래스에서 제공하는 newProxyInstance메소드를 통해 User타입으로 프록시 객체를 생성, 동적으로 생성된 프록시 객체의 useSomthing()을 호출했다.
newInstance()의 3번째 인자로 프록시의 메소드 호출을 담당하는 InvocationHandler를 익명클래스로 선언과 구현하고, invoke메소드에 targetUser의 메소드를 호출, 전후로 추가적인 작업을 수행하도록 구현했다.
References
'프로그래밍 > Java' 카테고리의 다른 글
Builder패턴이란? (0) | 2022.08.18 |
---|---|
Java GC 1차개정본 (0) | 2022.06.25 |
Dynamic Proxy직접 구현해보기-1 (0) | 2021.08.10 |
Comparator의 동작방식 (0) | 2021.07.27 |
Comparator VS Comparable (0) | 2021.07.26 |