程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • 快速入门

  • 克隆

  • 类型转换

  • 日期时间

  • IO流相关

  • 工具类

  • 语言特性

  • JavaBean

  • 集合类

  • Map

  • Codec编码

  • 文本操作

  • 注解

  • 比较器

  • 异常

  • 数学

  • 线程和并发

  • 图片

  • 网络

  • 源码编译

  • 配置文件

  • 日志

  • 缓存

  • JSON

  • 加密解密

  • DFA查找

  • HTTP客户端

  • 定时任务

  • 扩展

  • 切面

    • 切面代理工具 - `ProxyUtil`
      • 介绍
      • 使用示例
        • 1. 使用 JDK 的动态代理实现切面
        • 2. 使用 Cglib 实现切面
      • 其它方法
      • 原理解析
      • 实际应用场景
      • 总结
  • 脚本

  • Office文档操作

  • 系统调用

  • 图形验证码

  • 网络Socket

  • JWT

  • Hutoll
  • 切面
scholar
2024-08-20
目录

切面代理工具 - ProxyUtil

# 切面代理工具 - ProxyUtil


# 介绍

ProxyUtil 是 Hutool 中提供的切面代理工具,支持基于 JDK 动态代理和 Cglib 的切面实现。它能够帮助开发者在不侵入业务代码的情况下,为方法添加通用功能,如日志记录、性能监控等。无论目标类是否实现接口,ProxyUtil 都能够为其提供灵活的切面代理支持。


# 使用示例

# 1. 使用 JDK 的动态代理实现切面

JDK 动态代理要求被代理的类必须实现接口。以下示例展示了如何使用 JDK 动态代理为一个实现了接口的类添加切面功能:

  1. 定义一个接口:
/**
 * 定义一个动物接口,包含一个吃的行为
 */
public interface Animal {
    void eat();
}
1
2
3
4
5
6
  1. 定义接口的实现类:
/**
 * 猫类实现了 Animal 接口,表示猫会吃鱼
 */
public class Cat implements Animal {

    @Override
    public void eat() {
        // 打印猫的行为
        System.out.println("猫吃鱼");
    }
}
1
2
3
4
5
6
7
8
9
10
11
  1. 使用 TimeIntervalAspect 切面代理上述对象,统计猫吃鱼的执行时间:
import cn.hutool.aop.ProxyUtil;
import cn.hutool.aop.aspects.TimeIntervalAspect;

public class AopExample {
    public static void main(String[] args) {
        // 使用 ProxyUtil 创建代理对象
        Animal cat = ProxyUtil.proxy(new Cat(), TimeIntervalAspect.class);
        cat.eat();
    }
}
1
2
3
4
5
6
7
8
9
10
  1. TimeIntervalAspect 是 Hutool 提供的一个简单切面,继承自 SimpleAspect,用于统计方法执行时间:
import cn.hutool.aop.aspects.SimpleAspect;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.lang.Console;
import java.lang.reflect.Method;

/**
 * 统计方法执行时间的切面
 */
public class TimeIntervalAspect extends SimpleAspect {
    // Hutool 提供的计时器,用于记录时间
    private TimeInterval interval = new TimeInterval();

    @Override
    public boolean before(Object target, Method method, Object[] args) {
        // 方法执行前启动计时器
        interval.start();
        return true;
    }

    @Override
    public boolean after(Object target, Method method, Object[] args) {
        // 方法执行后打印执行时间
        Console.log("Method [{}] execute spend [{}]ms", method.getName(), interval.intervalMs());
        return true;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

执行结果:

猫吃鱼
Method [eat] execute spend [16]ms
1
2

说明:由于 JDK 动态代理的机制,返回的代理对象类型是接口类型(如 Animal),如果直接将其转为实现类(如 Cat),会导致类型转换异常。因此代理对象应按接口类型接收。


# 2. 使用 Cglib 实现切面

与 JDK 动态代理不同,Cglib 可以对没有实现接口的类进行代理。以下示例展示了如何使用 Cglib 为无接口类添加切面功能:

  1. 引入 Cglib 依赖:
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>${cglib.version}</version>
</dependency>
1
2
3
4
5
  1. 定义一个普通类:
/**
 * 狗类没有实现任何接口,表示狗会吃肉
 */
public class Dog {
    public void eat() {
        System.out.println("狗吃肉");
    }
}
1
2
3
4
5
6
7
8
  1. 使用 TimeIntervalAspect 进行切面代理:
import cn.hutool.aop.ProxyUtil;
import cn.hutool.aop.aspects.TimeIntervalAspect;

public class CglibAopExample {
    public static void main(String[] args) {
        // 使用 ProxyUtil 创建代理对象
        Dog dog = ProxyUtil.proxy(new Dog(), TimeIntervalAspect.class);
        dog.eat();
    }
}
1
2
3
4
5
6
7
8
9
10

执行结果:

狗吃肉
Method [eat] execute spend [13]ms
1
2

说明:Cglib 代理不要求目标类实现接口,因此适用范围更广,使用方式与 JDK 动态代理类似。


# 其它方法

ProxyUtil 提供了更多便捷的方法封装,例如:

  • newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h):封装了 Proxy.newProxyInstance 方法,提供泛型返回值,支持更多参数类型。
  • proxy(Object target, Class<? extends SimpleAspect> aspectClass):自动根据目标类选择合适的代理方式(JDK 或 Cglib)。

这些方法简化了代理对象的创建过程,使代码更加简洁。


# 原理解析

动态代理的核心原理是通过生成代理类(如 $Proxy0)来实现方法拦截:

  1. 根据传入的接口动态生成一个代理类,代理类实现了接口中的方法。
  2. 将生成的代理类加载到 JVM 中(即 load $Proxy0 类)。
  3. 代理类通过构造函数接受 InvocationHandler 对象,并在方法调用时通过反射执行被代理对象的方法。
  4. 返回代理对象,并在方法调用时进行切面增强。

# 实际应用场景

  • 日志记录:为方法添加统一的日志记录逻辑。
  • 性能监控:统计方法执行时间,定位性能瓶颈。
  • 事务管理:在方法执行前后添加事务控制逻辑。

通过 ProxyUtil,开发者可以轻松实现这些通用功能,而无需侵入业务代码,极大提升了代码的可维护性和灵活性。


# 总结

ProxyUtil 通过封装 JDK 动态代理和 Cglib,提供了统一的切面代理实现,使开发者能够在不修改现有业务逻辑的情况下,为方法添加通用功能。无论目标类是否实现接口,ProxyUtil 都能够自动选择合适的代理方式,极大简化了切面代理的使用。

如需进一步了解,请参考 Hutool 的官方文档及示例。

编辑此页 (opens new window)
上次更新: 2024/12/28, 18:32:08
模板引擎封装 - `TemplateUtil`
Script工具 - `ScriptUtil`

← 模板引擎封装 - `TemplateUtil` Script工具 - `ScriptUtil`→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式