本文仅供学习交流使用,侵权必删。
不作商业用途,转载请注明出处
WHAT 什么是代理模式

代理模式(Proxy Design Pattern)就是在不修改原来代码的情况下,通过增加一个代理类增强原来的功能代码。代理模式提高了代码的扩展性,需要增加非功能性需求的时候,只需要将这部分逻辑在代理类中实现即可,无需修改原来的代码,符合开闭原则。
代理模式和装饰器区别
装饰器与代理看起来非常相似,但从语义上理解其实并不相同。装饰器的增强代码是与原业务逻辑相关的,例如在原来需求上添加新逻辑。代理的增强代码是与业务逻辑不相关的,例如日志记录,事务,鉴权等。
动态代理
假设对每个接口都添加一层代理做日志或者统计,那么每个接口都需要添加一个代理类。如果接口数量较多,代理类个数也会非常多且不易维护,而且代理类中的代码重复度极高,需求稍作变动就需要修改所有的代理类,很显然这种方式是有问题的。
这种问题我们可以使用动态代理来解决。动态代理就是不事先为每个接口编写代理类,而是在运行时动态创建接口对应的代理类代替原来的接口。而Java语言本身就可以通过反射机制实现动态代理。
WHY 为什么使用代理模式
- 提高扩展性,符合开闭原则
- 符合单一职责,业务代码无需加入一些非功能性需求的代码
HOW 代理模式的实现(JAVA)
代理类通常需要实现与被代理类相同的接口或者继承被代理类。这里只实现接口方式以及java动态代理方式
接口实现代理方式
场景:数据获取接口,在获取数据前添加一个代理作为缓存,每次调用数据接口先在缓存中查询是否有数据,无需每次都将请求打到数据库,缓解数据库压力
- 数据接口
import java.util.List;
public interface IDataService {
List getData(String id, boolean cache);
}
- 数据接口实现类
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()));
/*
第二次从缓存中读取数据
从控制台打印结果中可以看到第二次的请求是从缓存表中读取数据并返回
*/
System.out.println("第二次请求:" + Arrays.toString(agent.getData("1", true).toArray()));
}
}
动态代理
场景: 增加一个计数器,统计接口调用次数
- 业务接口
import java.util.List;
public interface IBizService {
List execute();
}
- 业务接口实现类
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("调用次数:" + 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()));
}
}
}
网友评论