当前位置: 首页 > news >正文

代理对象与目标对象

1. 定义:代理对象和目标对象

1.1 目标对象(Target Object)

  • 目标对象是指 被增强的原始对象,即需要通过 AOP 切面(Aspect)增强功能的业务对象(原始类)。
  • 增强逻辑(Advice)最终是应用在目标对象的方法上的。
  • 目标对象是实际的业务逻辑持有者,它的功能由我们开发时编写的类直接实现。

例子:

public class UserService {public void createUser() {System.out.println("Creating user...");}
}
  • UserService 是目标对象,定义了业务逻辑。

1.2 代理对象(Proxy Object)

  • 代理对象是 Spring AOP 框架生成的 动态代理类实例,它是目标对象的增强版本。
  • 代理对象会包装目标对象,并在执行目标对象方法时:
    • 增加切面中的增强逻辑(如日志、事务等)。
    • 将调用转发到目标对象的方法。
  • 代理对象在 Spring 应用上下文中取代了目标对象,用户通过代理对象间接访问目标对象的功能。

代理对象的特点:

  • 它的外部表现与目标对象相同(方法签名一致)。
  • 它在方法调用时,可以插入增强逻辑(Advice)。

例子:
如果为 UserService 添加一个切面增强功能(例如日志记录),Spring 会生成一个代理对象来拦截方法调用。

UserService proxy = (UserService) context.getBean(UserService.class);
proxy.createUser();

2. 两者的区别

特性目标对象(Target Object)代理对象(Proxy Object)
定义原始的、未增强的业务对象Spring AOP 框架生成的动态代理对象
是否真实存在是真实存在的类实例(用户定义的类)是由 Spring 动态生成的新实例
增强逻辑(Advice)不包含增强逻辑包含增强逻辑,方法调用可能被拦截
访问方式只能通过代理对象间接访问直接被容器返回,外部调用的方法实际上由代理处理
与 Spring 的关系原始业务逻辑的实现者通过 Spring AOP 动态生成的代理实现
实际工作执行被调用的具体业务方法拦截方法调用,并决定是否执行增强逻辑或目标对象
反射行为目标对象的方法是用户定义的,直接反射可访问代理对象的方法是动态生成的,可能有额外逻辑

3. Spring 中是如何生成代理对象的

Spring AOP 中的代理对象生成有两种方式,分别基于 JDK 动态代理CGLIB 动态代理
代理的选择由目标对象的类型决定:

3.1 JDK 动态代理

  • 使用 Java 提供的动态代理机制(java.lang.reflect.Proxy)。
  • 要求目标对象实现一个或多个接口。
  • 代理对象是目标对象实现的接口的一个实现类。

优点:

  • 轻量级,直接基于接口生成代理。

缺点:

  • 目标对象必须实现接口,如果是纯类无法使用。

示例:

public interface UserService {void createUser();
}public class UserServiceImpl implements UserService {@Overridepublic void createUser() {System.out.println("Creating user...");}
}
  • Spring 会为 UserServiceImpl 生成一个动态代理对象,它实现了 UserService 接口。

3.2 CGLIB 动态代理

  • 使用 CGLIB(Code Generation Library)生成目标对象的子类作为代理对象。
  • 不要求目标对象实现接口,可以代理普通的类。
  • 代理对象是目标对象的子类,并通过方法重写(方法增强)来实现切面功能。

优点:

  • 不需要目标对象实现接口,可以直接增强普通类。

缺点:

  • 比 JDK 动态代理稍微重一些。

示例:

public class UserService {public void createUser() {System.out.println("Creating user...");}
}
  • Spring 会为 UserService 生成一个代理子类,并在方法上织入切面逻辑。

3.3 Spring 如何选择代理方式

Spring 默认通过 JDK 动态代理生成代理对象。如果目标对象没有实现接口,则自动切换为 CGLIB 动态代理。

可以通过以下配置强制使用 CGLIB 动态代理:

@EnableAspectJAutoProxy(proxyTargetClass = true)

4. 代理对象和目标对象的实际差异

在 Spring AOP 的运行时动态代理中,外部用户调用的其实是代理对象而非目标对象。以下是一些细节差异:

4.1 方法调用流程

未增强(目标对象直接调用):
UserService userService = new UserService();
userService.createUser();

方法调用的流程:

  • 直接调用目标对象的 createUser() 方法。
  • 输出:Creating user...
增强(通过代理对象调用):
UserService proxy = (UserService) context.getBean(UserService.class);
proxy.createUser();

方法调用的流程:

  1. 调用代理对象的 createUser() 方法。
  2. 代理对象拦截方法调用。
  3. 代理对象决定是否执行切面增强逻辑(如前置通知、后置通知等)。
  4. 代理对象将调用转发到目标对象的 createUser() 方法。

4.2 是否可以直接访问目标对象

  • 直接通过 Spring 容器获取的 Bean 是代理对象
    Spring 容器会将代理对象注册为 Bean,用户通过 @AutowiredgetBean() 获取的 Bean 实际上是代理对象。

  • 通过 AOP 上下文访问目标对象
    如果需要直接访问目标对象(绕过代理),可以通过 Spring 提供的 AopContext

    UserService target = (UserService) AopContext.currentProxy();
    

4.3 代理对象与目标对象的相互关系

  • 代理对象包含目标对象
    代理对象会将对业务方法的调用最终转发给目标对象。

  • 目标对象不知道代理对象的存在
    目标对象的代码完全独立,不需要感知代理对象或 Spring 的存在。


5. 示例:代理对象和目标对象的工作过程

目标对象

public class UserService {public void createUser() {System.out.println("Creating user...");}
}

切面

@Aspect
@Component
public class LoggingAspect {@Before("execution(* com.example.UserService.*(..))")public void logBefore() {System.out.println("Logging before method execution...");}
}

运行时流程

  1. Spring 生成一个代理对象(通过 JDK 动态代理或 CGLIB)。
  2. 用户调用代理对象的 createUser() 方法。
  3. 代理对象拦截该调用,并触发切面逻辑(前置通知)。
  4. 代理对象将方法调用转发给目标对象。
  5. 目标对象执行原始业务逻辑。

6. 总结

代理对象目标对象
Spring 动态生成的增强版本。开发者定义的原始业务逻辑类。
包含切面逻辑(通知)。不包含切面逻辑,只有业务逻辑。
用户通过代理对象间接访问目标对象方法。仅通过代理对象间接调用。
可以插入增强逻辑(如日志记录、事务)。无法直接应用增强逻辑。
http://www.lryc.cn/news/532337.html

相关文章:

  • 【Kubernetes Pod间通信-第3篇】Kubernetes中Pod与ClusterIP服务之间的通信
  • DNN(深度神经网络)近似 Lyapunov 函数
  • 128陷阱
  • PromptSource和LangChain哪个更好
  • 构成正方形的数量:算法深度剖析与实践
  • Redis持久化-秒杀系统设计
  • 音视频入门基础:RTP专题(8)——使用Wireshark分析RTP
  • OpenAI 实战进阶教程 - 第六节: OpenAI 与爬虫集成实现任务自动化
  • SpringUI Web高端动态交互元件库
  • 解密企业安全密码:密钥管理服务如何重塑数据保护?
  • 基于keepalived+GTID半同步主从复制的高可用MySQL集群
  • 图片PDF区域信息批量提取至Excel,基于QT和阿里云api的实现方案
  • Java 大视界 -- Java 大数据在智能教育中的应用与个性化学习(75)
  • 从零手写Spring IoC容器(二):bean的定义与注册
  • 《大模型面试宝典》(2025版) 发布了
  • AWS门店人流量数据分析项目的设计与实现
  • 出租车特殊计费表算法解析与实现
  • 文档解析技术:如何高效提取PDF扫描件中的文字与表格信息?
  • 【2】高并发导出场景下,服务器性能瓶颈优化方案-异步导出
  • 【DeepSeek论文精读】6. DeepSeek R1:通过强化学习激发大语言模型的推理能力
  • frida 通过 loadLibrary0 跟踪 System.loadLibrary
  • 【2025最新计算机毕业设计】基于SSM的智能停车场管理系统【提供源码+答辩PPT+文档+项目部署】(高质量源码,可定制,提供文档,免费部署到本地)
  • 【含文档+PPT+源码】Python爬虫人口老龄化大数据分析平台的设计与实现
  • 文本生图的提示词prompt和参数如何设置(基于Animagine XL V3.1)
  • 快速提取Excel工作簿中所有工作表的名称?
  • 【紫光同创PG2L100H开发板】盘古676系列,盘古100Pro+开发板,MES2L676-100HP
  • Node.JS 版本管理工具 Fnm 安装及配置(Windows)
  • labview通过时间计数器来设定采集频率
  • 汇编JCC条件跳转指令记忆
  • HTML排版标签、语义化标签、块级和行内元素详解