Proxy(代理)模式是通過創建一個代理對象,用這個代理對象代替真實對象,客戶端得到這個代理對象後,操作這個代理對象時,實際上功能還是由真實對象來完成。代理對象夾在客戶端和真實對象之間,相當於一箇中轉,中轉的時候可以添加自己的業務邏輯。
示類代碼:
1、Account接口:
- /**
- * 賬戶接口
- */
- public interface Account {
- public void updateAccount();
- public void queryAccount();
- }
2、實現類:
- public class AccountImpl implements Account {
- @Override
- public void updateAccount() {
- System.out.println("更新賬戶...");
- }
- @Override
- public void queryAccount() {
- System.out.println("查詢賬戶...");
- }
- }
3、代理對象:
- public class AccountProxy implements Account {
- private AccountImpl account;
- public AccountProxy(AccountImpl account) {
- this.account = account;
- }
- @Override
- public void updateAccount() {
- System.out.println("處理之前...");
- account.updateAccount();
- System.out.println("處理之後...");
- }
- @Override
- public void queryAccount() {
- System.out.println("處理之前...");
- account.queryAccount();
- System.out.println("處理之後...");
- }
- }
上面實現的代理方式稱爲靜態代理。通過觀察代碼發現,如果目標接口發生變化,那麼代理類和具體的目標實現類都要發生變化,不靈活。解決這一問題最好的做法是可以通過一個代理類完成全部的代理功能,此時就可使用Java內建的動態代理來完成。
靜態代理實現的時候,若在目標接口中定義很多方法,代理類裏也要實現很多方法,也動態代理實現的時候,雖然目標接口上定義了很多方法,但代理類只有一個invoke方法。這樣,當目標接口發生變化時,動態代理的接口就不需要發生變化了。
Java的動態代理目前只能代理接口,基本的實現是依靠Java的反射機制和動態生成class的技術,來動態生成被代理的接口的實現對象,若要實現類的代理,可以使用cglib。
Java動態代理中包含一個類和一個接口:
InvocationHandler接口:
public interface InvocationHandler{
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
參數說明:
Object proxy:被代理的對象
Method method:要調用的方法
Object[] args:方法調用時需要的參數
Proxy類:
Proxy是專門完成代理的操作類,可通過此類爲一個或多個接口動態的生成實現類,此類提供瞭如下方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumenException
參數說明:
ClassLoader loader:定義代理類的類加載器(目標對象)
Class<?>[] interfaces:代理類要實現的接口列表
InvocationHandler h:指派方法調用的調用處理程序
上述Account接口的代理類示例代碼如下:
- public class AccountProxy implements InvocationHandler {
- private Object target;
- // 綁定委託對象並返回一個代理類
- public Object bind(Object target) {
- this.target = target;
- return Proxy.newProxyInstance(target.getClass().getClassLoader(),
- target.getClass().getInterfaces(), this); //要綁定一個接口(cglib彌補了這一缺陷)
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- Object result = null;
- System.out.println("開始...");
- result = method.invoke(target, args);
- System.out.println("結束...");
- return result;
- }
- }
寫一單元測試方法:
- @Test
- public void test() {
- AccountProxy accountProxy = new AccountProxy();
- Account account = (Account) accountProxy.bind(new AccountImpl());
- account.updateAccount();
- account.queryAccount();
- }