带你重新认识Java动态代理

yizhihongxing

带你重新认识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日

相关文章

  • vue封装jquery修改自身及兄弟元素的方法

    这个问题需要分步骤来回答。 第一步:引入jQuery 为了在Vue项目中使用jQuery,我们需要先引入jQuery库。可以在html文件中直接引入: <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script> 但在Vue项目中,推荐通过n…

    other 2023年6月25日
    00
  • Nginx服务器的location指令匹配规则详解

    Nginx服务器的location指令匹配规则详解 Nginx是一款高性能的Web服务器和反向代理服务器,它使用location指令来匹配URL,并根据匹配结果执行相应的操作。在本攻略中,我们将详细讲解Nginx服务器的location指令的匹配规则。 1. 精确匹配 精确匹配是最基本的location匹配规则,它使用=操作符进行匹配。示例如下: locat…

    other 2023年8月18日
    00
  • python操作hbase详解

    当然,我很乐意为您提供有关“Python操作HBase详解”的完整攻略。以下是详细的步骤和两个示例: 1 Python操作HBase详解 HBase是一种分布式NoSQL数据库,它是基于Hadoop的HDFS文件系统构建的。Python是一种流行的编程语言,它可以用于操作HBase数据库。以下是使用Python操作HBase的详细步骤: 1.1 安装happ…

    other 2023年5月6日
    00
  • Win11刷新怎么设置为右键菜单的首选?

    要将Win11刷新设置为右键菜单的首选,需要进行以下步骤: 打开注册表编辑器: 按下Win + R键组合,输入regedit并回车,以启动注册表编辑器。 导航到右键菜单项所在的注册表分支: 在注册表编辑器中,使用左侧的目录导航器导航到以下路径: HKEY_CLASSES_ROOT\Directory\Background\shell 此处的“Director…

    other 2023年6月27日
    00
  • C语言进阶:指针的进阶(1)

    以下是C语言进阶中指针的进阶(1)的攻略,分为三个部分:介绍指针的进阶内容、示例说明、代码思路。 指针的进阶 在C语言中,指针是一个非常重要并且强大的概念,它可以让我们直接操作内存,高效地处理数据。在进阶学习指针之前,请确保你已经对指针的基本概念以及操作有了一定的理解。 在指针的进阶学习中,需要掌握以下几个方面的内容: 指针的指针 函数指针 内存管理 示例说…

    other 2023年6月27日
    00
  • vbs搜索文件名或者得到目录列表

    要使用VBScript搜索文件名或者获取目录列表,可以按照以下步骤进行: 1.使用FileSystemObject创建文件系统对象 Set fso = CreateObject("Scripting.FileSystemObject") 2.搜索文件 Set objFolder = fso.GetFolder("C:\Users…

    other 2023年6月26日
    00
  • c/c++中的幂函数

    以下是关于“C/C++中的幂函数”的完整攻略,过程中包含两个示例。 背景 幂函数是一种常见的数学函数,用于计算一个数的幂。在C/C++中,可以使用标准库中的pow函数来计算幂。本攻略将介绍如何在C/C++中使用pow函数。 基本原理 C/C++中,我们可以使用标准库中的pow函数来计算幂。pow函数的原型如下: double pow(double x, do…

    other 2023年5月9日
    00
  • Shell命令之数组表示语法学习

    Shell命令之数组表示语法学习 1. 数组的定义 数组是一种特殊的变量,它包含了多个元素,每个元素可以存储一个值。在Shell中定义数组的语法格式如下: 数组名=(元素1 元素2 ……) 其中,数组名是用户任意定义的名称,元素可以是数字、文本或其他Shell变量。定义数组时,元素之间用空格分隔。 例如,我们可以定义一个包含5个元素的数组: fruit=(&…

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