Java 切面与反射问题总结

1. 切面类为什么要用反射给对象赋值

问题背景:
你在 AutoFillAspect 切面中,需要在数据库插入/更新前给实体对象的公共字段(如 createTimeupdateTimecreateUserupdateUser)赋值。

原因分析:

  1. 切面操作的是未知类型对象

    Object entity = joinPoint.getArgs()[0];
    
    • entity 的具体类型在编译期未知(可能是 UserCategory 等)。
    • 编译器无法直接调用 entity.setCreateTime(...)
  2. 反射允许在运行时动态调用方法

    Method setCreateTime = entity.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class);
    setCreateTime.invoke(entity, LocalDateTime.now());
    
    • 无需知道对象具体类型,只要有对应方法就能调用。
    • 实现了切面通用逻辑,无需修改每个实体类。
  3. 可选方案

    • 如果所有实体类实现统一接口或继承父类,可以直接调用方法,避免反射:

      AutoFillEntity entity = (AutoFillEntity) args[0];
      entity.setCreateTime(now);
      
    • 反射的优点是无需改动现有实体类,缺点是性能略低


2. 什么时候用反射

适用场景:

  1. 运行时类型未知,需要动态调用方法或访问字段

    • 如切面中对任意实体对象赋值公共字段。
  2. 动态创建对象实例

    Class<?> clazz = Class.forName("com.example.User");
    Object obj = clazz.getDeclaredConstructor().newInstance();
    
  3. 框架或工具开发

    • Spring IoC / DI 自动注入 Bean
    • MyBatis / JPA 动态 SQL 映射
    • JSON 序列化/反序列化工具
    • 测试工具调用私有方法或字段

不适用场景:

  • 对象类型已知,直接调用方法即可
  • 性能敏感的代码路径
  • 安全要求严格的场景

总结:

反射用于处理编译期未知类型或方法,实现通用逻辑,但不适合普通业务逻辑。


3. 切面中用反射的核心原因

  • 切面拦截的是通用 Mapper 方法,参数类型不确定。
  • 反射可以在运行时动态获取对象的类信息并调用方法。
  • 允许统一处理“自动填充字段”,无需修改所有实体类。

可选替代方案:

  • 定义统一接口或父类,但改动成本高。
  • 反射的优势是通用性强,无侵入现有代码结构。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐