一、代理思想
代理:找一个代理对象,代替目标对象干活,在目标方法执行前后,增加额外功能(增强),不修改目标类源码。
举例:租房,你是目标对象,中介是代理;中介帮你处理合同、看房(增强逻辑),最后还是调用你租房的核心方法。
- 目标对象(被代理对象):包含核心业务方法
- 代理对象:对目标方法做增强,最终调用目标对象原方法
核心好处:不改动原有代码,对方法进行增强(AOP 思想底层原理)
二、静态代理(了解,对比用)
静态代理:代理类代码提前手动写好,编译期就存在代理类。 缺点:
- 一个目标类就要写一个代理类,类爆炸
- 接口方法增加,代理类代码也要同步修改
动态代理:不用手动写代理类!运行时 JVM 自动动态生成代理类的字节码
三、JDK 动态代理(重点,Java 原生)
✅ 前提:目标对象必须实现接口
JDK 动态代理只能给【实现了接口】的类生成代理对象。
核心 API(java.lang.reflect 包)
-
Proxy:代理工具类,用来创建代理对象javapublic static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)参数说明:
ClassLoader loader:类加载器,目标对象的类加载器Class<?>[] interfaces:目标对象实现的接口数组InvocationHandler h:调用处理器,代理对象执行方法时,会触发这个处理器的 invoke 方法
-
InvocationHandler接口 唯一抽象方法:invoke(Object proxy, Method method, Object[] args)代理对象调用任何方法,都会进入 invoke 方法
- proxy:生成的代理对象(一般不用)
- method:当前正在执行的目标方法
- args:目标方法的参数 返回值:目标方法执行后的返回结果
执行流程
- 运行时,JVM 自动生成代理类字节码
- 使用
Proxy.newProxyInstance()创建代理对象 - 代理对象调用方法 → 进入
invoke() - 在 invoke 里:执行增强代码 → 调用目标对象原方法 → 后续增强代码
四、完整代码示例
1. 定义接口
java
// 业务接口
public interface UserService {
void addUser();
void deleteUser();
}
2. 目标类(实现接口)
java
//目标对象:核心业务
public class UserServiceImpl implements UserService{
@Override
public void addUser() {
System.out.println("【核心】新增用户");
}
@Override
public void deleteUser() {
System.out.println("【核心】删除用户");
}
}
3. 创建代理对象 + 测试
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
//1. 创建目标对象
UserService target = new UserServiceImpl();
//2. 生成代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// ========== 前置增强 ==========
System.out.println("【增强】日志记录,方法执行前");
// 执行目标对象原始方法
Object result = method.invoke(target, args);
// ========== 后置增强 ==========
System.out.println("【增强】日志记录,方法执行后");
return result;
}
}
);
//3. 通过代理对象调用方法
proxy.addUser();
System.out.println("-----------------------");
proxy.deleteUser();
}
}
运行结果:
【增强】日志记录,方法执行前
【核心】新增用户
【增强】日志记录,方法执行后
-----------------------
【增强】日志记录,方法执行前
【核心】删除用户
【增强】日志记录,方法执行后
五、JDK 动态代理特点
✅ 优点:运行时自动生成代理类,不需要手动写代理代码;灵活 ❌ 限制:目标类必须实现接口,没有接口不能用 JDK 动态代理
拓展:CGLIB 动态代理(第三方):不需要接口,继承目标类生成子类做代理;Spring AOP 底层:优先 JDK 代理,没有接口就用 CGLIB。
六、作用 & 实际开发场景
作用:在不修改目标类源码的前提下,对目标方法做增强。 应用场景:
- Spring AOP(面向切面编程):日志、事务、权限校验
- MyBatis Mapper 接口:Mapper 没有实现类,底层 JDK 动态代理生成代理对象
七、面试简答背诵版
动态代理:在程序运行期间,JVM 自动生成代理类字节码,创建代理对象。 JDK 动态代理要求目标对象必须实现接口 ,通过Proxy.newProxyInstance()创建代理;代理对象调用方法会触发InvocationHandler的 invoke 方法,在 invoke 内部完成方法增强和目标方法调用。 核心思想:不修改源码,对方法增强。
JavaSE 高级全套到此结束:单元测试 → 反射 → 注解 → 动态代理。