☰
反射,动态代理,AOP联系和理解
2026/10/3 17:10:04 网站建设 项目流程

反射->动态代理->AOP理解:
反射:运行时的“自我审视”能力
反射是指程序在运行期间,可以获取任意一个类的内部信息(如属性、方法、构造器),并能够直接操作这些内部成员。

  • 核心作用:把“类”也当成对象来对待。正常情况下,我们通过 new 创建对象;有了反射,我们可以通过一个字符串类名,利用反射 API,在运行时动态地创建对象、调用方法。
  • 关键类:Class、Method、Field、Constructor。
  • 生活类比:你拿到一个遥控器(类的class对象),即使不看说明书,也能通过按键(反射 API)试出每个按钮的功能,甚至能拆开遥控器看到里面的电路板(私有属性)。
    一个简单的反射示例:
    java
    Class<?> clazz = Class.forName(“com.example.User”);
    Object user = clazz.newInstance(); // 创建对象
    Method method = clazz.getMethod(“sayHello”);
    method.invoke(user); // 调用方法

动态代理:运行时的“替身”机制
动态代理是指在程序运行时,动态地生成一个代理类,这个代理类可以在不修改原目标类代码的情况下,对目标类的方法进行增强(如添加日志、事务、权限校验、限流逻辑)。

  • 核心角色:
    • 目标对象:真正执行业务逻辑的对象。
    • 代理对象:由程序动态生成的“替身”,持有目标对象的引用。
    • 调用处理器:代理对象的所有方法调用,都会被转发到这个处理器中,由它决定何时调用目标方法、何时添加额外逻辑。
  • 两种主流实现:
    1. JDK 动态代理:基于接口。要求目标类必须实现至少一个接口。代理类和目标类实现同一个接口。
    2. CGLIB 动态代理:基于继承。通过生成目标类的子类来创建代理,因此无法代理 final 类或 final 方法。
      动态代理和反射的关系:
      动态代理是反射最经典的应用场景之一。代理类在运行时,正是通过反射来获取目标类的方法,并调用 method.invoke(target, args) 来执行目标方法的。

AOP:面向切面编程的思想
AOP 是一种编程思想,它把那些与核心业务逻辑无关,但被多处业务模块使用的代码(如日志、事务、安全)抽取出来,形成一个的“切面”,然后通过注解将这些切面的增强逻辑动态地应用到业务方法上。

  • 核心目的:解耦。让业务代码只关心业务,让通用逻辑(切面)可以独立维护。
  • 核心概念:
    • 切面:通用逻辑的模块化,比如一个日志切面。
    • 连接点:程序执行过程中的一个点,比如一个方法的调用。
    • 切入点:一个表达式,用来匹配哪些连接点需要被增强。
    • 通知:在切入点前后要执行的具体动作,如 @Before、@After、@Around。
  • 实现方式:在 Java 中,AOP 的底层实现主要就是动态代理。Spring AOP 就是通过 JDK 或 CGLIB 动态代理,在运行时为目标 Bean 生成代理对象,从而将切面逻辑“织入”到方法调用中。
  1. 反射是基石:没有反射,就无法在运行时动态获取类信息,动态代理也就无从谈起。
  2. 动态代理是反射的应用:动态代理利用反射,在运行时生成代理类并调用目标方法,实现了对方法的无侵入式增强。
  3. AOP 是思想,动态代理是手段:AOP 是一种解耦的编程思想,而动态代理是实现这种思想最主流的技术手段。Spring AOP 正是通过动态代理,将切面逻辑应用到目标方法上。
    反射是底层能力,动态代理依赖反射创建代理对象,AOP是一种编程思想,核心是为了将业务和通用逻辑进行解耦,依赖动态代理

代理对象是"转发员",本身不干活,所有方法调用都转发到调用处理器的 invoke() 方法
┌─────────────────────────────────────────────────────────────┐
│ 调用方 │
│ proxy.sayHello() │
└───────────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 代理对象 (Proxy) │
│ │
│ 所有方法调用都被转发,不执行真正的业务逻辑 │
│ │
│ sayHello() → invoke(proxy, sayHello, null) │
│ eat() → invoke(proxy, eat, null) │
│ pay(100) → invoke(proxy, pay, [100]) │
└───────────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 调用处理器 (InvocationHandler) │
│ │
│ invoke(proxy, method, args) { │
│ ┌─────────────────────────────────────┐ │
│ │ 1. 决定是否调用目标方法 │ │
│ │ 2. 决定前置逻辑(日志、事务、权限) │ │
│ │ 3. method.invoke(target, args) │ ← 反射调用 │
│ │ 4. 决定后置逻辑(提交、回滚、耗时) │ │
│ │ 5. 决定返回值 │ │
│ └─────────────────────────────────────┘ │
│ } │
└───────────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 目标对象 (Target) │
│ │
│ 真正执行 sayHello() 的业务逻辑 │
│ 不知道代理和处理器的存在 │
└─────────────────────────────────────────────────────────────┘

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询