介紹
在代理模式(Proxy Pattern)中,一個類代表另一個類的功能。這種類型的設(shè)計模式屬于結(jié)構(gòu)型模式簸呈。
在代理模式中,我們創(chuàng)建具有現(xiàn)有對象的對象店茶,以便向外界提供功能接口蜕便。
意圖
為其他對象提供一種代理以控制對這個對象的訪問
在直接訪問對象時帶來的問題,比如說:要訪問的對象在遠程的機器上忽妒。在面向?qū)ο笙到y(tǒng)中玩裙,有些對象由于某些原因(比如對象創(chuàng)建開銷很大,或者某些操作需要安全控制段直,或者需要進程外的訪問),直接訪問會給使用者或者系統(tǒng)結(jié)構(gòu)帶來很多麻煩溶诞,我們可以在訪問此對象時加上一個對此對象的訪問層鸯檬。
主要角色
- 委托類:實現(xiàn)抽象角色,定義真實角色所要實現(xiàn)的業(yè)務(wù)邏輯螺垢,供代理角色調(diào)用喧务。
- 代理類:實現(xiàn)抽象角色,是真實角色的代理枉圃,通過真實角色的業(yè)務(wù)邏輯方法來實現(xiàn)抽象方法功茴,并可以附加自己的操作。
- 抽象角色:通過接口或抽象類聲明真實角色實現(xiàn)的業(yè)務(wù)方法孽亲。
優(yōu)點
1.職責清晰2.易擴展
缺點
1.由于在客戶端和真實主題之間增加了代理對象坎穿,因此有些類型的代理模式可能會造成請求的處理速度變慢。 2.實現(xiàn)代理模式需要額外的工作返劲,有些代理模式的實現(xiàn)非常復(fù)雜玲昧。
代碼示例
抽象角色:OrderService接口,規(guī)范了委托類實現(xiàn)的業(yè)務(wù)方法
public interface OrderService {
/*
* 創(chuàng)建訂單
*/
boolean createOrder();
/*
* 查找訂單
*/
List listOrder();
/*
* 刪除訂單
*/
boolean removeOrder();
}
委托類:OrderServiceImpl類,訂單業(yè)務(wù)實現(xiàn)類
package com.apesource.service.impl;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;
import com.apesource.service.OrderService;
/*
* 訂單業(yè)務(wù)服務(wù)類
*/
public class OrderServiceImpl implements OrderService{
//
@Override
public boolean createOrder() {
System.out.println("A.創(chuàng)建訂單業(yè)務(wù)步驟1");
System.out.println("B.創(chuàng)建訂單業(yè)務(wù)步驟2");
System.out.println("C.創(chuàng)建訂單業(yè)務(wù)步驟3");
System.out.println("D.創(chuàng)建訂單業(yè)務(wù)步驟4");
System.out.println("E.創(chuàng)建訂單業(yè)務(wù)步驟5");
return true;
}
@Override
public List listOrder() {
System.out.println("A.查找訂單業(yè)務(wù)步驟1");
System.out.println("B.查找訂單業(yè)務(wù)步驟2");
System.out.println("C.查找訂單業(yè)務(wù)步驟3");
return Arrays.asList();
}
@Override
public boolean removeOrder() {
System.out.println("A.刪除訂單業(yè)務(wù)步驟1");
System.out.println("B.刪除訂單業(yè)務(wù)步驟2");
System.out.println("C.刪除訂單業(yè)務(wù)步驟3");
return true;
}
}
代理類:添加程序日志,調(diào)用委托類中的方法
package com.apesource.service.proxy;
import java.util.List;
import java.util.logging.Logger;
import com.apesource.service.OrderService;
import com.apesource.service.impl.OrderServiceImpl;
/*
* 代理類
*/
public class OrderSercviceImplProxy implements OrderService {
// 添加日志
private static Logger log = Logger.getLogger(OrderServiceImpl.class.getName());
// 關(guān)聯(lián)目標類
private OrderService orderServiceImpl;
public OrderSercviceImplProxy() {
// 實例化目標列對象
orderServiceImpl = new OrderServiceImpl();
}
@Override
public boolean createOrder() {
// 添加日志
log.info("開始執(zhí)行創(chuàng)建訂單業(yè)務(wù)");
// 調(diào)用目標類的方法
boolean bool = orderServiceImpl.createOrder();
// 添加日志
log.info("結(jié)束執(zhí)行創(chuàng)建訂單業(yè)務(wù)");
return bool;
}
@Override
public List listOrder() {
// 添加日志
log.info("開始執(zhí)行返回訂單業(yè)務(wù)");
List list = orderServiceImpl.listOrder();
// 添加日志
log.info("結(jié)束執(zhí)行返回訂單業(yè)務(wù)");
return list;
}
@Override
public boolean removeOrder() {
// 添加日志
log.info("開始執(zhí)行刪除訂單業(yè)務(wù)");
Boolean bool = orderServiceImpl.removeOrder();
// 添加日志
log.info("結(jié)束執(zhí)行刪除訂單業(yè)務(wù)");
return bool;
}
}
JDK自帶的動態(tài)代理
無論是動態(tài)代理還是靜態(tài)代理都需要三個角色:目標對象,接口篮绿,代理類孵延。動態(tài)代理主要使用了反射中的知識。
JDK中:
- java.lang.reflect.InvocationHandler(處理器接口):可以通過invoke方法實現(xiàn)對真實角色的代理訪問亲配。
創(chuàng)建一個類并實現(xiàn)InvocationHandler接口尘应,在invoke方法中實現(xiàn)代理類的操作以及調(diào)用目標對象的方法惶凝。因此要先關(guān)聯(lián)目標對象并通過構(gòu)造方法注入目標對象
//與目標對象關(guān)聯(lián)
private Object target;
// 通過構(gòu)造方法得到目標對象
public LogInvocationHander(Object target) {
this.target = target;
}
InvocationHandler接口中的invoke方法:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
}
Object proxy:Proxy創(chuàng)建的代理對象
Method method: 將執(zhí)行的方法方法對象
Object[] args:將執(zhí)行方法的參數(shù)列表
- java.lang.reflect.Proxy類,通過newProxyInstance方法生成動態(tài)代理類和對象犬钢;它的類型是com.sun.proxy.$Proxy
Proxy.newProxyInstance(類加載器梨睁,目標對象實現(xiàn)的所有接口,實現(xiàn)InvocationHander接口類的對象)
通過反射方式獲取類加載器娜饵,目標對象Class獲取所有接口對象Class
Proxy.newProxyInstance(
orderServiceTarget.getClass().getClassLoader(), orderServiceTarget.getClass().getInterfaces(),
logInvocationHander1);
代碼示例
實現(xiàn)InvocationHandler的 LogInvocationHander類坡贺,添加日志并調(diào)用目標類中的方法。
package com.apesource.service.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.logging.Logger;
/*
* *代理類的執(zhí)行過程
* *需要得到目標對象
*/
public class LogInvocationHander implements InvocationHandler {
//與目標對象關(guān)聯(lián)
private Object target;
private static Logger logger = Logger.getLogger(LogInvocationHander.class.getName());
// 通過構(gòu)造方法得到目標對象
public LogInvocationHander(Object target) {
this.target = target;
}
/*
* *運行時得到代理對象,方法對象
*/
/*
* *參數(shù)1:代理的對象 *參數(shù)2:運行期要執(zhí)行的方法的對象,代理和目標的方法名相同 *參數(shù)3:該方法的參數(shù)
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//添加日志
logger.info("代理"+proxy.getClass().getName());
logger.info("方法開始");
Object object = method.invoke(target, args);
logger.info("方法結(jié)束");
return object;
}
}
主函數(shù)中創(chuàng)建LogInvocationHander類的對象箱舞,創(chuàng)建Proxy對象遍坟。
package com.apesource.test;
import java.lang.reflect.Proxy;
import com.apesource.service.OrderService;
import com.apesource.service.PaymentService;
import com.apesource.service.impl.OrderServiceImpl;
import com.apesource.service.impl.PaymentServiceImpl;
import com.apesource.service.proxy.LogInvocationHander;
public class Test01 {
public static void main(String[] args) {
// 創(chuàng)建目標對象
// 訂單的目標對象
OrderService orderServiceTarget = new OrderServiceImpl();
// 支付的目標對象
PaymentService paymentServiceTarget = new PaymentServiceImpl();
// 將目標對象傳入LogInvocationHander,LogInvocationHander是代理真正執(zhí)行的邏輯
LogInvocationHander logInvocationHander1 = new LogInvocationHander(orderServiceTarget);
LogInvocationHander logInvocationHander2 = new LogInvocationHander(paymentServiceTarget);
// 創(chuàng)建代理
/*
* 參數(shù)1:類加載器 參數(shù)2:代理要實現(xiàn)的所有接口,也就是目標對象實現(xiàn)的接口 參數(shù)3:LogInvocationHander,真正執(zhí)行的邏輯
*/
// 通過傳入的類加載器,通過反射的方式,獲取目標類接口數(shù)組,創(chuàng)建出代理對象,通過類型轉(zhuǎn)換為OrderService
OrderService orderServiceProxy = (OrderService) Proxy.newProxyInstance(
orderServiceTarget.getClass().getClassLoader(), orderServiceTarget.getClass().getInterfaces(),
logInvocationHander1);
//調(diào)用的方法,其實調(diào)用了invoke方法晴股,logInvocationHander1中的Method對象
orderServiceProxy.createOrder();
PaymentService paymentServiceproxy = (PaymentService) Proxy.newProxyInstance(
paymentServiceTarget.getClass().getClassLoader(), paymentServiceTarget.getClass().getInterfaces(),
logInvocationHander2);
paymentServiceproxy.aliPay();
}
}