Java 反射与注解处理实战

框架的底层魔法:Spring 的依赖注入、MyBatis 的 ORM、JUnit 的测试发现,都靠反射和注解。本文讲清这两个 Java 进阶核心工具。

Java 反射配图:亮蓝色背景上透明玻璃立方体棱镜投射光束连接几何形状,扁平科技插画
反射与注解:框架的底层魔法

一、反射是什么

反射(Reflection)是运行时获取类信息、调用方法、访问字段的能力。普通编程在编译期确定类型,反射在运行期动态探查。Spring 能根据配置自动创建 Bean、注入依赖,全靠反射。

能力API
获取 ClassClass.forName() / obj.getClass()
创建实例clazz.getDeclaredConstructor().newInstance()
调用方法method.invoke(obj, args)
访问字段field.get(obj) / field.set(obj, value)

二、基础反射操作

// 获取 Class 对象
Class<User> clazz = User.class;

// 创建实例
User user = clazz.getDeclaredConstructor().newInstance();

// 获取并调用方法
Method method = clazz.getMethod("setName", String.class);
method.invoke(user, "张三");

// 获取并访问字段
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);  // 突破 private
String name = (String) field.get(user);
System.out.println(name);  // 张三
性能注意:反射比直接调用慢,因为绕过了编译优化。但现代 JVM(JIT 编译)对热点反射代码做了优化,差距已缩小。框架启动时用反射是可接受的。

三、自定义注解

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {
    String value() default "";
}

四、注解 + 反射实战

public class UserService {

    @Loggable("查询用户")
    public User findById(Long id) {
        return userRepository.findById(id).orElse(null);
    }

    @Loggable("创建用户")
    public void create(User user) {
        userRepository.save(user);
    }
}

// 注解处理器:自动打日志
public class LogProcessor {
    public static void process(Object bean) throws Exception {
        Method[] methods = bean.getClass().getDeclaredMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(Loggable.class)) {
                Loggable anno = method.getAnnotation(Loggable.class);
                System.out.println("[日志] 调用: " + anno.value());
            }
        }
    }
}

五、注解的保留策略

// SOURCE:只在源码保留,编译后丢弃(如 @Override)
@Retention(RetentionPolicy.SOURCE)

// CLASS:保留到 class 文件,运行时不加载(默认)
@Retention(RetentionPolicy.CLASS)

// RUNTIME:运行时保留,可通过反射读取(最常用)
@Retention(RetentionPolicy.RUNTIME)

六、常见框架中的应用

Spring 的 @Autowired 通过反射在启动时扫描 Bean 并注入依赖。MyBatis 的 @Select 注解在运行时解析 SQL 并执行。JUnit 5 的 @Test 注解被反射扫描后自动执行测试方法。注解 + 反射是框架魔法的底层基础。

七、总结

反射让 Java 拥有运行时动态能力,注解是给代码打标签的方式。两者结合就是框架的核心玩法。记住:反射功能强大但有性能开销,注解要选对保留策略,RUNTIME 才能被反射读到。