기존 Proxy를 읊어보자.
저번에 사용했던 Internet 관련 자바 코드를 한번 보자.
public interface IInternet {
void connectTo(String host);
}
public class Internet implements IInternet {
void connectTo(String host) {
System.out.println("Connecting to " + host);
}
}
public class BlockedInternet implements IInternet {
private final Internet internet = new Internet();
void connectTo(String host) {
if (host.equals("www.blocked.com")) throw new RuntimeException();
internet.connectTo(host);
}
}
이 코드의 문제점은 무엇일까?
물론, 추상화가 되어있다면 추 후 유지보수나 확장성 측면에서 용이할 수 있지만, 인터넷 같은 경우는 그 자체가 고체화되어 굳이 추상화를 해 줄 필요가 없다고 생각한다.
하지만, Proxy를 사용하기 위해서는 같은 구조를 사용하여야 하기 때문에 Interface를 상속받아야만 이를 구현할 수 있다.
Java Reflection API
Dynamic Proxy를 사용하기 위해서는 Java Reflection API에 대해 간단한 이해가 필요해야 한다.
하지만 이 글은 Java Reflection API에 대한 글이 아니기에 간단하게 이게 뭔지에 대해서만 알고 가자.
Java는 일반적인 다른 언어와 다르게 동적 환경에서 Class의 정보(ield, Method 등) 혹은 Method의 정보(접근자 등)를 다루거나 실행할 수 있는 Interface가 존재하는데, 이가 Java Reflection API이다.
예를 들어 아래와 같은 클래스가 있다고 하자.
public class Target {
private final String name;
public Target(String name) { this.name = name; }
public void hello() { System.out.println("Hello, %s.".formatted(name)); }
}
이 상황에서 동적으로 name이 "Daehyeon"인 Target의 hello를 실행하고자 한다.
// 편의상 import와 예외 처리는 하지 않음.
public static void main(String[] args) {
// 클래스를 동적으로 불러온다.
Class<Target> targetClass = Class.forName("Target");
// 1번째 인수가 String인 생성자를 불러온다.
Constructor<Target> targetConstructor = targetClass.getConstructor(String.class);
// name이 Daehyeon인 Instance를 생성한다.
Target instance = targetConstructor.newInstance("Daehyeon");
// Target#hello 메소드를 불러온다.
Method helloMethod = targetClass.getMethod("hello");
// Target#hello를 instance로 실행한다.
helloMethod.execute(instance);
}
이런식으로 동적으로 실행할 수 있게 된다.
Dynamic Proxy란?
Dynamic Proxy를 사용하면 기존 Proxy의 단점(Interface가 존재해야 한다는 점, 새로운 Method가 추가되면 Proxy도 만들어줘야 한다는 점 등)을 해결할 수 있다.
Dynamic Proxy는 Java에서 InvocationHandler(어떻게 Method를 수정할 것 인지)와 적용시킬 Class를 주면 알아서 Proxy 객체를 생성해준다.
public class Internet {
void connectTo(String host) {
System.out.println("Connecting to " + host);
}
}
위와 같이 Internet Class를 Dynamic Proxy로 생성하고자 한다면 아래와 같이 사용할 수 있다.
Internet proxyInternet = (Internet) Proxy.newProxyInstance(
Internet.class.getClassLoader(),
new Class[]{Internet.class},
(proxy, method, arguments) -> {
// Pre-processing
Object result = method.invoke(proxy, arguments);
// Post-processing
return result;
}
);
기존 Proxy와 다른점이 보이는가? 이 Proxy 객체는 동적으로 작동하기 때문에 매우 유연하다.
새로운 Method가 생겨도 알아서 Proxy가 적용되고, 더 이상 Interface를 만들 필요가 없다.
'Java' 카테고리의 다른 글
[Java] Proxy (0) | 2024.05.16 |
---|---|
[Java] Virtual Thread (0) | 2024.05.12 |