随缘玩 一: 代理模式

代理模式

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

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

1. 定义

  • 静态代理

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

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

2. 实现方式

  • 静态代理

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

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

3. 灵活性

  • 静态代理

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

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

4. 性能

  • 静态代理

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

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

5. 应用场景

  • 静态代理

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

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

示例

静态代理示例
java 复制代码
// 主题接口
interface Subject {
    void request();
}

// 真实主题
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

// 静态代理
class Proxy implements Subject {
    private RealSubject realSubject;

    public Proxy(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void request() {
        System.out.println("Proxy: Checking access before calling real subject.");
        realSubject.request();
        System.out.println("Proxy: Logging the request.");
    }
}
动态代理示例
java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 主题接口
interface Subject {
    void request();
}

// 真实主题
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

// 动态代理处理器
class DynamicProxyHandler implements InvocationHandler {
    private Object realSubject;

    public DynamicProxyHandler(Object realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public 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 IUser
    proxy.addUser()
    proxy.delUser()
}

结果

`Proxy.newProxyInstance 说明

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

方法签名

java 复制代码
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)

参数说明

  1. ClassLoader loader

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

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

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

返回值

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

使用示例

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

java 复制代码
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 {
    @Override
    public 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 中使用动态代理进行方法调用的拦截:

kotlin 复制代码
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 UserService

    proxyInstance.addUser("John Doe")
}

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

相关推荐
极梦网络无忧几秒前
Android无障碍服务实现抖音直播间界面监控(场控助手核心原理)
android
海兰15 分钟前
使用 Spring AI 打造企业级 RAG 知识库第二部分:AI 实战
java·人工智能·spring
历程里程碑32 分钟前
二叉树---二叉树的中序遍历
java·大数据·开发语言·elasticsearch·链表·搜索引擎·lua
小信丶1 小时前
Spring Cloud Stream EnableBinding注解详解:定义、应用场景与示例代码
java·spring boot·后端·spring
无限进步_1 小时前
【C++】验证回文字符串:高效算法详解与优化
java·开发语言·c++·git·算法·github·visual studio
亚历克斯神1 小时前
Spring Cloud 2026 架构演进
java·spring·微服务
七夜zippoe1 小时前
Spring Cloud与Dubbo架构哲学对决
java·spring cloud·架构·dubbo·配置中心
海派程序猿1 小时前
Spring Cloud Config拉取配置过慢导致服务启动延迟的优化技巧
java
call me by ur name1 小时前
ERNIE 5.0 Technical Report论文解读
android·开发语言·人工智能·机器学习·ai·kotlin
阿维的博客日记1 小时前
为什么不逃逸代表不需要锁,JIT会直接删掉锁
java