带你重新认识Java动态代理

带你重新认识Java动态代理

什么是动态代理?

代理模式是一种设计模式,它允许我们创建一个对象,该对象充当其他对象的代表或占位符,以便控制对这些对象的访问。

在Java中,我们可以使用静态代理和动态代理。其中,静态代理需要自行编写代理类,因此显得比较复杂。而动态代理则可以通过Java API来实现,大大减少了编程的工作量。

动态代理是Java中的一项高级编程技术,它允许我们在运行时动态生成代码,从而实现代理对象的创建和管理。在动态代理模式中,我们不需要显式地编写代理类,而是依赖于Java反射机制在运行时生成代理对象并自动处理代理方法。

动态代理的优点

  • 类的职责分离:代理类作为原有类的代理,可以将一些原有类中的方法抽象出来,保留真正关心的核心业务逻辑,使得代理类具有更高的聚合性和可维护性。
  • 代码复用:一个代理类可以代理多个委托类,而静态代理则需要每个委托类对应一个代理类,代码冗余度更高。
  • 高可扩展性:动态代理在实现时使用反射机制,在运行时动态地创建了代理类的对象,因此可以在代理类的实现上进行更多的扩展,实现更复杂的业务逻辑。

动态代理的缺点

  • 性能较差:由于动态代理的实现机制是基于反射实现的,因此在运行时会有额外的开销,而静态代理则可以直接调用委托对象的方法,效率更高。
  • 编程复杂度高:相较于静态代理,动态代理实现的过程较为复杂,需要涉及到反射机制、方法调用等多个方面。

举例说明

下面我们通过两个示例来详细说明动态代理的实现过程。

示例1

首先,我们需要定义一个接口UserService,并在其中定义一个getUser方法。

public interface UserService {
    User getUser(String name);
}

然后,我们定义一个UserServiceImpl类来实现接口中的方法。

public class UserServiceImpl implements UserService {
    @Override
    public User getUser(String name) {
        return new User(name);
    }
}

其中,User类是一个简单的JavaBean类,用来存储用户信息。

public class User {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

接着,我们定义一个UserInvocationHandler类,用来处理代理对象的方法调用。

public class UserInvocationHandler implements InvocationHandler {
    private UserService userService;

    public UserInvocationHandler(UserService userService) {
        this.userService = userService;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before invoke method: " + method.getName());
        Object result = method.invoke(userService, args);
        System.out.println("after invoke method: " + method.getName());
        return result;
    }
}

最后,我们在main方法中创建一个代理对象,并调用其getUser方法。在代理对象调用getUser方法之前和之后,都会输出一些调试信息。

public static void main(String[] args) {
    UserService userService = new UserServiceImpl();
    UserInvocationHandler invocationHandler = new UserInvocationHandler(userService);
    UserService proxy = (UserService) Proxy.newProxyInstance(
            UserService.class.getClassLoader(),
            new Class[]{UserService.class},
            invocationHandler);
    User user = proxy.getUser("Tom");
    System.out.println("get user: " + user.getName());
}

示例2

接下来,我们用另外一个示例来说明动态代理的实现过程。

首先,我们需要定义一个接口Calculator,并在其中定义两个方法addsubtract

public interface Calculator {
    int add(int x, int y);

    int subtract(int x, int y);
}

然后,我们定义一个CalculatorImpl类来实现接口中的方法。

public class CalculatorImpl implements Calculator {
    @Override
    public int add(int x, int y) {
        System.out.println("add: " + x + " + " + y);
        return x + y;
    }

    @Override
    public int subtract(int x, int y) {
        System.out.println("subtract: " + x + " - " + y);
        return x - y;
    }
}

接着,我们定义一个CalculatorInvocationHandler类,用来处理代理对象的方法调用。

public class CalculatorInvocationHandler implements InvocationHandler {
    private Calculator calculator;

    public CalculatorInvocationHandler(Calculator calculator) {
        this.calculator = calculator;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before invoke method: " + method.getName());
        Object result = method.invoke(calculator, args);
        System.out.println("after invoke method: " + method.getName());
        return result;
    }
}

最后,我们在main方法中创建一个代理对象,并调用其addsubtract方法。在代理对象调用addsubtract方法之前和之后,都会输出一些调试信息。

public static void main(String[] args) {
    Calculator calculator = new CalculatorImpl();
    CalculatorInvocationHandler invocationHandler = new CalculatorInvocationHandler(calculator);
    Calculator proxy = (Calculator) Proxy.newProxyInstance(
            Calculator.class.getClassLoader(),
            new Class[]{Calculator.class},
            invocationHandler);
    int result1 = proxy.add(2, 3);
    System.out.println("result1: " + result1);
    int result2 = proxy.subtract(5, 2);
    System.out.println("result2: " + result2);
}

注意,在示例中,我们使用了Java反射机制来调用代理对象的方法。由于反射机制会带来额外的性能开销,因此在实际应用中需要慎重选择。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:带你重新认识Java动态代理 - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • PHP 5.0创建图形的实用方法完整篇第1/3页

    PHP 5.0创建图形的实用方法完整篇 第1/3页 在PHP 5.0中,有多种方法可以创建和操作图形。以下是详细的攻略: 1. 使用GD库创建图像 GD库是一个常用的PHP图形库,可以用于创建和处理图像。以下是使用GD库创建图像的示例代码: // 创建一个空白图像 $image = imagecreatetruecolor(400, 300); // 设置背…

    other 2023年10月15日
    00
  • 浅析AngularJS中的生命周期和延迟处理

    浅析AngularJS中的生命周期和延迟处理 什么是生命周期? 在AngularJS中,每个组件(如控制器、指令、服务、过滤器等)都有它自己的生命周期。生命周期定义了组件从实例化到销毁的整个过程。在这其中,组件会经历一些固定的事件,称为生命周期事件或生命周期钩子。 生命周期钩子指的是AngularJS执行的关键点,这些关键点将会触发一些事件,如创建、更新和销…

    other 2023年6月27日
    00
  • shell脚本配置hostname的方法步骤

    Shell脚本配置hostname的方法步骤 在Shell脚本中,可以使用以下步骤来配置主机名(hostname): 获取当前主机名:首先,我们需要获取当前主机的主机名。可以使用hostname命令来获取当前主机名,并将其保存到一个变量中。以下是一个示例: shell current_hostname=$(hostname) echo \”当前主机名:$cu…

    other 2023年8月15日
    00
  • JavaScript实现从数组中选出和等于固定值的n个数

    下面是JavaScript实现从数组中选出和等于固定值的n个数的完整攻略: 问题描述 假设有一个数组arr和一个固定值target,如何从arr中选出n个数,使得这n个数的和等于target。 解决方案 1. 暴力破解 最简单粗暴的方法当然是暴力破解,即枚举所有的 n 个数的组合情况,计算它们的和,如果等于 target,则返回这个组合。但其时间复杂度为O(…

    other 2023年6月25日
    00
  • Win11电脑重启很慢怎么办? win11系统电脑开机慢的解决办法

    Win11电脑重启很慢怎么办? 在Win11系统中,电脑重启很慢可能是由于某些启动项、服务等导致的。下面介绍几种可能的解决办法。 1. 检查启动项 启动项指的是开机自启动的应用程序。有些应用程序在开机自启时可能会占用大量CPU资源,进而导致电脑开机速度变慢。因此,检查和优化启动项可以缩短电脑开机时间。 步骤: 打开任务管理器,选择“启动”选项卡。 对于不必要…

    other 2023年6月26日
    00
  • Android实现沉浸式状态栏功能

    Android实现沉浸式状态栏功能攻略 沉浸式状态栏是一种在Android应用中隐藏系统状态栏并使应用内容占据整个屏幕的功能。下面是实现沉浸式状态栏功能的完整攻略。 步骤一:设置主题样式 首先,在styles.xml文件中定义一个新的主题样式,用于设置沉浸式状态栏的属性。示例代码如下: <style name=\"AppTheme\&quot…

    other 2023年8月26日
    00
  • linux下普通文件和目录文件区别详解

    Linux下普通文件和目录文件区别详解 在 Linux 操作系统中,普通文件和目录文件是两种最基本最常用的文件类型。本文将详细讲解在 Linux 系统中普通文件和目录文件的区别。 1. 普通文件 普通文件是指不包含任何特殊属性的文件,可以存储文本、二进制数据等各种格式的文件。普通文件有很多种类型,比如文本文件、二进制文件、图片文件、压缩文件等,我们可以使用 …

    other 2023年6月26日
    00
  • 微信小程序实现文章关注功能详细流程

    followedArticles: [] }, onLoad() { // 从后端接口获取用户关注的文章列表 // … }});“` 以上是实现微信小程序文章关注功能的完整流程。希望对您有所帮助!如果您还有其他问题,请随时提问。

    other 2023年10月17日
    00
合作推广
合作推广
分享本页
返回顶部