设计模式--代理模式(Proxy)
2023-09-11 14:16:24 时间
1. 代理模式
1.1. 概念
代理是一种结构设计模式,它提供一个对象作为客户端使用的实际对象的替代品。代理接收客户端请求,完成一些工作(访问控制、缓存等),然后将请求传递给服务对象。
代理对象具有与实际对象拥有相同的接口,这使得它在传递给客户端时可以与实际对象互换。
使用代理模式创建代理对象,让代理对象控制目标对象的访问(目标对象可以是远程的对象、创建开销大的对象或需要安全控制的对象),并且可以在不改变目标对象的情况下添加一些额外的功能
1.2. 结构
- Subject:抽象类或接口,是一个最普通的业务类型定义,无特殊要求。
- RealSubject:被委托角色、被代理角色。是业务逻辑的具体执行者。
- Proxy:委托类、代理类。它把所有抽象类或接口定义的方法给RealSubject实现,并且在RealSubject处理完毕前后做预处理和善后工作。(最简单的比如打印日志)
1.3. 使用场景
使用场景包括但不限于如下:
- 远程代理 :为位于两个不同地址空间对象的访问提供了一种实现机制,可以将一些消耗资源较多的对象和操作移至性能更好的计算机上,提高系统的整体运行效率。
- 虚拟代理:通过一个消耗资源较少的对象来代表一个消耗资源较多的对象,可以在一定程度上节省系统的运行开销。
- 缓冲代理:为某一个操作的结果提供临时的缓存存储空间,以便在后续使用中能够共享这些结果,优化系统性能,缩短执行时间。
- 保护代理:可以控制对一个对象的访问权限,为不同用户提供不同级别的使用权限。
- 智能引用:要为一个对象的访问(引用)提供一些额外的操作时可以使用
1.4. 分类
- 静态代理: 静态代理是指预先确定了代理与被代理者的关系. 代理类与被代理类的依赖关系在编译期间就确定了
- 动态代理: 代理类与被代理类的依赖关系是在程序运行期间确定的,实现方案有2种: JAVA动态代理和cglib动态代理
1.5. cgLib的动态代理原理
动态生成一个要代理类的子类,子类重写要代理类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。
CGLIB底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
CGLIB缺点:对于final方法 或 final类(如StringBuffer, String等),无法进行代理
2. 代码示例
假设要记录对象各个方法的执行时间,则通过动态代理实现如下:
2.1. JDK动态代理
class DynamicProxyTest {
public static void main(String[] args) throws Exception {
Map mapProxyInstance = (Map) Proxy.newProxyInstance(
DynamicProxyTest.class.getClassLoader(), new Class[] { Map.class },
new TimingDynamicInvocationHandler(new HashMap<>()));
mapProxyInstance.put("hello", "world");
mapProxyInstance.get("hello");
CharSequence csProxyInstance = (CharSequence) Proxy.newProxyInstance(
DynamicProxyTest.class.getClassLoader(),
new Class[] { CharSequence.class },
new TimingDynamicInvocationHandler("Hello World"));
csProxyInstance.charAt(10);
csProxyInstance.length();
}
}
class TimingDynamicInvocationHandler implements InvocationHandler {
private static Logger LOGGER = LoggerFactory.getLogger(TimingDynamicInvocationHandler.class);
private final Map<String, Method> methods = new HashMap<>();
private Object target;
public TimingDynamicInvocationHandler(Object target) {
this.target = target;
for(Method method: target.getClass().getDeclaredMethods()) {
this.methods.put(method.getName(), method);
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.nanoTime();
Object result = methods.get(method.getName()).invoke(target, args);
long elapsed = System.nanoTime() - start;
LOGGER.info("Executing {} finished in {} ns", method.getName(), elapsed);
return result;
}
}
2.2. cglib动态代理
class DynamicProxyTest {
public static void main(String[] args) throws Exception {
Map<String,String> mapProxyInstance = (Map) new TimingCglibProxy(new HashMap<String,String>()).getProxyInstance();
mapProxyInstance.put("hello", "world");
mapProxyInstance.get("hello");
//报错,Cannot subclass final class java.lang.StringBuffer
StringBuffer sbProxyInstance = (StringBuffer) new TimingCglibProxy(new StringBuffer("hello world")).getProxyInstance();
sbProxyInstance.length();
}
}
class TimingCglibProxy implements MethodInterceptor {
private static Logger LOGGER = LoggerFactory.getLogger(TimingCglibProxy.class);
private final Map<String, Method> methods = new HashMap<>();
private Object target;
public TimingCglibProxy(Object target) {
this.target = target;
for (Method method : target.getClass().getDeclaredMethods()) {
this.methods.put(method.getName(), method);
}
}
public Object getProxyInstance() {
//工具类
Enhancer en = new Enhancer();
//设置父类
en.setSuperclass(target.getClass());
//设置回调函数
en.setCallback(this);
//创建子类代理对象
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
long start = System.nanoTime();
Object result = methods.get(method.getName()).invoke(target, objects);
long elapsed = System.nanoTime() - start;
LOGGER.info("Executing {} finished in {} ns", method.getName(), elapsed);
return result;
}
}
相关文章
- C#设计模式(13)——代理模式(Proxy Pattern)
- 代理者模式----设计模式系列
- 设计模式——代理模式
- 结构型模式之代理模式
- 设计模式(十一)代理模式Proxy(结构型)
- 代理模式
- 简介Python设计模式中的代理模式与模板方法模式编程
- 《大话设计模式》--代理模式
- 【设计模式】代理模式
- 「补课」进行时:设计模式(5)——从 LOL 中学习代理模式
- 设计模式之代理模式
- 简介Python设计模式中的代理模式与模板方法模式编程
- C#设计模式——代理模式(Proxy Pattern)
- 【设计模式】代理模式
- 不一样的代理模式(设计模式十三)
- k8s:Service的四种类型和三种代理模式
- 设计模式之代理模式(Proxy Pattern)
- 熬夜学Java语言-设计模式之代理模式
- 设计模式-深入剖析动态代理模式(3)内部运作机制-通俗代码版
- Android kotlin 设计模式(单例模式,建造者模式,代理模式)
- Python:设计模式之代理模式
- 设计模式【代理模式】
- 【iOS开发-54】案例学习:通过UIScrollView的缩放图片功能练习代理模式的详细实现
- 设计模式:代理模式
- 设计模式(Python语言)----代理模式