当前位置: 首页 > 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.dtcms.com/a/304412.html

相关文章:

  • 算法导论核心代码精粹
  • USRP X440 和USRP X410 直接RF采样架构的优势
  • 【51单片机静态1位数码管显示按键倒计时控制蜂鸣器】2022-9-28
  • Wndows Docker Desktop-Unexpected WSL error
  • AUTOSAR Mcal Dio - 模块介绍 + EB配置工具介绍
  • 【开源项目】轻量加速利器 HubProxy 自建 Docker、GitHub 下载加速服务
  • Doris中文检索效果调优
  • 自组织遗传算法(Self-Organizing Genetic Algorithm, SOGA)求解Rastrigin函数优化问题
  • 【Rust并发集合】如何在多线程中并发安全地使用集合
  • 【AI News | 20250728】每日AI进展
  • 接口自动化测试pytest框架
  • 网络原理--HTTPHTTPS
  • JAVA_TWENTY—ONE_单元测试+注解+反射
  • MySQL——MVCC
  • ftp加ssl,升级ftps
  • 解决Spring MVC中@PathVariable参数为null导致的404问题:全面解析与最佳实践
  • Spring MVC数据传递全攻略
  • 架构实战——互联网架构模板(“网络层”技术)
  • WINCC选项组配置
  • Spring Boot 请求限流实战:基于 IP 的高效防刷策略
  • Postgresql 查询使用正则
  • SQL158 每类视频近一个月的转发量/率
  • Java 大视界 -- Java 大数据在智能教育学习社区知识图谱构建与知识传播分析中的应用(370)
  • DeepCompare文件深度对比软件的差异内容提取与保存功能深度解析
  • Go语言新手村:轻松理解变量、常量和枚举用法
  • 论文阅读--射频电源在半导体领域的应用
  • 《从HTTP到IP证书:网络身份验证的下一站革命》
  • 如何使用 Git 钩子 hooks 自动化任务?
  • 【MySQL】数据库的简单介绍
  • [2025CVPR-图象分类]ProAPO:视觉分类的渐进式自动提示优化