

前言:为什么需要自定义注解?
在日常开发中,我们经常遇到两类重复工作:
日志记录:每个重要方法都要写 "开始执行"、"参数是 xxx"、"执行结束" 的代码;参数校验:判断输入是否为 null、年龄是否在合理范围、手机号格式是否正确等。
这些工作机械且冗余,而注解 + 反射正是解决这类问题的 "银弹"—— 用注解标记需要处理的地方,用反射自动执行逻辑,实现 "一次定义,多处复用"。
本文将带你从零实现两个实用案例:
- 自定义日志注解
@Log:自动记录方法调用细节; - 自定义参数校验注解
@NotNull、@Range:自动校验方法参数合法性。
全程实战,代码可直接运行,搭配图解帮你吃透底层逻辑。
案例一:自定义日志注解@Log—— 自动记录方法调用轨迹
需求分析
我们需要一个注解,标记在方法上后,能自动完成:
记录方法开始执行的时间;打印方法参数(可选);记录方法执行耗时;打印返回结果(可选);捕获并记录方法抛出的异常。
步骤 1:定义@Log注解
import java.lang.annotation.*; // 只能标记在方法上 @Target(ElementType.METHOD) // 运行时保留,允许反射获取 @Retention(RetentionPolicy.RUNTIME) public @interface Log { // 操作描述(如"创建订单") String description() default ""; // 是否记录参数 boolean recordParams() default true; // 是否记录返回值 boolean recordResult() default true; // 是否记录异常 boolean recordException() default true; }
元注解说明:
@Target(ElementType.METHOD):限制注解仅用于方法(符合日志记录的场景);@Retention(RetentionPolicy.RUNTIME):必须保留到运行时,否则反射无法获取。
步骤 2:创建使用@Log注解的业务类
public class OrderService { // 标记日志:记录参数和返回值,描述为"创建订单" @Log(description = "创建订单", recordParams = true, recordResult = true) public String createOrder(String userId, double amount) { if (amount <= 0) { throw new IllegalArgumentException("金额必须大于 0"); } // 模拟业务耗时 try { Thread.sleep(100); } catch (InterruptedException e) {} return "ORDER_" + System.currentTimeMillis(); } // 标记日志:不记录返回值(无返回值),描述为"取消订单" @Log(description = "取消订单", recordParams = true, recordResult = false) public void cancelOrder(String orderId) { if (orderId == null || orderId.isEmpty()) { throw new IllegalArgumentException("订单 ID 不能为空"); } // 模拟业务耗时 try { Thread.sleep(50); } catch (InterruptedException e) {} }
}



