设计模式--代理模式

devtools/2024/10/20 8:48:22/

代理模式(Proxy Pattern)是设计模式中的一种结构型模式,它为其他对象提供一种代理以控制对这个对象的访问。代理模式在不改变目标对象功能的前提下,为目标对象添加额外的处理逻辑或控制,比如权限验证、日志记录、事务处理等。通过引入代理对象,可以使得客户端代码与真实目标对象之间解耦,从而增强系统的灵活性和可扩展性。

代理模式的结构
代理模式主要包含三种角色:

抽象主题角色(Subject):定义代理类和真实主题的公共接口,这样可以在任何使用真实主题的地方都可以使用代理。
真实主题角色(Real Subject):定义了代理角色所代表的真实对象,是代理对象所代理的实体。
代理主题角色(Proxy Subject):代理角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象;同时,代理角色可以在执行真实主题前后添加一些附加的操作,相当于对真实主题对象进行封装。
代理模式的分类
根据代理的创建时期,代理模式可以分为两种:

静态代理:代理类在程序运行前就已经存在,一般由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经被创建。
动态代理:动态代理类的源码是在程序运行时由JVM根据反射等机制动态生成的,所以不存在代理类的字节码文件。与静态代理类相比,动态代理更加灵活,但每次调用代理方法时,动态代理机制都会创建一个新的代理实例对象,所以速度相对较慢。
使用场景
远程代理(Remote Proxy):为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是本机的不同进程,也可以是网络上的一台远程服务器。
虚拟代理(Virtual Proxy):根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。
保护代理(Protect or Access Proxy):控制对原始对象的访问。保护代理用于控制不同用户对真实对象的访问权限。
智能指引(Smart Reference Proxy):提供了比简单调用更多的服务。例如,实现了自动缓存,当再次访问同一资源时,可以从缓存处直接返回,而不需要再次去创建或查询。
优缺点
优点:

代理模式能够协调调用者和被调用者,降低系统的耦合度。
在客户端和目标对象之间起到一个中介作用和保护目标对象的作用。
可以通过代理类添加额外的功能。
缺点:

代理模式会造成系统设计中类的数量增加。
在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢。
增加了系统的复杂度。

下面我将分别提供一个使用JDK动态代理和CGLIB代理的案例。

JDK动态代理案例
首先,我们需要定义一个接口和一个实现了该接口的类。然后,我们将创建一个动态代理类,该类将在运行时动态生成,并用于代理对真实对象的调用。
接口定义

public interface HelloService {  String sayHello(String name);  
}

真实类实现

public class HelloServiceImpl implements HelloService {  @Override  public String sayHello(String name) {  return "Hello, " + name;  }  
}

JDK动态代理实现

import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;  public class JdkProxyFactory {  // 创建一个动态代理类  public static <T> T getProxyInstance(Class<T> interfaceClass, InvocationHandler handler) {  return (T) Proxy.newProxyInstance(  interfaceClass.getClassLoader(), // 类加载器  new Class<?>[]{interfaceClass},   // 需要代理的接口  handler                           // 调用处理器  );  }  public static void main(String[] args) {  HelloService realService = new HelloServiceImpl();  HelloService proxyService = JdkProxyFactory.getProxyInstance(  HelloService.class,  (proxy, method, args1) -> {  System.out.println("Before method call");  Object result = method.invoke(realService, args1);  System.out.println("After method call");  return result;  }  );  String result = proxyService.sayHello("World");  System.out.println(result);  }  
}

CGLIB代理案例
CGLIB代理是通过继承被代理类来创建代理对象的,因此它不需要接口。但是,由于它基于继承,所以无法代理final类或者final方法。

真实类定义(无需接口)

public class HelloService {  public String sayHello(String name) {  return "Hello, " + name;  }  
}

CGLIB代理实现
注意:CGLIB库不是JDK自带的,你需要通过Maven或Gradle等构建工具来引入它。

<!-- Maven依赖 -->  
<dependency>  <groupId>cglib</groupId>  <artifactId>cglib</artifactId>  <version>3.3.0</version>  
</dependency>
import net.sf.cglib.proxy.Enhancer;  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  import java.lang.reflect.Method;  public class CglibProxyFactory {  public static <T> T getProxyInstance(Class<T> clazz, MethodInterceptor interceptor) {  Enhancer enhancer = new Enhancer();  enhancer.setSuperclass(clazz);  enhancer.setCallback(interceptor);  return (T) enhancer.create();  }  public static void main(String[] args) {  HelloService realService = new HelloService();  HelloService proxyService = CglibProxyFactory.getProxyInstance(  HelloService.class,  (obj, method, args, proxy) -> {  System.out.println("Before method call");  Object result = method.invoke(realService, args);  System.out.println("After method call");  return result;  }  );  String result = proxyService.sayHello("World");  System.out.println(result);  }  
}

在CGLIB的代理实现中,我们使用了Enhancer类来生成代理对象,并通过MethodInterceptor接口的实现来定义在方法调用前后的行为。

请注意,由于CGLIB代理是通过继承实现的,因此它不能代理final类或者final方法。此外,由于它需要在运行时生成新的类,因此可能会有一定的性能开销。而JDK动态代理则依赖于接口,因此不能代理没有实现接口的类。在选择使用哪种代理方式时,你需要根据你的具体需求来做出决定。

非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤ 分享👥 留言💬thanks!!!


http://www.ppmy.cn/devtools/102449.html

相关文章

[Linux#46][线程->网络] 单例模式 | 饿汉与懒汉 | 自旋锁 |读写锁 | 网络基础 | 书单

目录 1.线程安全 1.1 线程安全的单例模式 1.2 饿汉与懒汉实现方式&#xff1a; 实操 2.锁 3.读者写者问题 实操 4.网络基础 4.1 初始协议 书单&#xff1a; 1.线程安全 STL中的容器和智能指针的线程安全性整理如下&#xff1a;STL容器线程安全性&#xff1a; 状态&…

IOS、OSX逆向工具关系分析

在逆向工程中&#xff0c;工具的使用通常是有一定顺序和层次的&#xff0c;不同工具之间的关系和使用场景也各有不同。下面是根据你的目录中提到的工具进行的分析。 1. OSX 工具集 这些工具主要用于 macOS 环境下的逆向工程&#xff0c;特别是在处理 iOS 应用和二进制文件时非…

AI辅助编码在主流IDE中的智能代码补全说明

AI辅助编码在主流IDE&#xff08;集成开发环境&#xff09;中的智能代码补全和生成功能已经成为现代软件开发不可或缺的一部分&#xff0c;它们显著提高了开发效率和代码质量。以下是几个主流IDE中智能代码补全和生成功能的对比&#xff1a; 1. IntelliJ IDEA 智能代码补全&a…

电影票接口对用户来说有哪些优好处

电影票接口为用户带来的便利性和优惠 购票便利性 电影票接口通过提供在线选座购票功能&#xff0c;极大地方便了用户购票。用户无需前往实体售票处排队&#xff0c;只需通过互联网连接&#xff0c;即可随时随地完成购票。这种便利性不仅节省了用户的时间和精力&#xff0c;也…

案例分享—医疗行业国外优秀界面设计案例

医疗行业UI网页设计需注重用户体验与可访问性&#xff0c;确保页面布局清晰、导航简洁明了&#xff0c;以便用户快速找到所需信息。同时&#xff0c;设计应符合医疗行业规范&#xff0c;传递出专业、可信的形象。 在医疗行业UI网页设计中&#xff0c;色彩搭配与视觉元素的选择至…

AJAX(4)——XMLHttpRequest

XMLHttpRequest 定义&#xff1a;XMLHttpRequest(XHR)对象用于与服务器交互。通过XMLHttpRequest可以在不刷新页面的情况下请求特定URL&#xff0c;获取数据。这允许网页在不影响用于操作的情况下&#xff0c;更新页面的局部内容。XMLHttpRequest在AJAX编程中被大量使用 关系…

Python编程进阶题

Python进阶题目讲解周报 1. 引言 在这份周报中&#xff0c;我们将深入探讨Python编程中的进阶题目&#xff0c;涵盖函数式编程、面向对象编程、错误处理、高级数据结构等主题。我们的目标是帮助您提升Python编程技能&#xff0c;解决更复杂的问题。 2. 函数式编程 2.1 Lamb…

prometheus 运维中遇到的问题

1.Lifecycle API is not enabled.# prometheus启动后修改配置文件就需要再重启生效 可以通过以下方式 热加载 curl -X POST http://localhost:9090/-/reload 请求接口后返回 Lifecycle API is not enabled. 那么就是启动的时候没有开启热更新配置&#xff0c;需要在启动的命…