欢迎光临
我们一直在努力

Java反射与动态代理:Spring AOP底层原理揭秘

一、前言

反射与动态代理是 Java 高级特性重中之重,也是 Spring 框架 AOP 实现底层原理。 反射允许程序在运行时获取类信息、操作对象;动态代理依托反射实现无侵入增强目标对象功能。本文结合全套代码案例,系统梳理核心知识点。

二、反射机制

2.1 什么是反射

正常编码:编译期直接new 对象(),正向操作。 反射:程序运行阶段,获取类的全部信息(构造器、成员变量、成员方法),并且创建对象、修改变量、执行方法。

核心:先拿到 Class 字节码对象,一切操作基于 Class。

2.2 获取 Class 对象三种方式

//方式1:类名.class 【编译阶段,无需对象】
Class<Student> clazz1 = Student.class;
//方式2:对象.getClass() 【必须存在实例对象】
Student s = new Student();
Class<? extends Student> clazz2 = s.getClass();
//方式3:Class.forName("全类名") 【最常用,配置文件加载】
Class<?> clazz3 = Class.forName("com.itheima.reflect.Student");

💡重点:同一个类在 JVM 中只会加载一份字节码,三种方式获取的Class是同一个对象。

2.3 反射核心 API 总览

类型Class 方法作用
构造方法 Constructor getConstructors()getDeclaredConstructors() 获取所有公共构造器 / 所有构造器(包含 private)
成员变量 Field getFields()getDeclaredFields() 获取所有公共成员变量 / 全部成员变量
成员方法 Method getMethods()getDeclaredMethods() 获取所有公共方法 (含继承)/ 本类全部方法

⚠️getXXX() 只能获取public;getDeclaredXXX() 获取本类所有权限(private/protected/public)。 setAccessible(true):暴力反射,关闭权限检查,允许访问私有成员。

2.4 反射实战操作

1)操作构造方法,创建对象

//获取私有构造器
Constructor<Student> cons = clazz.getDeclaredConstructor(String.class);
cons.setAccessible(true); //暴力访问
Student stu = cons.newInstance("张三");

2)操作成员变量(赋值、取值)

Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(stu,"李四"); //赋值
String name = (String) nameField.get(stu); //取值

3)操作成员方法(运行方法)

Method showMethod = clazz.getDeclaredMethod("show",String.class);
showMethod.setAccessible(true);
//invoke(对象,方法参数),执行方法
Object result = showMethod.invoke(stu,"测试参数");

2.5 反射典型应用场景

  • 框架底层:Spring Bean 实例化
  • 配合配置文件:读取 properties,通过全类名动态创建对象
  • 通用工具:序列化、ORM 框架(Mybatis)实体类映射
  • 2.6 反射优缺点

    ✅优点:代码灵活,运行时动态操作,适配各类通用框架 ❌缺点:破坏封装性;跳过编译检查;存在一定性能损耗


    三、动态代理

    3.1 代理思想

    代理模式:不直接操作目标对象,通过代理对象中转,可以在不修改原有目标代码的前提下,增加额外逻辑(日志、事务、权限校验),也就是无侵入增强。

    • 静态代理:提前写好代理类,一个目标类对应一个代理类,类爆炸
    • JDK 动态代理:运行时自动生成代理类(依托反射实现)

    3.2 JDK 动态代理前置条件

    ⚠️硬性要求:目标对象必须实现接口 代理对象和目标对象实现同一个接口,保证对外方法一致。

    3.3 核心 API

    java.lang.reflect.Proxy

    public static Object newProxyInstance(ClassLoader loader,
    Class<?>[] interfaces,
    InvocationHandler h)

    参数说明:

  • ClassLoader:目标类的类加载器
  • interfaces:目标类实现的接口数组
  • InvocationHandler:回调处理器,代理执行方法时触发
  • InvocationHandler唯一方法:

    Object invoke(Object proxy, Method method, Object[] args)

    • proxy:生成的代理对象
    • method:当前执行的目标方法
    • args:方法入参
    • 通过method.invoke(target,args)调用真实目标方法

    3.4 完整代码模板

    //1.定义接口
    public interface Star {
    String sing(String name);
    void dance();
    }

    //2.目标实现类
    public class BigStar implements Star{
    @Override
    public String sing(String name) {
    System.out.println("唱歌:"+name);
    return "歌曲结束";
    }
    @Override
    public void dance() {
    System.out.println("跳舞");
    }
    }

    //3.代理工具类,生成代理对象
    public class ProxyUtil{
    public static Star createProxy(Star target){
    Star proxy = (Star) Proxy.newProxyInstance(
    BigStar.class.getClassLoader(),
    BigStar.class.getInterfaces(),
    (proxyObj, method, args) -> {
    //增强前置逻辑
    System.out.println("准备场地、收取费用");
    //执行目标方法
    Object res = method.invoke(target,args);
    //增强后置逻辑
    System.out.println("演出结束,清理场地");
    return res;
    }
    );
    return proxy;
    }
    }

    //4.测试调用
    public class Test{
    public static void main(String[] args) {
    Star target = new BigStar();
    Star proxy = ProxyUtil.createProxy(target);
    proxy.sing("七里香");
    proxy.dance();
    }
    }

    3.5 动态代理核心价值

    这是 Spring AOP 底层实现基础: 在不改动业务代码的情况下,统一增加:日志记录、事务控制、异常捕获、权限校验。

    3.6 JDK 动态代理局限

    只能代理实现了接口的类;没有接口的类无法使用。

    补充:CGLIB 动态代理可以直接代理类,底层通过继承目标类实现。


    四、整体总结

  • 反射核心:运行时操作 Class 字节码,操纵构造器、字段、方法;暴力反射setAccessible(true)突破权限限制。
  • 反射经典场景:框架动态创建对象、解析实体类。
  • JDK 动态代理基于反射实现,运行时动态生成代理类,实现功能增强。
  • JDK 动态代理约束:目标类必须实现接口;
  • 两大特性是学习 Spring AOP、MyBatis 等主流框架必须掌握的底层基础。
  • 赞(0)
    未经允许不得转载:171主机测评 » Java反射与动态代理:Spring AOP底层原理揭秘
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址