当前位置: 首页 > 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.xdnf.cn/news/1208773.html

相关文章:

  • 计算器4.0:新增页签功能梳理页面,通过IO流实现在用户本地存储数据
  • MySQL数据库 mysql常用命令
  • 再谈亚马逊云科技(AWS)上海AI研究院7月22日关闭事件
  • 实现视频实时马赛克
  • P1098 [NOIP 2007 提高组] 字符串的展开
  • python案例:基于python 神经网络cnn和LDA主题分析的旅游景点满意度分析
  • 小程序中事件对象的属性与方法
  • 微算法科技(NASDAQ:MLGO)应用区块链联邦学习(BlockFL)架构,实现数据的安全传输
  • Django自带的加密算法
  • 3D游戏引擎的“眼睛“:相机系统深度揭秘与技术实现
  • 14、distance_object_model_3d算子
  • 如何用命令行快速提取PPT中的所有图片?
  • 线程崩溃是否导致进程崩溃
  • 【嵌入式电机控制#18】有刷直流串级控制
  • MySQL图解索引篇
  • 大模型技术对部分岗位的影响
  • Apache Ignite 的分布式原子类型(Atomic Types)
  • 在CSS中,如果你想设置一个元素的高度(height)与其宽度(width)相匹配,但又希望宽度使用百分比来定义,你可以通过几种方式来实现。
  • 试用SAP BTP 02C:试用SAP HANA Schemas HDI Containers
  • VSCode使用Code Runner运行C/C++输出[Done] exited with code=0 in xxx seconds
  • SpringBoot整合RocketMQ(rocketmq-client.jar)
  • C++ AI流处理核心算法实战
  • MOGA(多目标遗传算法)求解 ZDT1 双目标优化问题
  • 沪铝本周想法
  • 智能编队重构职场生态:Agentic AI 协同时代来临
  • 基于Blazor进销存管理系统
  • 对College数据进行多模型预测(R语言)
  • thingsboard 自定义动作JS编程
  • 【高阶版】R语言空间分析、模拟预测与可视化高级应用
  • 【C++算法】82.BFS解决FloodFill算法_被围绕的区域