AOP-日志

AI-摘要
LNotes-AI GPT
AI初始化中...
介绍自己 🙈
生成本文简介 👋
推荐相关文章 📖
前往主页 🏠
前往爱发电购买
AOP-日志
Liuxz- 静态代理:编码期间就决定好了代理的关系
定义:代理对象,是目标对象的接口的子类型,代理对象本身并不是目标对象,而是将目标对象作为自己的属性。
优点:同一种类型的所有对象都能代理
缺点:范围太小了,只能负责部分接口代理 - 动态代理:运行期间才决定好了代理关系(拦截器:拦截所有)
定义:目标对象在执行期间会被动态拦截,插入指定逻辑
优点:可以代理世间万物
缺点:难写
代理对象proxy需要传递三个参数
分别是:
- ClassLoader loader 类加载器
- Class<?>[] interfaces 目标对象实现的接口
- InvocationHandler h 代理逻辑
1、对于类加载器:
userService.getClass().getClassLoader()
| 写法 | 获取的类加载器 | 推荐度 |
|---|---|---|
userService.getClass().getClassLoader() |
UserServiceImpl的类加载器 |
一般 |
UserService.class.getClassLoader() |
UserService接口的类加载器 |
推荐 |
更推荐使用 **UserService.class.getClassLoader()**,原因是: |
- 动态代理的核心是 “代理接口”,使用接口的类加载器更符合语义(代理类需要实现该接口)。
- 避免因
UserServiceImpl被特殊类加载器加载而导致的潜在问题。
2、对于接口:
获取接口的来源:(第二种在动态代理中获取是错误的)
userService.getClass().getInterfaces()- 含义:获取
userService实例所属类(即UserServiceImpl)所实现的所有接口 - 特点:
- 如果
UserServiceImpl实现了多个接口(如UserService、AnotherService),会返回所有接口 - 代理对象会实现所有这些接口,可转换为其中任意一个接口类型
- 如果
- 适用场景:需要代理目标类实现的所有接口时使用
- 含义:获取
UserService.class.getInterfaces()- 含义:获取
UserService接口本身所继承的父接口(如果有的话) - 特点:
- 如果
UserService没有继承其他接口,会返回空数组 - 这种方式错误,因为代理需要的是目标类实现的接口,而不是接口的父接口
- 如果
- 问题:会导致生成的代理对象没有实现
UserService接口,从而无法正常使用
- 含义:获取
new Class[] {UserService.class}- 含义:显式指定只代理
UserService这一个接口 - 特点:
- 无论
UserServiceImpl实现了多少接口,代理对象只实现UserService - 最常用、最推荐的方式,明确指定需要代理的接口
- 无论
- 适用场景:只需要代理特定接口时使用(绝大多数情况)
- 含义:显式指定只代理
总结建议
- 第 2 种方式(
UserService.class.getInterfaces())是错误的,会导致代理失效 - 第 1 种和第 3 种在
UserServiceImpl只实现UserService一个接口时效果相同 - 推荐使用第 3 种方式,因为:
- 明确指定要代理的接口,代码意图更清晰
- 避免意外代理不需要的接口
- 即使目标类未来实现了更多接口,也不会影响当前代理的范围
3.对于代理逻辑
假设我们有一个简单的接口和实现类:
1 | // 目标接口 |
1、类写法:
1 | import java.lang.reflect.InvocationHandler; |
2、Lambda 表达式写法
1 | import java.lang.reflect.InvocationHandler; |
两种写法的对比:
| 维度 | Lambda 表达式写法 | 类写法 |
|---|---|---|
| 代码简洁性 | 更简洁,无需定义单独类,逻辑直接写在使用处 | 代码量稍多,需要单独定义类和方法 |
| 可读性 | 简单逻辑(如单行日志)可读性高;复杂逻辑(多分支、大量代码)会显得臃肿 | 结构清晰,复杂逻辑可通过方法拆分提高可读性 |
| 复用性 | 无法复用,逻辑与当前场景绑定 | 可复用,同一个LogHandler可用于多个代理场景 |
| 状态管理 | 难以维护状态(如需保存额外变量,需依赖外部 final 变量) | 可通过类的成员变量轻松维护状态(如目标对象、配置参数) |
| 调试难度 | 匿名实现,调试时栈轨迹中无具体类名,定位问题稍复杂 | 有明确类名和方法名,调试栈轨迹清晰 |
| 适用场景 | 简单代理逻辑(如日志、计时),且无需复用 | 复杂代理逻辑(如事务管理、权限校验),或需要多处复用 |
评论
匿名评论隐私政策
✅ 你无需删除空行,直接评论以获取最佳展示效果




