当前位置: 首页 > news >正文

随缘玩 一: 代理模式

代理模式

代理模式(Proxy Pattern)是一种结构型设计模式,它允许一个对象代表另一个对象进行操作。代理模式通常用于控制对某个对象的访问,或者在访问该对象时添加一些额外的功能(如延迟加载、权限检查、日志记录等)。

静态代理和动态代理是代理模式的两种实现方式,它们各自有不同的特点和使用场景。以下是两者的对比:

1. 定义

  • 静态代理

    • 在编译时就确定代理类的实现。代理类和真实类都需要在代码中明确地定义,并且代理类通常会实现与真实类相同的接口。
  • 动态代理

    • 在运行时根据需要生成代理类。代理类不需要在编译时就定义,而是通过反射机制在运行时动态创建。

2. 实现方式

  • 静态代理

    • 需要手动创建代理类,通常为每个真实类创建一个代理类。例如,如果有 UserService,则需要手动创建 UserServiceProxy
  • 动态代理

    • 使用 Java 的 Proxy 类和 InvocationHandler 接口来创建代理。可以为多个真实类创建一个通用的代理类。

3. 灵活性

  • 静态代理

    • 灵活性较低,因为每个代理类都需要单独实现,代码量较大,维护起来也比较麻烦。
  • 动态代理

    • 灵活性较高,可以在运行时决定代理的行为,减少了代码重复,提高了可维护性。

4. 性能

  • 静态代理

    • 由于代理类在编译时就已经确定,因此性能较好,调用方法时不需要反射。
  • 动态代理

    • 由于使用了反射机制,性能相对较低,但在大多数情况下,这种性能差异是可以接受的。

5. 应用场景

  • 静态代理

    • 适用于代理类数量较少且相对固定的场景,比如一些简单的权限控制、日志记录等。
  • 动态代理

    • 适用于代理类数量较多且需要灵活处理的场景,比如 AOP(面向切面编程)、远程方法调用等。

示例

静态代理示例
// 主题接口
interface Subject {void request();
}// 真实主题
class RealSubject implements Subject {@Overridepublic void request() {System.out.println("RealSubject: Handling request.");}
}// 静态代理
class Proxy implements Subject {private RealSubject realSubject;public Proxy(RealSubject realSubject) {this.realSubject = realSubject;}@Overridepublic void request() {System.out.println("Proxy: Checking access before calling real subject.");realSubject.request();System.out.println("Proxy: Logging the request.");}
}
动态代理示例
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 主题接口
interface Subject {void request();
}// 真实主题
class RealSubject implements Subject {@Overridepublic void request() {System.out.println("RealSubject: Handling request.");}
}// 动态代理处理器
class DynamicProxyHandler implements InvocationHandler {private Object realSubject;public DynamicProxyHandler(Object realSubject) {this.realSubject = realSubject;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Proxy: Checking access before calling real subject.");Object result = method.invoke(realSubject, args);System.out.println("Proxy: Logging the request.");return result;}
}// 使用动态代理
public class DynamicProxyExample {public static void main(String[] args) {RealSubject realSubject = new RealSubject();Subject proxyInstance = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),new Class<?>[]{Subject.class},new DynamicProxyHandler(realSubject));proxyInstance.request();}
}

动态代理实例

/*** 动态代理要求被代理对象必须实现一个接口*/
interface IUser {fun addUser()fun delUser()
}/*** 实现接口*/
class UserImp : IUser{override fun addUser() {println("addUser")}override fun delUser() {println("delUser")}}/*** InvocationHandler 是动态代理的核心接口,用于定义代理对象的逻辑。我们实现一个简单的 InvocationHandler*/
class UserHandler(private val target:Any):InvocationHandler{override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {println("invoke")val result = method?.invoke(target,*(args ?: arrayOf()))println("invoke1")return result}}fun main(){val user = UserImp()val handler = UserHandler(user)val proxy = Proxy.newProxyInstance(user::class.java.classLoader,user::class.java.interfaces,handler) as IUserproxy.addUser()proxy.delUser()
}

结果
在这里插入图片描述

`Proxy.newProxyInstance 说明

Proxy.newProxyInstance 是 Java 中用于创建动态代理的一个静态方法。它允许您在运行时创建一个实现了指定接口的代理实例,并将方法调用转发到指定的处理器。

方法签名

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

参数说明

  1. ClassLoader loader

    • 用于加载代理类的类加载器。通常可以使用目标类的类加载器。
  2. Class<?>[] interfaces

    • 代理类要实现的接口数组。代理实例将实现这些接口。
  3. InvocationHandler h

    • 处理方法调用的处理器。您需要实现 InvocationHandler 接口,并重写 invoke 方法,以定义在代理实例上调用方法时的行为。

返回值

  • 返回一个实现了指定接口的代理实例,该实例会将所有方法调用委托给指定的 InvocationHandler

使用示例

以下是一个简单的使用示例:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 定义一个接口
interface Hello {void sayHello(String name);
}// 实现 InvocationHandler 接口
class HelloInvocationHandler implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (method.getName().equals("sayHello")) {System.out.println("Hello, " + args[0]);}return null;}
}public class DynamicProxyExample {public static void main(String[] args) {// 创建代理实例Hello helloProxy = (Hello) Proxy.newProxyInstance(Hello.class.getClassLoader(),new Class<?>[]{Hello.class},new HelloInvocationHandler());// 调用代理方法helloProxy.sayHello("World");}
}

运行结果

运行上述代码时,输出将是:

Hello, World

注意事项

  • 动态代理只能用于接口,而不能直接用于类。
  • 代理类在运行时生成,因此它们的性能可能不如直接调用实现类的方法。
  • 代理机制在很多框架中被广泛使用,例如 Spring 的 AOP(面向切面编程)。

通过 Proxy.newProxyInstance,您可以灵活地创建代理对象,以便在方法调用时插入自定义逻辑,如日志记录、事务处理等。

应用场景

动态代理在 Android 开发中有多种应用场景,以下是一些常见的应用场景:

1. 网络请求拦截

在进行网络请求时,可以使用动态代理来拦截请求和响应,以便进行日志记录、修改请求参数、添加请求头等。例如,使用 OkHttp 时,可以通过动态代理来实现自定义的拦截器。

2. AOP(面向切面编程)

动态代理常用于实现 AOP 功能,例如在方法执行前后添加日志、权限检查、事务管理等。通过动态代理,可以在不修改业务逻辑的情况下,增强方法的功能。

3. 事件监听

在 Android 中,动态代理可以用于实现事件监听的机制。例如,可以通过动态代理来创建一个通用的事件处理器,动态地为不同的视图设置监听器。

4. 数据绑定

在使用数据绑定库时,动态代理可以用于实现对数据变化的监听。通过动态代理,可以简化视图与数据模型之间的交互,使得 UI 更新更为方便。

5. 权限控制

在某些情况下,动态代理可以用于控制对特定方法的访问权限。通过在代理中添加权限检查逻辑,可以确保只有合适的用户才能调用某些敏感操作。

6. 延迟加载

在需要延迟加载某些资源(如图片、数据等)时,可以使用动态代理来控制何时加载这些资源。只有在真正需要时,才会创建和加载真实对象,从而节省资源。

7. 跨进程通信

在 Android 的 Binder 机制中,动态代理可以用来实现跨进程通信。通过动态代理,可以在客户端和服务端之间传递方法调用,简化跨进程的操作。

示例

以下是一个简单的动态代理示例,展示了如何在 Android 中使用动态代理进行方法调用的拦截:

import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy// 定义接口
interface UserService {fun addUser(name: String)
}// 真实主题
class UserServiceImpl : UserService {override fun addUser(name: String) {println("User added: $name")}
}// 动态代理处理器
class DynamicProxyHandler(private val target: UserService) : InvocationHandler {override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {println("Before method: ${method?.name}")val result = method?.invoke(target, *(args ?: arrayOf()))println("After method: ${method?.name}")return result}
}// 使用动态代理
fun main() {val userService = UserServiceImpl()val proxyInstance = Proxy.newProxyInstance(userService::class.java.classLoader,arrayOf(UserService::class.java),DynamicProxyHandler(userService)) as UserServiceproxyInstance.addUser("John Doe")
}

可看 Kotlin开发编码-动态代理

http://www.lryc.cn/news/603216.html

相关文章:

  • 算法第29天|动态规划dp2:不同路径、不同路径Ⅱ、整数拆分、不同的二叉搜索树
  • 【图像处理基石】如何对遥感图像进行实例分割?
  • 小白学OpenCV系列1-图像处理基本操作
  • 在 Web3 时代通过自我主权合规重塑 KYC/AML
  • [SWPU2019]Web1
  • 链表反转中最常用的方法————三指针法
  • PHP云原生架构:容器化、Kubernetes与Serverless实践
  • redis【1】
  • 小程序视频播放,与父视图一致等样式设置
  • zama test
  • 百元级工业级核心板:明远智睿×瑞萨V2H,开启AIoT开发新纪元
  • PDF转Word免费工具!批量处理PDF压缩,合并, OCR识别, 去水印, 签名等全功能详解
  • 数据结构之时间复杂度
  • 前端css 的固定布局,流式布局,弹性布局,自适应布局,响应式布局
  • ZKmall开源商城中台架构实践:API 网关与服务治理如何撑起电商技术骨架
  • 在 PolkaVM 上用 Rust 实现 ERC20 合约的全流程开发指南
  • 接口自动化测试pytest框架
  • c++-list
  • 【VOS虚拟操作系统】未来之窗打包工具在前端资源优化中的应用与优势分析——仙盟创梦IDE
  • Redis内存使用耗尽情况分析
  • 40+个常用的Linux指令——下
  • 艾利特机器人:光伏机器人如何重塑清洁能源制造新格局
  • 【CDH】CDH环境中升级ZooKeeper的实战记录
  • 基于KMeans、AgglomerativeClustering、DBSCAN、PCA的聚类分析的区域经济差异研究
  • 【Linux知识】Linux Shell 脚本中的 `set -ex` 命令深度解析
  • 复现cacti的RCE(CVE-2022-46169)
  • Go 客户端玩转 ES|QL API 直连与 Mapping Helpers 实战详解
  • upload-labs靶场通关(1-12)
  • 服务器之光:Nginx--反向代理模块详解及演练
  • 图论:Bellman_ford算法