浅谈Java动态代理的实现

浅谈 Java 动态代理的实现

什么是动态代理?

Java 中的代理分为静态代理和动态代理两种。静态代理需要事先写好代理类,通过程序员手动编写的方式,代理对象和目标对象之间的关系就已经确定了。而动态代理是在程序运行时动态生成的代理对象,不需要事先写好代理类。动态代理可以根据目标对象动态地生成代理对象,无需为每个目标对象都编写代理类,增强代码的可重用性。

实现步骤

动态代理的实现需要以下步骤:

  1. 定义一个接口,为某个类的接口创建一个代理对象。
  2. 创建实现 InvocationHandler 接口的类,它必须实现 invoke() 方法,该方法在代理对象中被调用。
  3. 实现 jdk 动态代理的 Proxy 类,它提供了创建动态代理类的静态方法,同时可以实现多个接口。

示例一

假设有一个接口计算器(Calculator),它有一个 add() 方法,实现两个数字相加。我们使用动态代理为其创建代理对象,实现输出日志的功能。

public interface Calculator {
    int add(int a, int b);
}
public class CalculatorHandler implements InvocationHandler {
    private Calculator calculator;

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

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before method executed.");
        Object result = method.invoke(calculator, args);
        System.out.println("after method executed.");
        return result;
    }
}
public class Demo {
    public static void main(String[] args) {
        Calculator calculator = new CalculatorImpl();
        Calculator proxy = (Calculator) Proxy.newProxyInstance(
                Calculator.class.getClassLoader(),
                new Class[]{Calculator.class},
                new CalculatorHandler(calculator));
        int result = proxy.add(1, 2);
        System.out.println("result: " + result);
    }
}

此时,我们调用代理对象的 add() 方法,控制台将打印出 before method executed. 和 after method executed.,表示代理对象的方法已经被调用。

示例二

假设有一个接口用户服务(UserService),它提供了查找用户和更新用户信息的方法。我们使用动态代理为其创建代理对象,实现缓存用户信息的功能,即先从缓存中查找用户信息,若找不到,则从数据库中查找用户信息并更新缓存,若找到则直接返回缓存中的用户信息。

public interface UserService {
    User findUserById(int id);
    void updateUser(User user);
}
public class UserServiceHandler implements InvocationHandler {
    private UserService userService;
    private Map<Integer, User> cache = new HashMap<>();

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

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Integer userId = (Integer) args[0];
        if ("findUserById".equals(method.getName())) {
            User user = cache.get(userId);
            if (user != null) {
                return user;
            }
            user = (User) method.invoke(userService, args);
            cache.put(userId, user);
            return user;
        } else if ("updateUser".equals(method.getName())) {
            method.invoke(userService, args);
            User user = (User) args[0];
            cache.put(user.getId(), user);
            return null;
        } else {
            return method.invoke(userService, args);
        }
    }
}
public class Demo {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        UserService proxy = (UserService) Proxy.newProxyInstance(
                UserService.class.getClassLoader(),
                new Class[]{UserService.class},
                new UserServiceHandler(userService));
        User user1 = proxy.findUserById(1);
        System.out.println("user1: " + user1);
        User user2 = proxy.findUserById(1);
        System.out.println("user2: " + user2);
        user1.setName("John");
        proxy.updateUser(user1);
        User user3 = proxy.findUserById(1);
        System.out.println("user3: " + user3);
    }
}

此时,我们调用代理对象的 findUserById() 方法,第一次输出将从数据库中获取用户信息,第二次输出将从缓存中获取用户信息,第三次输出将从数据库中重新获取用户信息并更新缓存,验证了缓存用户信息的功能。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈Java动态代理的实现 - Python技术站

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

相关文章

  • 详解SpringBoot封装使用JDBC

    下面我来详细讲解如何在SpringBoot中封装使用JDBC。 1. 使用JDBC操作数据库 1.1 创建数据库 首先,我们需要创建一个数据库来进行操作。假设我们使用MySQL数据库,在MySQL客户端中输入以下命令来创建一个名为“test”的数据库。 CREATE DATABASE IF NOT EXISTS test DEFAULT CHARSET ut…

    Java 2023年5月19日
    00
  • Java定时器Timer使用方法详解

    Java定时器Timer使用方法详解 在Java中,有时需要在程序中计划执行某些任务,或者需要按照一定的时间间隔来执行任务。在这种情况下,我们可以使用Java的定时器——Timer。 Timer概述 Java中的定时器类是java.util.Timer,它允许您在某个时间后执行某个任务,或者在某个时间间隔后重复执行某个任务。它是线程安全的,因此您可以同时计划…

    Java 2023年5月20日
    00
  • Mybatis-Plus主键生成策略的方法

    关于Mybatis-Plus主键生成策略的方法,我们来一步步讲解。 什么是Mybatis-Plus主键生成策略 首先,让我们了解一下Mybatis-Plus是什么。Mybatis-Plus是一个Mybatis的增强工具,提供了很多强大的功能,包括自动生成代码、通用CRUD操作、分页插件等等。而Mybatis-Plus主键生成策略就是Mybatis-Plus提…

    Java 2023年5月19日
    00
  • Java有哪些操作字符串的类?区别在哪?

    Java中有多个类可以用于操作字符串,以下是比较常用的几个类: String 类: String 是一个 final 类,字符串是一个对象,一旦被创建,就不能被修改。因为Java中的String对象是可以共享的,所以每次对String进行修改时,都会创建一个新的String对象,影响了性能。 示例1:使用加号操作字符串,每次操作都会创建一个新的 String…

    Java 2023年5月27日
    00
  • Java Fluent Mybatis 项目工程化与常规操作详解流程篇 下

    Java Fluent Mybatis 项目工程化与常规操作详解流程篇 Java Fluent Mybatis 是一个基于 Mybatis 的 fluent 动态 SQL 构建器,可以帮助我们快速生成复杂的 SQL 语句。下面我们将详细讲解 Java Fluent Mybatis 项目工程化与常规操作的流程。 一、创建项目 首先,我们需要创建一个 Maven…

    Java 2023年5月20日
    00
  • JDBC常用接口总结

    对于JDBC常用接口总结的完整攻略,首先我们需要了解下JDBC的基本概念和使用的流程。JDBC即Java Database Connectivity,它是一种用于处理Java与数据库之间连接通讯的API。在Java中,我们可以使用JDBC与各种数据库进行交互,常见的包括MySQL、Oracle、SQL Server等。 在使用JDBC时,我们需要依次完成以下…

    Java 2023年5月20日
    00
  • Java中进程与线程的区别

    Java中进程与线程的区别 在Java中,进程(Process)和线程(Thread)都是常见的概念。虽然它们的功能类似,但它们之间存在明显的不同。了解它们的区别对我们正确地设计和编写多线程程序非常重要。 进程和线程的定义 进程是操作系统操作的基本单位,它是程序执行时的一个实例。它拥有自己的内存空间、系统资源和进程上下文等。每个进程都有一个或多个线程,线程是…

    Java 2023年5月19日
    00
  • JAVA基础之一些不为人知的那些秘密

    JAVA基础之一些不为人知的那些秘密 简介 JAVA是一门广泛使用的编程语言,很多人学习JAVA是为了更好的工作和生活。但是,我们有些知识点在学习过程中往往会被忽略或者被遗忘,这些知识点有时候会对我们的工作产生影响。 下面将会向大家逐一介绍一些JAVA基础中的不为人知的那些秘密。 内容 1. JVM JVM全称是Java虚拟机,它是Java程序的运行环境。J…

    Java 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部