深入解析 Java 代理:从静态代理到 CGLIB,掌握 AOP 底层核心
代理模式是 Java 设计模式中结构型模式的核心代表,更是 Spring AOP、事务管理、RPC 框架、日志拦截等核心技术的底层实现基石。理解 Java 代理的实现原理,不仅能掌握设计模式的实战应用,更能打通 Spring 等主流框架的底层逻辑。本文将从代理模式的核心思想出发,逐层拆解静态代理、JDK 动态代理、CGLIB 代理的实现细节、底层原理、优缺点及实战场景,最终带你掌握 AOP 技术的核心本质。
一、代理模式的核心本质
1.1 代理模式的定义
代理模式(Proxy Pattern):为目标对象提供一个代理对象,由代理对象控制对目标对象的访问。代理对象作为 “中间层”,既可以保护目标对象,也可以在不修改目标对象源码的前提下,对目标对象的功能进行扩展(如添加日志、权限校验、性能监控等)。
1.2 生活中的代理类比
- 租房中介:你(客户端)不直接对接房东(目标对象),而是通过中介(代理对象)完成租房流程,中介会帮你筛选房源、审核资质(附加功能),最终完成租房(核心功能);
- 明星经纪人:经纪人(代理)负责对接演出、洽谈费用(附加功能),明星(目标)只需要专注表演(核心功能);
- 律师代理:律师(代理)处理法律流程(附加功能),当事人(目标)只需陈述事实(核心功能)。
1.3 代理模式的核心角色
代理模式的核心包含 4 个角色,所有代理实现都围绕这 4 个角色展开:
| 角色名称 | 核心职责 |
|---|---|
| 抽象主题(Subject) | 定义目标对象和代理对象的共同接口 / 抽象类,确保代理对象可替代目标对象(里氏替换原则); |
| 真实主题(RealSubject) | 真正执行业务逻辑的目标对象,是代理的最终调用目标; |
| 代理对象(Proxy) | 实现 / 继承抽象主题,持有真实主题的引用,在调用目标方法前后添加附加逻辑; |
| 客户端(Client) | 仅与代理对象交互,不直接操作真实主题; |
1.4 代理模式的核心价值
- 解耦:将核心业务逻辑(如用户新增)与非核心逻辑(如日志、事务)分离,符合 “单一职责原则”;
- 扩展:无需修改目标对象源码,通过代理即可新增功能(开放封闭原则);
- 控制:可控制对目标对象的访问(如权限校验、限流、熔断);
- 隐藏:可隐藏目标对象的实现细节(如 RPC 代理隐藏远程调用细节)。
二、静态代理:手动编写的 “专属代理”
静态代理是最基础的代理实现方式,代理类由开发者手动编写,在编译期就确定了代理类与目标类的绑定关系,属于 “一对一” 的专属代理。
2.1 实现步骤
- 定义抽象主题接口,声明核心业务方法;
- 实现真实主题类,完成核心业务逻辑;
- 编写代理类,实现抽象主题接口,持有真实主题引用;
- 在代理类的方法中,调用目标方法并添加附加逻辑;
- 客户端通过代理类调用业务方法。
2.2 实战案例:用户服务日志代理
以 “用户新增功能” 为例,通过静态代理添加日志记录功能。
步骤 1:定义抽象主题接口
/**
* 抽象主题:用户服务接口(定义核心业务方法)
*/
public interface UserService {
/**
* 新增用户
* @param username 用户名
* @param age 年龄
* @return 是否新增成功
*/
boolean addUser(String username, int age);
}
步骤 2:实现真实主题类
/**
* 真实主题:用户服务实现类(核心业务逻辑)
*/
public class UserServiceImpl implements UserService {
@Override
public boolean addUser(String username, int age) {
// 核心业务逻辑:模拟数据库新增用户
if (username == null || username.isEmpty()) {
throw new IllegalArgumentException("用户名不能为空");
}
System.out.println("【核心逻辑】新增用户:" + username + ",年龄:" + age);
return true;
}
}
步骤 3:编写静态代理类
/**
* 静态代理类:为UserService添加日志功能
*/
public class UserServiceStaticProxy implements UserService {
// 持有真实主题引用
private final UserService target;
// 通过构造器注入目标对象
public UserServiceStaticProxy(UserService target) {
this.target = target;
}
@Override
public boolean addUser(String username, int age) {
// 1. 前置附加逻辑:日志记录(方法调用前)
System.out.println("【静态代理-前置】开始调用addUser方法,参数:username=" + username + ", age=" + age);
long startTime = System.currentTimeMillis();
boolean result = false;
try {
// 2. 调用目标对象的核心方法
result = target.addUser(username, age);
// 3. 后置附加逻辑:日志记录(方法调用成功)
System.out.println("【静态代理-后置】addUser方法调用成功,返回结果:" + result);
return result;
} catch (Exception e) {
// 4. 异常附加逻辑:日志记录(方法调用异常)
System.out.println("【静态代理-异常】addUser方法调用失败,异常信息:" + e.getMessage());
throw e; // 抛出异常,不影响上层处理
} finally {
// 5. 收尾逻辑:性能监控
long endTime = System.currentTimeMillis();
System.out.println("【静态代理-耗时】addUser方法执行耗时:" + (endTime - startTime) + "ms");
}
}
}
步骤 4:客户端测试
/**
* 客户端:通过静态代理调用目标方法
*/
public class StaticProxyClient {
public static void main(String[] args) {
// 1. 创建真实目标对象
UserService target = new UserServiceImpl();
// 2. 创建代理对象,注入目标对象
UserService proxy = new UserServiceStaticProxy(target);
// 3. 调用代理方法(正常场景)
System.out.println("===== 正常场景 =====");
proxy.addUser("张三", 25);
// 4. 调用代理方法(异常场景)
System.out.println("\n===== 异常场景 =====");
try {
proxy.addUser("", 20);
} catch (IllegalArgumentException e) {
System.out.println("客户端捕获异常:" + e.getMessage());
}
}
}
运行结果
===== 正常场景 =====
【静态代理-前置】开始调用addUser方法,参数:username=张三, age=25
【核心逻辑】新增用户:张三,年龄:25
【静态代理-后置】addUser方法调用成功,返回结果:true
【静态代理-耗时】addUser方法执行耗时:1ms
===== 异常场景 =====
【静态代理-前置】开始调用addUser方法,参数:username=, age=20
【静态代理-异常】addUser方法调用失败,异常信息:用户名不能为空
【静态代理-耗时】addUser方法执行耗时:0ms
客户端捕获异常:用户名不能为空
2.3 静态代理的优缺点
优点
- 实现简单:纯原生 Java 实现,无需依赖任何框架,新手易理解;
- 性能最优:编译期确定代理逻辑,无反射、无字节码生成开销;
- 逻辑清晰:代理类与目标类一一对应,调试时可直接定位代码。
缺点
- 代码冗余:每一个目标类都需要编写对应的代理类,若系统中有 100 个服务类,就需要 100 个代理类;
- 维护成本高:若抽象主题接口新增 / 修改方法,所有代理类都需同步修改;
- 扩展性差:代理逻辑无法复用,不同目标类的附加逻辑(如日志)需重复编写。
2.4 静态代理的适用场景
仅适用于目标类数量极少、业务逻辑固定、无需频繁扩展的简单场景,如小型工具类、固定流程的业务模块,实际企业开发中使用频率极低。
三、JDK 动态代理:基于接口的 “通用代理”
为解决静态代理的代码冗余问题,Java 提供了原生的动态代理机制 ——JDK 动态代理。代理类无需手动编写,而是在运行时通过反射动态生成,可代理所有实现了接口的目标类,实现 “一套代理逻辑适配所有目标类”。
3.1 核心原理
JDK 动态代理的核心依赖 java.lang.reflect 包下的两个类 / 接口:
Proxy:核心工具类,通过newProxyInstance()方法动态生成代理类的字节码,并创建代理对象;InvocationHandler:调用处理器接口,所有代理方法的逻辑都会委托给该接口的invoke()方法处理。
其底层逻辑可概括为:
- 代理类由
Proxy类动态生成,继承自java.lang.reflect.Proxy,并实现目标类的所有接口; - 代理类的所有接口方法都会调用
InvocationHandler的invoke()方法; - 在
invoke()方法中,开发者可统一处理前置、后置、异常逻辑,并通过反射调用目标方法; - 由于 Java 单继承限制(代理类已继承
Proxy),JDK 动态代理只能代理实现了接口的类。
3.2 核心 API 详解
| 类 / 接口 | 核心方法 | 参数说明 |
|---|---|---|
Proxy |
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) |
- loader:目标对象的类加载器;- interfaces:目标对象实现的所有接口;- h:调用处理器(核心逻辑) |
InvocationHandler |
invoke(Object proxy, Method method, Object[] args) |
- proxy:生成的代理对象(一般不使用);- method:当前调用的目标方法;- args:目标方法的参数数组;返回值:目标方法的执行结果 |
3.3 实战案例:通用日志动态代理
实现一个通用的 JDK 动态代理工具,可给任意实现了接口的目标类添加日志和性能监控功能。
步骤 1:编写通用调用处理器
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 通用JDK动态代理调用处理器
* 统一处理所有代理方法的日志、性能监控逻辑
*/
public class JdkLogInvocationHandler implements InvocationHandler {
// 持有目标对象引用(通用类型,适配所有目标类)
private final Object target;
public JdkLogInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1. 前置逻辑:日志记录(含时间戳)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String methodName = method.getName();
System.out.println("【JDK动态代理-" + sdf.format(new Date()) + "】开始调用方法:" + methodName);
System.out.println("【JDK动态代理】方法参数:" + argsToString(args));
long startTime = System.currentTimeMillis();
Object result = null;
try {
// 2. 调用目标对象的核心方法(反射)
result = method.invoke(target, args);
// 3. 后置逻辑:调用成功日志
System.out.println("【JDK动态代理-" + sdf.format(new Date()) + "】方法" + methodName + "调用成功,返回结果:" + result);
return result;
} catch (Exception e) {
// 4. 异常逻辑:调用失败日志(解包原始异常)
Throwable realException = e.getTargetException() == null ? e : e.getTargetException();
System.out.println("【JDK动态代理-" + sdf.format(new Date()) + "】方法" + methodName + "调用失败,异常:" + realException.getMessage());
throw realException; // 抛出原始异常,避免包装
} finally {
// 5. 收尾逻辑:性能监控
long endTime = System.currentTimeMillis();
System.out.println("【JDK动态代理】方法" + methodName + "执行耗时:" + (endTime - startTime) + "ms\n");
}
}
/**
* 参数数组转字符串,方便日志打印
*/
private String argsToString(Object[] args) {
if (args == null || args.length == 0) {
return "无参数";
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < args.length; i++) {
sb.append("arg").append(i + 1).append("=").append(args[i]);
if (i < args.length - 1) {
sb.append(", ");
}
}
return sb.toString();
}
}
步骤 2:编写 JDK 动态代理工具类
import java.lang.reflect.Proxy;
/**
* JDK动态代理工具类
* 提供通用的代理对象生成方法
*/
public class JdkProxyFactory {
/**
* 生成目标对象的代理对象
* @param target 目标对象(必须实现至少一个接口)
* @param <T> 目标对象类型
* @return 代理对象
*/
@SuppressWarnings("unchecked")
public static <T> T createProxy(T target) {
// 1. 获取目标对象的类加载器
ClassLoader classLoader = target.getClass().getClassLoader();
// 2. 获取目标对象实现的所有接口
Class<?>[] interfaces = target.getClass().getInterfaces();
// 3. 创建调用处理器
JdkLogInvocationHandler handler = new JdkLogInvocationHandler(target);
// 4. 动态生成代理对象并返回
return (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
}
}
步骤 3:客户端测试(复用 UserService 体系)
/**
* 客户端:测试JDK动态代理
*/
public class JdkProxyClient {
public static void main(String[] args) {
// 1. 创建目标对象(实现了接口)
UserService target = new UserServiceImpl();
// 2. 生成动态代理对象
UserService proxy = JdkProxyFactory.createProxy(target);
// 3. 调用代理方法(正常场景)
System.out.println("===== 正常场景 =====");
proxy.addUser("李四", 30);
// 4. 新增测试:代理另一类方法(验证通用性)
System.out.println("===== 多类适配 =====");
OrderService orderTarget = new OrderServiceImpl();
OrderService orderProxy = JdkProxyFactory.createProxy(orderTarget);
orderProxy.createOrder("ORDER_001", 100.0);
}
// 新增订单服务接口(验证通用性)
interface OrderService {
boolean createOrder(String orderNo, double amount);
}
// 订单服务实现类
static class OrderServiceImpl implements OrderService {
@Override
public boolean createOrder(String orderNo, double amount) {
System.out.println("【核心逻辑】创建订单:" + orderNo + ",金额:" + amount);
return true;
}
}
}
运行结果
===== 正常场景 =====
【JDK动态代理-2026-03-11 16:00:00】开始调用方法:addUser
【JDK动态代理】方法参数:arg1=李四, arg2=30
【核心逻辑】新增用户:李四,年龄:30
【JDK动态代理-2026-03-11 16:00:00】方法addUser调用成功,返回结果:true
【JDK动态代理】方法addUser执行耗时:1ms
===== 多类适配 =====
【JDK动态代理-2026-03-11 16:00:00】开始调用方法:createOrder
【JDK动态代理】方法参数:arg1=ORDER_001, arg2=100.0
【核心逻辑】创建订单:ORDER_001,金额:100.0
【JDK动态代理-2026-03-11 16:00:00】方法createOrder调用成功,返回结果:true
【JDK动态代理】方法createOrder执行耗时:0ms
3.4 JDK 动态代理的优缺点
优点
- 通用性强:一套代理逻辑可适配所有实现接口的目标类,无代码冗余;
- 扩展性好:新增目标类无需修改代理逻辑,只需传入目标对象即可;
- 原生支持:基于 JDK 原生 API 实现,无需依赖第三方框架。
缺点
- 接口限制:只能代理实现了接口的类,无法代理普通类(无接口);
- 继承限制:代理类继承自
Proxy,无法代理final类; - 反射开销:目标方法调用基于反射实现,性能略低于静态代理(现代 JVM 优化后,该开销可忽略)。
3.5 JDK 动态代理的适用场景
是企业开发中最常用的代理方式,适用于目标类实现了接口的所有场景,如 Spring AOP 对接口型 Bean 的代理、MyBatis Mapper 接口代理、RPC 接口代理等。
四、CGLIB 动态代理:基于继承的 “无接口代理”
JDK 动态代理的核心限制是 “必须实现接口”,而在实际开发中,很多业务类并未实现接口(如普通 POJO、工具类)。CGLIB(Code Generation Library)作为第三方字节码生成库,通过继承目标类生成子类的方式实现代理,突破了接口限制。
4.1 核心原理
CGLIB 基于 ASM 字节码操作框架,其核心原理为:
- 在运行时动态生成目标类的子类作为代理类;
- 代理类重写目标类的所有
非final、非private方法; - 通过
MethodInterceptor(方法拦截器)拦截所有重写方法的调用; - 在拦截器中处理附加逻辑,并调用目标类的原始方法。
核心特点:
- 无需目标类实现接口,直接代理普通类;
- 代理类继承目标类,因此无法代理
final类(无法继承),也无法代理final方法(无法重写); - 方法调用通过字节码直接调用,性能优于 JDK 动态代理(Spring 5 后已优化,两者性能差异极小)。
4.2 核心依赖与 API
依赖引入(Maven)
CGLIB 非 JDK 原生库,需手动引入依赖(Spring Core 已内置 CGLIB,Spring 项目无需额外引入):
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
核心 API 详解
| 类 / 接口 | 核心方法 | 作用 |
|---|---|---|
Enhancer |
setSuperclass(Class<?> superclass)setCallback(Callback callback)create() |
核心增强类,用于生成代理类:- 设置目标类为父类;- 设置回调拦截器;- 生成代理对象 |
MethodInterceptor |
intercept(Object obj, Method method, Object[] args, MethodProxy proxy) |
方法拦截器,处理所有代理方法逻辑:- obj:代理对象;- method:目标方法;- args:方法参数;- proxy:方法代理(高效调用父类方法) |
MethodProxy |
invokeSuper(Object obj, Object[] args) |
调用父类(目标类)的原始方法,性能优于反射 method.invoke() |
4.3 实战案例:CGLIB 通用代理工具
实现一个通用的 CGLIB 代理工具,代理无接口的普通类。
步骤 1:编写 CGLIB 方法拦截器
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* CGLIB方法拦截器
* 统一处理代理方法的日志、性能监控逻辑
*/
public class CglibLogInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 1. 前置逻辑:日志记录
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String methodName = method.getName();
System.out.println("【CGLIB动态代理-" + sdf.format(new Date()) + "】开始调用方法:" + methodName);
System.out.println("【CGLIB动态代理】方法参数:" + argsToString(args));
long startTime = System.currentTimeMillis();
Object result = null;
try {
// 2. 调用目标类的原始方法(高效调用)
result = proxy.invokeSuper(obj, args);
// 3. 后置逻辑:调用成功日志
System.out.println("【CGLIB动态代理-" + sdf.format(new Date()) + "】方法" + methodName + "调用成功,返回结果:" + result);
return result;
} catch (Exception e) {
// 4. 异常逻辑:调用失败日志
System.out.println("【CGLIB动态代理-" + sdf.format(new Date()) + "】方法" + methodName + "调用失败,异常:" + e.getMessage());
throw e;
} finally {
// 5. 收尾逻辑:性能监控
long endTime = System.currentTimeMillis();
System.out.println("【CGLIB动态代理】方法" + methodName + "执行耗时:" + (endTime - startTime) + "ms\n");
}
}
/**
* 参数数组转字符串
*/
private String argsToString(Object[] args) {
if (args == null || args.length == 0) {
return "无参数";
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < args.length; i++) {
sb.append("arg").append(i + 1).append("=").append(args[i]);
if (i < args.length - 1) {
sb.append(", ");
}
}
return sb.toString();
}
}
步骤 2:编写 CGLIB 代理工厂
import net.sf.cglib.proxy.Enhancer;
/**
* CGLIB动态代理工厂
* 生成无接口类的代理对象
*/
public class CglibProxyFactory {
/**
* 生成代理对象
* @param targetClass 目标类的Class对象
* @param <T> 目标类类型
* @return 代理对象
*/
@SuppressWarnings("unchecked")
public static <T> T createProxy(Class<T> targetClass) {
// 1. 创建增强器
Enhancer enhancer = new Enhancer();
// 2. 设置父类(目标类)
enhancer.setSuperclass(targetClass);
// 3. 设置方法拦截器
enhancer.setCallback(new CglibLogInterceptor());
// 4. 生成并返回代理对象
return (T) enhancer.create();
}
}
步骤 3:客户端测试(代理无接口类)
/**
* 客户端:测试CGLIB动态代理
*/
public class CglibProxyClient {
public static void main(String[] args) {
// 1. 代理无接口的普通类
System.out.println("===== 代理无接口类 =====");
PayService payProxy = CglibProxyFactory.createProxy(PayService.class);
payProxy.pay("USER_001", 200.5);
// 2. 测试final方法(无法代理)
System.out.println("===== 测试final方法 =====");
payProxy.finalMethod();
}
/**
* 无接口的普通类(支付服务)
*/
static class PayService {
// 普通方法(可被代理)
public boolean pay(String userId, double amount) {
System.out.println("【核心逻辑】用户" + userId + "支付金额:" + amount);
return true;
}
// final方法(无法被代理)
public final void finalMethod() {
System.out.println("【核心逻辑】这是final方法,无法被CGLIB代理增强");
}
}
}
运行结果
plaintext
===== 代理无接口类 =====
【CGLIB动态代理-2026-03-11 16:30:00】开始调用方法:pay
【CGLIB动态代理】方法参数:arg1=USER_001, arg2=200.5
【核心逻辑】用户USER_001支付金额:200.5
【CGLIB动态代理-2026-03-11 16:30:00】方法pay调用成功,返回结果:true
【CGLIB动态代理】方法pay执行耗时:1ms
===== 测试final方法 =====
【核心逻辑】这是final方法,无法被CGLIB代理增强
4.4 CGLIB 动态代理的优缺点
优点
- 无接口限制:可代理任意非
final普通类,弥补 JDK 动态代理的不足; - 性能更优:通过字节码直接调用方法,性能略优于 JDK 动态代理;
- 功能丰富:支持方法拦截、构造器拦截、回调过滤等高级功能。
缺点
- 依赖第三方库:需引入 CGLIB/ASM 依赖(Spring 项目可忽略);
- 继承限制:无法代理
final类和final方法; - 初始化开销:动态生成字节码的初始化开销略高于 JDK 动态代理(运行时可忽略)。
4.5 CGLIB 动态代理的适用场景
适用于目标类未实现接口的场景,如 Spring AOP 对非接口型 Bean 的代理、MyBatis 延迟加载、Hibernate 实体代理等。
五、三种代理模式的核心对比(面试必背)
| 特性 | 静态代理 | JDK 动态代理 | CGLIB 动态代理 |
|---|---|---|---|
| 实现方式 | 手动编写代理类 | 反射 + 接口 | 字节码生成 + 继承 |
| 是否需要接口 | 是 | 是 | 否 |
| 代理类生成时机 | 编译期 | 运行时 | 运行时 |
| 核心限制 | 无(但代码冗余) | 只能代理接口类 | 不能代理 final 类 / 方法 |
| 性能 | 最优(无额外开销) | 中等(反射开销) | 高(字节码直接调用) |
| 代码冗余度 | 极高(一对一) | 极低(通用代理) | 极低(通用代理) |
| 维护成本 | 高(接口修改需同步改) | 低(通用逻辑) | 低(通用逻辑) |
| Spring 默认使用 | 不使用 | 有接口时优先使用 | 无接口时使用 |
六、代理模式与 AOP 的关系
6.1 AOP 的核心本质
AOP(面向切面编程)的核心是 “横切逻辑”:将日志、事务、权限等与核心业务无关的逻辑(横切逻辑)从业务代码中抽离,通过 “切面” 统一管理。而动态代理是 AOP 实现的底层技术。
6.2 Spring AOP 的代理策略
Spring AOP 自动选择代理方式:
- 若目标 Bean 实现了接口,默认使用 JDK 动态代理;
- 若目标 Bean 未实现接口,使用 CGLIB 代理;
- 可通过
proxy-target-class=true强制使用 CGLIB 代理。
6.3 示例:Spring AOP 底层代理逻辑
// Spring AOP 核心拦截器(简化版)
public class AopAdviceInterceptor implements MethodInterceptor {
private final Advice advice; // 切面逻辑(如@Before、@After)
private final TargetSource targetSource; // 目标对象
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 1. 执行前置通知(@Before)
advice.before(method, args);
try {
// 2. 调用目标方法
Object result = targetSource.getTarget().getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(targetSource.getTarget(), args);
// 3. 执行后置通知(@AfterReturning)
advice.afterReturning(result);
return result;
} catch (Exception e) {
// 4. 执行异常通知(@AfterThrowing)
advice.afterThrowing(e);
throw e;
} finally {
// 5. 执行最终通知(@After)
advice.after();
}
}
}
七、总结
- 代理模式的核心:通过代理对象封装目标对象,实现核心逻辑与附加逻辑的解耦,核心是 “增强不修改”;
- 静态代理:简单但冗余,仅适用于简单固定场景;
- JDK 动态代理:基于接口,原生支持,是接口型 Bean 的首选;
- CGLIB 动态代理:基于继承,突破接口限制,适配无接口类;
- 动态代理是 AOP 的底层:Spring AOP、事务、日志等功能均依赖动态代理实现。
掌握 Java 代理的实现原理,不仅能理解设计模式的实战价值,更能打通 Spring 框架的底层逻辑,是 Java 后端开发者的核心基本功。

所有评论(0)