Giriş
Şu satırı dahil ederiz
Şu satırı dahil ederiz
import java.lang.reflect.Proxy;
Not : Eğer Spring kullanıyorsak CGLIB tercih edilebilirdi. Ancak CGLIB de deprecate edildi
Açıklaması şöyle. InvocationHandler aslında Interceptor olarak düşünülebilir.
There two critical classes: Proxy and InvocationHandler
Proxy: It provides you a static factory method to create a proxy instance on which you make a call. The proxy could delegate your call to the real class
InvocationHandler: It defines an invoke method which will be triggered when you make a call on the proxy intance
Gerçek bir nesneyi sarmalayarak yeni metod ekleyebilmeyi sağlar. Önce elimizde bir arayüz olmalı.
newProxyInstance metodu - ClassLoader + interfaces+ InvocationHandler
InvocationHandler içinde Proxy nesnesinin bir metodu çağrılınca ne yapmak istiyorsak onu yaparız
Örnek - Bir Parametreli Proxy
Elimizde şöyle bir arayüz ve gerçekleştirimi olsun
public class User { private String name; } public interface UserService { void addUser(User user); } public class UserServiceImpl implements UserService { @Override public void addUser(User user) { ... } }
InvocationHandler için şöyle yaparız
public class UserServiceJdkInterceptor implements InvocationHandler { private Object realObj; public UserServiceJdkInterceptor(Object realObject) { super(); this.realObj = realObject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; if (args != null && args.length > 0 && args[0] instanceof User) { User user = (User)args[0]; result = method.invoke(realObj, args); } return result; } }
Kullanmak için şöyle yaparız
UserService target = new UserServiceImpl(); // The real object InvocationHandler interceptor = new UserServiceJdkInterceptor(target); UserService proxy = (UserService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor);
Örnek - Parametresiz ve Method İsmine Bakan Proxy
Elimizde şöyle bir arayüz ve gerçekleştirimi olsun
interface Task { void save(); int load(); } class DefaultTask implements Task { @Override public void save() { System.out.println("save"); } @Override public int load() { System.out.println("load"); return new Random().nextInt(); } }
InvocationHandler nesnesini yaratalım.
class TaskInvocationHandler implements InvocationHandler { private final Object target; public TaskInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("save".equals(method.getName())) { System.out.println("Method name is save"); } else if ("load".equals(method.getName())) { System.out.println("Method name is load"); } return method.invoke(target, args); } }
Şimdi bir Proxy yaratalım.
Task task = (Task) Proxy.newProxyInstance( Task.class.getClassLoader(), new Class[]{Task.class}, new TaskInvocationHandler(new DefaultTask()));
Proxy nesnesini çağıralım
task.save(); task.load();
Çıktı olarak şunu alırız
Method name is save save Method name is load load
Örnek - InvocationHandler Olarak Lambda
public class Streams {
public interface EnhancedStream<T> extends Stream<T> {
List<T> toList();
Iterable<T> toIterable();
}
public static <T> EnhancedStream<T> enhance(Stream<T> stream) {
return (EnhancedStream<T>) Proxy.newProxyInstance(
EnhancedStream.class.getClassLoader(),
new Class<?>[] {EnhancedStream.class},
(proxy, method, args) -> {
...
});
}
Kullanmak için şöyle yaparız.Stream<Integer> stream1 = ...
List<Integer> list = Streams.enhance (stream1).toList();
Stream<Integer> stream2 = ...;
Iterable<Integer> iterable = Streams.enhance(stream2).toIterable();
InvocationHandler olarak verilen Lambda içinde şöyle yaparız.
Elimizde şöyle bir kod olsun
if ("toList".equals(method.getName())) {
return stream.collect(Collectors.toList());
} else if ("toIterable".equals(method.getName())) {
return (Iterable<T>) stream::iterator;
} else {
// invoke method on the actual stream
return method.invoke(stream, args);
}
ÖrnekElimizde şöyle bir kod olsun
interface StateEventListener {
void onEventX();
void onEventY(int x, int y);
void onEventZ(String s);
}
Normalde şöyle yapmamız gerekir. Ancak çok fazla delegation kodu yazmak gerekiyor.class StateMachine implements StateEventListener {
State currentState;
@Override
public void onEventX() {
currentState.onEventX();
}
@Override
public void onEventY(int x, int y) {
currentState.onEventY(x, y);
}
@Override
public void onEventZ(String s) {
currentState.onEventZ(s);
}
}
Delegation yapan basit bir Proxy üreterek kodu azaltabiliriz. Şöyle yaparız.State currentState = ...;
final StateEventListener stateEventPublisher = buildStateEventForwarder();
StateEventListener buildStateEventForwarder() {
Class<?>[] interfaces = {StateEventListener.class};
return (StateEventListener) Proxy.newProxyInstance(getClass().getClassLoader(),
interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
return method.invoke(currentState, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
});
}
Hiç yorum yok:
Yorum Gönder