Hutool Hutool
(opens new window)
🏡首页
📖指南
  • 核心(Hutool-core)
  • 配置文件(Hutool-setting)
  • 日志(Hutool-log)
  • 缓存(Hutool-cache)
  • JSON(Hutool-json)
  • 加密解密(Hutool-crypto)
  • DFA查找(Hutool-dfa)
  • 数据库(Hutool-db)
  • HTTP客户端(Hutool-http)
  • 定时任务(Hutool-cron)
  • 扩展(Hutool-extra)
  • 布隆过滤(Hutool-bloomFilter)
  • 切面(Hutool-aop)
  • 脚本(Hutool-script)
  • Office文档操作(Hutool-poi)
  • 系统调用(Hutool-system)
  • 图形验证码(Hutool-captcha)
  • 网络Socket(Hutool-socket)
  • JWT(Hutool-jwt)
💡javaDoc (opens new window)
⏳更新记录 (opens new window)
  • 🍎gitee (opens new window)
  • 🍏github (opens new window)
(opens new window)
🏡首页
📖指南
  • 核心(Hutool-core)
  • 配置文件(Hutool-setting)
  • 日志(Hutool-log)
  • 缓存(Hutool-cache)
  • JSON(Hutool-json)
  • 加密解密(Hutool-crypto)
  • DFA查找(Hutool-dfa)
  • 数据库(Hutool-db)
  • HTTP客户端(Hutool-http)
  • 定时任务(Hutool-cron)
  • 扩展(Hutool-extra)
  • 布隆过滤(Hutool-bloomFilter)
  • 切面(Hutool-aop)
  • 脚本(Hutool-script)
  • Office文档操作(Hutool-poi)
  • 系统调用(Hutool-system)
  • 图形验证码(Hutool-captcha)
  • 网络Socket(Hutool-socket)
  • JWT(Hutool-jwt)
💡javaDoc (opens new window)
⏳更新记录 (opens new window)
  • 🍎gitee (opens new window)
  • 🍏github (opens new window)
  • 快速入门

  • 核心(Hutool-core)

  • 配置文件(Hutool-setting)

  • 日志(Hutool-log)

  • 缓存(Hutool-cache)

  • JSON(Hutool-json)

  • 加密解密(Hutool-crypto)

  • DFA查找(Hutool-dfa)

  • 数据库(Hutool-db)

  • HTTP客户端(Hutool-http)

  • 定时任务(Hutool-cron)

  • 扩展(Hutool-extra)

  • 布隆过滤(Hutool-bloomFilter)

  • 切面(Hutool-aop)

    • 概述
    • 切面代理工具-ProxyUtil
      • 使用
        • 使用JDK的动态代理实现切面
        • 使用Cglib实现切面
      • 其它方法
      • 原理
  • 脚本(Hutool-script)

  • Office文档操作(Hutool-poi)

  • 系统调用(Hutool-system)

  • 图形验证码(Hutool-captcha)

  • 网络Socket(Hutool-socket)

  • JWT(Hutool-jwt)

  • 指南
  • 切面(Hutool-aop)
Hutool
2023-03-28
目录

切面代理工具-ProxyUtil

特别赞助 by:

# 使用

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

  1. 我们定义一个接口:
public interface Animal{
	void eat();
}
  1. 定义一个实现类:
public class Cat implements Animal{

	@Override
	public void eat() {
		Console.log("猫吃鱼");
	}
	
}
  1. 我们使用TimeIntervalAspect这个切面代理上述对象,来统计猫吃鱼的执行时间:
Animal cat = ProxyUtil.proxy(new Cat(), TimeIntervalAspect.class);
cat.eat();

TimeIntervalAspect位于cn.hutool.aop.aspects包,继承自SimpleAspect,代码如下:

public class TimeIntervalAspect extends SimpleAspect{
	//TimeInterval为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", target.getClass().getName(), method.getName(), interval.intervalMs());
		return true;
	}
}

执行结果为:

猫吃鱼
Method [cn.hutool.aop.test.AopTest$Cat.eat] execute spend [16]ms

在调用proxy方法后,IDE自动补全返回对象为Cat,因为JDK机制的原因,我们的返回值必须是被代理类实现的接口,因此需要手动将返回值改为Animal,否则会报类型转换失败。

# 使用Cglib实现切面

使用Cglib的好处是无需定义接口即可对对象直接实现切面,使用方式完全一致:

  1. 引入Cglib依赖
<dependency>
	<groupId>cglib</groupId>
	<artifactId>cglib</artifactId>
	<version>${cglib.version}</version>
</dependency>
  1. 定义一个无接口类(此类有无接口都可以)
public class Dog {
	public String eat() {
		Console.log("狗吃肉");
	}
}
Dog dog = ProxyUtil.proxy(new Dog(), TimeIntervalAspect.class);
String result = dog.eat();

执行结果为:

狗吃肉
Method [cn.hutool.aop.test.AopTest$Dog.eat] execute spend [13]ms

# 其它方法

ProxyUtil中还提供了一些便捷的Proxy方法封装,例如newProxyInstance封装了Proxy.newProxyInstance方法,提供泛型返回值,并提供更多参数类型支持。

# 原理

动态代理对象的创建原理是假设创建的代理对象名为$Proxy0:

  1. 根据传入的interfaces动态生成一个类,实现interfaces中的接口
  2. 通过传入的classloder将刚生成的类加载到jvm中。即load$Proxy0类
  3. 调用$Proxy0的$Proxy0(InvocationHandler)构造函数 创建$Proxy0的对象,并且用interfaces参数遍历其所有接口的方法,并生成实现方法,这些实现方法的实现本质上是通过反射调用被代理对象的方法。
  4. 将$Proxy0的实例返回给客户端。
  5. 当调用代理类的相应方法时,相当于调用InvocationHandler.invoke(Object, Method, Object [])方法。
上次更新: 2025/05/06, 10:48:51
概述
概述

← 概述 概述→

Theme by Vdoing | Copyright © 2023-2025 Hutool | MulanPSL-2.0
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×