在了解動態(tài)代理之前,有必要先知道什么是靜態(tài)代理。
1. 靜態(tài)代理
在靜態(tài)代理的實現(xiàn)中,代理對象與被代理對象都必須實現(xiàn)同一個借口,在代理對象中可以實現(xiàn)日志記錄等相關(guān)服務(wù),并在需要的時候在呼叫被代理對象。如此代理對象中就可以僅保留業(yè)務(wù)相關(guān)職責(zé)。
示例代碼:
首先定義一個IHello接口:
1
public interface IHello
{
2
public void sayHello(String name);
3
}
然后讓實現(xiàn)業(yè)務(wù)邏輯的HelloSpeaker類實現(xiàn)IHello接口:
1
public class HelloSpeaker implements IHello
{
2
public void sayHello(String name)
{
3
System.out.println("Hello, " + name);
4
}
5
}
將日志記錄功能放入代理對象中,代理對象同樣也要實現(xiàn)IHello接口:
1
import java.util.logging.*;
2
3
public class HelloSpeakerProxy implements IHello
{
4
5
private Logger logger = Logger.getLogger(this.getClass().getName());
6
private IHello helloObject;
7
8
public HelloSpeakerProxy(IHello hello)
{;
9
this.helloObject = hello;
10
}
11
public void sayHello(String name)
{
12
logger.log(Level.INFO, "before sayHello");
13
helloObject.sayHello(name);
14
logger.log(Level.INFO, "after sayHello");
15
}
16
}
編寫測試程序:
1
public class StaticProxyDemo
{
2
public static void main(String[] args)
{
3
HelloSpeakerProxy proxy = new HelloSpeakerProxy(new HelloSpeaker());
4
proxy.sayHello("codingliyi");
5
}
6
// 運行結(jié)果:
7
// 2009-11-7 21:21:55 SpringAOP.HelloSpeakerProxy sayHello
8
// 信息: before sayHello
9
// Hello, codingliyi
10
// 2009-11-7 21:21:55 SpringAOP.HelloSpeakerProxy sayHello
11
// 信息: after sayHello
12
}
靜態(tài)代理缺陷:代理對象的一個接口只服務(wù)于一種類型的被代理對象。如果要代理的方法很多,靜態(tài)代理就無法勝任。
2. 動態(tài)代理
在JDK1.3之后加入了可協(xié)助開發(fā)動態(tài)代理功能的API,不必為特定對象與方法編寫特定的代理對象。使用動態(tài)代理,可以使得一個處理者(Handler)服務(wù)于各個對象。
相關(guān)的接口和類有如下兩個:
1.java.lang.reflect.InvocationHandler接口
該接口僅定義了一個方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
其中,proxy指代理類,method是被代理的方法,args指方法的參數(shù)。
2.java.lang.reflect.Proxy類;
該類最主要的方法:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
其中,loader指被代理類的類加載器;interfaces指被代理類實現(xiàn)的接口,h指方法調(diào)用的處理程序。
動態(tài)代理的示例代碼如下:
DynamicProxyHandler.java
1
public class DynamicProxyHandler implements InvocationHandler
{
2
private Object delegate;
3
4
public DynamicProxyHandler(Object delegate)
{
5
this.delegate = delegate;
6
}
7
8
public Object invoke(Object proxy, Method method, Object[] args)
9
throws Throwable
{
10
System.out.println("調(diào)用方法前");
11
Object result = method.invoke(delegate,args);
12
System.out.println("調(diào)用方法后");
13
return result;
14
}
15
}
DynamicProxyDemo.java
1
public class DynamicProxyDemo
{
2
public static void main(String[] args)
{
3
HelloSpeaker speaker = new HelloSpeaker();
4
IHello hello = (IHello)Proxy.newProxyInstance(speaker.getClass().getClassLoader(), speaker.getClass().getInterfaces(), new DynamicProxyHandler(speaker));
5
hello.sayHello("codingliyi");
6
}
7
// 運行結(jié)果:
8
// 調(diào)用方法前
9
// Hello, codingliyi
10
// 調(diào)用方法后
11
}
動態(tài)代理的實戰(zhàn)步驟:
a. 業(yè)務(wù)接口,一個Interface;
b. 實現(xiàn)業(yè)務(wù)接口的類,即被代理類;
c. 一個繼承了java.lang.reflect.InvocationHandler的Handler類,里面維持了一個被代理對象的引用(Object類型),實現(xiàn)invoke()方法;
d. 使用Proxy.newProxyInstance()將Handler與被代理類關(guān)聯(lián),得到代理類,并強制轉(zhuǎn)化為接口類型;
e. 調(diào)用該接口的方法。