Java Proxy動態代理簡單範例。
建議先了解什麼是代理模式(Proxy Pattern)才能理解Java的Proxy動態代理,因為背後觀念一樣。
Java Proxy動態代理是基於反射(Reflection)來實現,與一般代理的差別在於其不用事先定義好原物件的代理類別,允許在執行期間(runtime)才生成代理物件供客戶端使用。
使用Java動態代理的步驟有三;
- 被代理對象必須提供介面。
- 實作
InvocationHandler
提供代理要處理的邏輯。 - 使用
Proxy
生成代理物件。
Subject
為RealSubject
實作的介面。
Subject
public interface Subject {
void service();
}
RealSubject
為原物件,Thread.sleep()
模擬執行時耗費的時間。
RealSubject
public class RealSubject implements Subject {
@Override
public void service() {
try {
Thread.sleep(2000L);
System.out.println("Do something...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
LogProxyInvocationHandler
實作InvocationHandler
介面,在invoke()
方法實作代理物件的邏輯,並轉調用原物件的方法。
LogProxyInvocationHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;
public class LogProxyInvocationHandler implements InvocationHandler {
private final Object realSubject; // 被代理的原物件
public LogProxyInvocationHandler(Object realSubject) {
this.realSubject = realSubject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + " 開始於:" + new Date());
Object result = method.invoke(realSubject, args); // 調用原物件的方法
System.out.println(method.getName() + " 結束於:" + new Date());
return result;
}
}
Client
為客戶端,透過Proxy.newProxyInstance()
動態產生代理物件,回傳物件型態為傳入的原物件介面參數。
Client
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
Subject proxy = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(), // 被代理對象的ClassLoader
realSubject.getClass().getInterfaces(), // 被代理對象的實作介面
new LogProxyInvocationHandler(realSubject) // InvocationHandler實作
);
proxy.service();
}
}
執行結果如下。
service 開始於:Wed Nov 18 15:32:15 CST 2020
Do something...
service 結束於:Wed Nov 18 15:32:17 CST 2020
代理物件生成的邏輯也可封裝在代理處理類別LogProxyInvocationHandler
中。
LogProxyInvocationHandler
public class LogProxyInvocationHandler implements InvocationHandler {
private final Object realSubject; // 被代理的原物件
private LogProxyInvocationHandler(Object realSubject) {
this.realSubject = realSubject;
}
// 生成代理
public static Object newInstance(Object realSubject) {
return Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
new LogProxyInvocationHandler(realSubject)
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + " 開始於:" + new Date());
Object result = method.invoke(realSubject, args); // 調用原物件的方法
System.out.println(method.getName() + " 結束於:" + new Date());
return result;
}
}
Client
public class Client {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
Subject proxy = (Subject) LogProxyInvocationHandler.newInstance(realSubject);
proxy.service();
}
}
以上即為Java動態代理的簡單範例。
沒有留言:
張貼留言