设计模式--动态代理

动态代理是 Java 中一种常见的设计模式,它允许在运行时创建一个实现一组接口的代理类对象。Java 提供了 java.lang.reflect 包来支持动态代理的实现。在 JDK 中,可以使用 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口来创建动态代理。

下面是一个简单的示例,展示如何使用 JDK 的动态代理来代理一个接口。

步骤概述

  1. 定义接口:首先定义一个接口,代理对象将实现这个接口。

  2. 实现 InvocationHandler 接口:创建一个类实现 InvocationHandler 接口,该接口包含一个方法 invoke,在该方法中定义代理对象的行为。

  3. 使用 Proxy 类创建代理对象:使用 Proxy.newProxyInstance 方法来创建代理对象,该方法接受类加载器、要实现的接口数组和 InvocationHandler 实现类的实例。

当涉及到理解 JDK 动态代理中的 InvocationHandler 接口时,我们可以用更通俗易懂的方式来解释它的作用和功能。

示例

假设有一个接口 UserService

public interface UserService {
    void save(String userName);
    void delete(String userName);
}

 现在我们实现一个 InvocationHandler 接口的类 UserServiceProxy,用于处理代理对象的方法调用:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class UserServiceProxy implements InvocationHandler {
    private Object target;

    public UserServiceProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before invoking " + method.getName());
        
        // 执行目标对象的方法
        Object result = method.invoke(target, args);
        
        System.out.println("After invoking " + method.getName());
        return result;
    }
}

UserServiceProxy 中,我们实现了 InvocationHandler 接口,并覆写了 invoke 方法来定义代理对象的行为。在这个例子中,我们简单地在方法调用前后输出日志。

接下来,我们可以使用 Proxy.newProxyInstance 方法创建代理对象:

import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {
        // 创建真实对象
        UserService realService = new UserServiceImpl();

        // 创建代理对象
        UserService proxy = (UserService) Proxy.newProxyInstance(
            UserService.class.getClassLoader(),
            new Class[] { UserService.class },
            new UserServiceProxy(realService)
        );

        // 调用代理对象的方法
        proxy.save("Alice");
        proxy.delete("Bob");
    }
}

解释代码

  1. 创建真实对象

UserService realService = new UserServiceImpl();

 这里假设 UserServiceImplUserService 接口的实现类

     2.创建代理对象

UserService proxy = (UserService) Proxy.newProxyInstance(
    UserService.class.getClassLoader(),
    new Class[] { UserService.class },
    new UserServiceProxy(realService)
);
  • Proxy.newProxyInstance 方法创建一个代理对象,需要传入类加载器、要实现的接口数组和 InvocationHandler 实现类的实例。
  • UserService.class.getClassLoader() 获取 UserService 接口的类加载器。
  • new Class[] { UserService.class } 指定代理对象实现的接口,这里只有 UserService
  • new UserServiceProxy(realService)InvocationHandler 的实现类实例,用于处理代理对象的方法调用

调用代理对象的方法

proxy.save("Alice");
proxy.delete("Bob");

这些方法调用会被 UserServiceProxy 中的 invoke 方法拦截,并在方法执行前后输出日志。

注意事项

  • 动态代理只能代理接口,不能代理类。
  • Proxy.newProxyInstance 创建的代理对象会实现指定的接口,并委托 InvocationHandler 处理方法调用。

以上就是一个简单的 JDK 动态代理的示例,展示了如何利用 Proxy 类和 InvocationHandler 接口来实现代理对象的创建和方法拦截。

什么是 InvocationHandler?

在使用 JDK 动态代理时,你需要定义一个接口,这个接口是代理对象和真实对象都要实现的。接着,你需要编写一个类来实现 InvocationHandler 接口。这个实现类承担了代理对象的调用处理逻辑,也就是说,当通过代理对象调用接口方法时,实际上会调用 InvocationHandlerinvoke 方法来处理这个调用。

InvocationHandler 的核心功能

InvocationHandler 接口中定义了一个方法 invoke,它接收三个参数:

  • Object proxy:代理对象本身。
  • Method method:被调用的方法对象。
  • Object[] args:方法调用时传入的参数。

invoke 方法中,你可以编写代码来决定如何处理这个方法调用。通常的情况下,你会根据需要:

  • 执行一些额外的逻辑(例如日志记录、性能监控等)。
  • 将方法调用委托给真实对象的对应方法。
  • 根据条件决定是否拦截、修改方法的调用行为等。
为什么需要 InvocationHandler?

动态代理的核心思想是在运行时生成代理对象,这些代理对象能够拦截对其所代理的接口方法的调用,并且能够自定义处理逻辑。InvocationHandler 提供了这样一个处理入口,让你能够控制代理对象如何处理方法调用,从而实现了动态代理的灵活性和可扩展性。

示例场景

举个例子,假设有一个 UserService 接口,其中有一个 getUserById(int id) 方法。你想要在每次调用这个方法时记录日志。你可以通过 JDK 动态代理来实现这个功能:

  1. 定义一个 UserService 接口。
  2. 编写一个 UserServiceImpl 类实现 UserService 接口,提供实际的方法逻辑。
  3. 编写一个 LogInvocationHandler 类实现 InvocationHandler 接口,在 invoke 方法中添加日志记录逻辑。
  4. 使用 Proxy.newProxyInstance 方法创建代理对象,将 UserService 接口和 LogInvocationHandler 关联起来。

这样,当通过代理对象调用 getUserById 方法时,实际上会先进入 LogInvocationHandlerinvoke 方法,你可以在这里编写代码来记录日志,然后再将调用委托给 UserServiceImpl 的相应方法。

  • 17
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值