JAVA反射_代理
一、什麼是動態代理
動態代理可以提供對另一個物件的訪問,同時隱藏實際物件的具體事實。代理一般會實現它所表示的實際物件的介面。代理可以訪問實際物件,但是延遲實現實際物件的部分功能,實際物件實現系統的實際功能,代理物件對客戶隱藏了實際物件。客戶不知道它是與代理打交道還是與實際物件打交道。
目的:主要用來做方法的增強,讓你可以在不修改原始碼(不用改變這個方法的簽名,原來呼叫這個方法的類依然能正常工作)的情況下,增強一些方法。在方法執行前後做任何你想做的事情(甚至根本不去執行這個方法),因為在InvocationHandler的invoke方法中,你可以直接獲取正在呼叫方法對應的Method物件,具體應用的話,比如可以新增呼叫日誌,做事務控制等。
還有一個有趣的作用是可以用作遠端呼叫,比如現在有Java介面,這個介面的實現部署在其它伺服器上,在編寫客戶端程式碼的時候,沒辦法直接呼叫介面方法,因為介面是不能直接生成物件的,這個時候就可以考慮代理模式(動態代理)了,通過Proxy.newProxyInstance代理一個該介面對應的InvocationHandler物件,然後在InvocationHandler的invoke方法內封裝通訊細節就可以了。具體的應用,最經典的當然是Java標準庫的RMI,其它比如hessian,各種webservice框架中的遠端呼叫,大致都是這麼實現的。
而像 AspectJ 這種 AOP 剛不同,它直接把人家的 class 程式碼修改了,它就不需要使用代理。
這些在新的 JDK 6 中都可以通過 Instrument 來做到,不過也是個通用的方法,還得通過規則來定製什麼情況下處理,什麼時候不處理。
二、jdk的動態代理
目前Java開發包中包含了對動態代理的支援,但是其實現只支援對介面的的實現。 其實現主要通過java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler介面。
Proxy類主要用來獲取動態代理物件,InvocationHandler介面用來約束呼叫者實現。
動態代理是很多框架和技術的基礎, spring 的AOP實現就是基於動態代理實現的。瞭解動態代理的機制對於理解AOP的底層實現是很有幫助的。
平常寫的程式碼,一般是一個物件直接持有另外一個物件的引用,稱為
靜態代理:
public class StaticProxyMain {
//這裡傳入的是介面型別的物件,方便向上轉型,實現多型
public static void consumer(ProxyInterface pi){
pi.say();
}
public static void main(String[] args) {
StaticProxyMain.consumer(new ProxyObject());
}
}
//代理介面
interface ProxyInterface{
void say();
}
//被代理者
class RealObject implements ProxyInterface{
//實現介面方法
@Override
public void say() {
System.out.println("say");
}
}
//代理者
class ProxyObject implements ProxyInterface{
@Override
public void say() {
System.out.println("hello proxy");
new RealObject().say();
System.out.println("this is method end");
}
}
動態代理:
例子1:
public class DProxyMain {
public static void main(String[] args) {
ArrayList<String> content = new ArrayList<>();
MyInvocationHandler handler = new MyInvocationHandler(content);
Object proxy = Proxy.newProxyInstance(null, new Class[]{List.class}, handler);
if (proxy instanceof List) {
System.out.println("proxy is list");
List<String> mlist = (List<String>) proxy;
mlist.add("one");
mlist.add("two");
mlist.add("three");
mlist.add("apple");
}
System.out.println("proxy:"+proxy.toString());
System.out.println("content:"+content.toString());
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method name:"+method.getName());
if (method.getName().equals("add")) {
if (args[0].equals("apple")) {
return false;
}
}
return method.invoke(this.target, args);
}
}
例子2:
public class DynamicProxyMain {
public static void main(String[] args) {
RealObject realObject = new RealObject();
ProxyInterface proxyInterface = (ProxyInterface) Proxy.newProxyInstance(ProxyInterface.class.getClassLoader(), new Class[]{ProxyInterface.class}, new ProxyObject(realObject));
proxyInterface.say();
}
}
//代理介面
interface ProxyInterface{
void say();
}
//被代理類
class RealObject implements ProxyInterface {
@Override
public void say() {
System.out.println("I'm talking...");
}
}
//代理類,實現InvocationHandler 介面
class ProxyObject implements InvocationHandler {
private Object target = null;
public ProxyObject(Object proxied){
this.target = proxied;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method name:"+method.getName());
return method.invoke(this.target, args);
}
}
1. 利用動態代理實現設計模式,修飾器和介面卡
2. AOP程式設計(Spring AOP)