本文僅供學習交流使用冰悠,侵權必刪。
不作商業(yè)用途皮迟,轉載請注明出處
WHAT 什么是代理模式
代理模式(Proxy Design Pattern)就是在不修改原來代碼的情況下桑寨,通過增加一個代理類增強原來的功能代碼。代理模式提高了代碼的擴展性尉尾,需要增加非功能性需求的時候,只需要將這部分邏輯在代理類中實現(xiàn)即可,無需修改原來的代碼辨图,符合開閉原則。
代理模式和裝飾器區(qū)別
裝飾器與代理看起來非常相似故河,但從語義上理解其實并不相同。裝飾器的增強代碼是與原業(yè)務邏輯相關的鱼的,例如在原來需求上添加新邏輯。代理的增強代碼是與業(yè)務邏輯不相關的猿规,例如日志記錄晌砾,事務坎拐,鑒權等养匈。
動態(tài)代理
假設對每個接口都添加一層代理做日志或者統(tǒng)計都伪,那么每個接口都需要添加一個代理類。如果接口數(shù)量較多陨晶,代理類個數(shù)也會非常多且不易維護,而且代理類中的代碼重復度極高湿刽,需求稍作變動就需要修改所有的代理類,很顯然這種方式是有問題的诈闺。
這種問題我們可以使用動態(tài)代理來解決铃芦。動態(tài)代理就是不事先為每個接口編寫代理類雅镊,而是在運行時動態(tài)創(chuàng)建接口對應的代理類代替原來的接口刃滓。而Java語言本身就可以通過反射機制實現(xiàn)動態(tài)代理。
WHY 為什么使用代理模式
- 提高擴展性卓缰,符合開閉原則
- 符合單一職責,業(yè)務代碼無需加入一些非功能性需求的代碼
HOW 代理模式的實現(xiàn)(JAVA)
代理類通常需要實現(xiàn)與被代理類相同的接口或者繼承被代理類征唬。這里只實現(xiàn)接口方式以及java動態(tài)代理方式
接口實現(xiàn)代理方式
場景:數(shù)據(jù)獲取接口,在獲取數(shù)據(jù)前添加一個代理作為緩存鳍鸵,每次調用數(shù)據(jù)接口先在緩存中查詢是否有數(shù)據(jù),無需每次都將請求打到數(shù)據(jù)庫击罪,緩解數(shù)據(jù)庫壓力
- 數(shù)據(jù)接口
import java.util.List;
public interface IDataService {
List getData(String id, boolean cache);
}
- 數(shù)據(jù)接口實現(xiàn)類
import java.util.Arrays;
import java.util.List;
public class DataServiceImpl implements IDataService {
@Override
public List getData(String id, boolean cache) {
return Arrays.asList("100", "1000", "10000");
}
}
- 緩存代理類
public class DataCacheProxy implements IDataService {
/**
* 被代理類
*/
private IDataService dataService;
/**
* 緩存表
*/
private Map<String, List> cacheMap = new HashMap<>();
public DataCacheProxy(IDataService dataService) {
this.dataService = dataService;
}
/**
* @param id
* @param cache 是否需要查詢緩存
* @return
*/
@Override
public List getData(String id, boolean cache) {
if (cache) {
List lst = cacheMap.get(id);
if (lst != null && !lst.isEmpty()) {
System.out.println("cache return data");
return lst;
}
}
List lst = dataService.getData(id, false);
cacheMap.put(id, lst);
return lst;
}
}
- 客戶端
import java.util.Arrays;
public class ProxyClientMain {
public static void main(String[] args) {
IDataService agent = new DataCacheProxy(new DataServiceImpl());
System.out.println("第一次請求:" + Arrays.toString(agent.getData("1", true).toArray()));
/*
第二次從緩存中讀取數(shù)據(jù)
從控制臺打印結果中可以看到第二次的請求是從緩存表中讀取數(shù)據(jù)并返回
*/
System.out.println("第二次請求:" + Arrays.toString(agent.getData("1", true).toArray()));
}
}
動態(tài)代理
場景: 增加一個計數(shù)器贪薪,統(tǒng)計接口調用次數(shù)
- 業(yè)務接口
import java.util.List;
public interface IBizService {
List execute();
}
- 業(yè)務接口實現(xiàn)類
import java.util.Arrays;
import java.util.List;
public class BizServiceImpl implements IBizService {
@Override
public List execute() {
return Arrays.asList("hello", "world");
}
}
- 代理類
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.atomic.AtomicLong;
public class CounterProxy {
private static final AtomicLong COUNTER = new AtomicLong(0);
public Object createProxy(Object serivce) {
Class[] interfaces = serivce.getClass().getInterfaces();
DynamicProxyHandler handler = new DynamicProxyHandler(serivce);
return Proxy.newProxyInstance(serivce.getClass().getClassLoader(), interfaces, handler);
}
private class DynamicProxyHandler implements InvocationHandler {
private Object bizService;
public DynamicProxyHandler(Object bizService) {
this.bizService = bizService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
long count = COUNTER.addAndGet(1);
try {
Object result = method.invoke(bizService, args);
System.out.println("調用次數(shù):" + count);
return result;
} catch (Exception e) {
System.err.println();
}
return null;
}
}
}
- 客戶端
public class DynamicProxyClientMain {
public static void main(String[] args) {
CounterProxy counterProxy = new CounterProxy();
IBizService bizService = (IBizService) counterProxy.createProxy(new BizServiceImpl());
for (int i = 0; i < 10; i++) {
System.out.println(Arrays.toString(bizService.execute().toArray()));
}
}
}