02-Java语言核心-语法特性-注解体系详解

5 阅读11分钟

注解体系详解

一、知识概述

注解(Annotation)是Java 5引入的一种元数据机制,它为代码提供了一种结构化的标记方式。注解本身不直接影响代码的执行,但可以被编译器、工具或框架读取并据此生成代码、进行验证或实现特定功能。

注解的作用

  1. 编译时检查:如 @Override 帮助编译器检查方法重写是否正确
  2. 代码生成:如 Lombok 自动生成 getter/setter
  3. 运行时处理:如 Spring 的依赖注入、事务管理
  4. 文档生成:如 Javadoc 使用注解生成文档

注解分类

类型保留范围用途
源码注解仅源码,编译后丢弃编译时检查、APT处理
编译注解编译后保留在class文件编译时处理、静态分析
运行时注解运行时通过反射获取框架运行时处理

二、知识点详细讲解

2.1 内置注解

Java 提供了一系列内置注解:

// === 编译相关 ===

// 标记方法重写父类方法
@Override
public String toString() {
    return "Override example";
}

// 标记已过时,不建议使用
@Deprecated
public void oldMethod() {
    // 旧方法,但仍保留兼容性
}

// 抑制编译器警告
@SuppressWarnings("unchecked")
public void suppressWarning() {
    List list = new ArrayList(); // 原始类型警告被抑制
}

// 标记功能性接口(只有一个抽象方法)
@FunctionalInterface
interface Calculator {
    int calculate(int a, int b);
}

// === Java 9+ 模块相关 ===

// 模块导出
// @Module(...)

// === Java 14+ 预览特性 ===

// 标记预览特性API
// @PreviewFeature

2.2 元注解

元注解是用于定义注解的注解:

/**
 * 元注解示例
 */

@Retention(RetentionPolicy.RUNTIME)  // 保留策略
@Target(ElementType.METHOD)          // 使用目标
@Documented                          // 包含在javadoc中
@Inherited                           // 可被子类继承
public @interface MyAnnotation {
    String value() default "";
    int count() default 0;
}
@Retention - 保留策略
public enum RetentionPolicy {
    SOURCE,   // 源码级,编译后丢弃
    CLASS,    // class级,保留到class文件但运行时不可见(默认)
    RUNTIME   // 运行时级,可通过反射读取
}
@Target - 使用目标
public enum ElementType {
    TYPE,               // 类、接口、枚举
    FIELD,              // 字段
    METHOD,             // 方法
    PARAMETER,          // 参数
    CONSTRUCTOR,        // 构造器
    LOCAL_VARIABLE,     // 局部变量
    ANNOTATION_TYPE,    // 注解类型
    PACKAGE,            // 包
    TYPE_PARAMETER,     // 类型参数(Java 8)
    TYPE_USE            // 类型使用(Java 8)
}
使用示例
// 不同目标示例
@Target(ElementType.TYPE)
@interface ClassAnnotation {}

@Target(ElementType.FIELD)
@interface FieldAnnotation {}

@Target(ElementType.METHOD)
@interface MethodAnnotation {}

@Target(ElementType.PARAMETER)
@interface ParamAnnotation {}

@Target({ElementType.FIELD, ElementType.METHOD})
@interface FieldOrMethodAnnotation {}

// Java 8 类型注解
@Target(ElementType.TYPE_USE)
@interface TypeAnnotation {}

// 类型注解使用示例
public class TypeAnnotationDemo {
    // 类型声明
    TypeAnnotationDemo.@TypeAnnotation Inner inner;
    
    // 泛型参数
    List<@TypeAnnotation String> strings;
    
    // 类型转换
    String s = (@TypeAnnotation String) new Object();
    
    // instanceof
    boolean isString = new Object() instanceof @TypeAnnotation String;
    
    class Inner {}
}

2.3 自定义注解

/**
 * 自定义注解:数据库表映射
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table {
    String name() default "";
    String schema() default "";
}

/**
 * 自定义注解:字段映射
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
    String name() default "";
    boolean nullable() default true;
    int length() default 255;
    String defaultValue() default "";
}

/**
 * 自定义注解:主键
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Id {
    boolean autoIncrement() default true;
}

/**
 * 自定义注解:忽略字段
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Ignore {}

/**
 * 自定义注解:方法日志
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
    String value() default "";
    LogLevel level() default LogLevel.INFO;
    
    enum LogLevel {
        DEBUG, INFO, WARN, ERROR
    }
}

/**
 * 自定义注解:重复注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Repeatable(Roles.class)
public @interface Role {
    String value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Roles {
    Role[] value();
}

2.4 注解属性类型

注解属性只能是以下类型:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface AnnotationTypes {
    // 基本类型
    int intValue();
    long longValue();
    double doubleValue();
    boolean booleanValue();
    
    // String
    String stringValue();
    
    // Class
    Class<?> classValue();
    
    // 枚举
    ElementType enumValue();
    
    // 注解
    Table annotationValue();
    
    // 以上类型的一维数组
    int[] intArray();
    String[] stringArray();
    Class<?>[] classArray();
    
    // 默认值
    String withDefault() default "default";
    
    // value() 是特殊属性,使用时可以省略属性名
    // @AnnotationTypes("test") 等同于 @AnnotationTypes(value = "test")
    String value() default "";
}

2.5 注解处理器(APT)

注解处理器在编译时处理注解,生成代码:

/**
 * 自定义注解:用于生成Builder
 */
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface GenerateBuilder {}

// 注解处理器需要继承 AbstractProcessor(通常单独放在 processor 模块)
// 这里展示处理器的核心逻辑框架

/*
public class BuilderProcessor extends AbstractProcessor {
    
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return Set.of(GenerateBuilder.class.getCanonicalName());
    }
    
    @Override
    public boolean process(Set<? extends TypeElement> annotations, 
                          RoundEnvironment roundEnv) {
        for (Element element : roundEnv.getElementsAnnotatedWith(GenerateBuilder.class)) {
            // 处理每个被注解的类
            // 生成 Builder 类代码
            generateBuilderClass((TypeElement) element);
        }
        return true;
    }
    
    private void generateBuilderClass(TypeElement element) {
        String className = element.getSimpleName().toString();
        String builderClassName = className + "Builder";
        // 使用 JavaPoet 或类似库生成代码
        // ...
    }
}
*/

2.6 运行时注解处理

通过反射读取运行时注解:

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 注解处理器:运行时处理
 */
public class AnnotationProcessor {
    
    /**
     * 解析类上的注解
     */
    public static void parseClassAnnotation(Class<?> clazz) {
        // 检查类是否有@Table注解
        if (clazz.isAnnotationPresent(Table.class)) {
            Table table = clazz.getAnnotation(Table.class);
            String tableName = table.name().isEmpty() ? 
                clazz.getSimpleName().toLowerCase() : table.name();
            System.out.println("表名: " + tableName);
        }
    }
    
    /**
     * 解析字段上的注解
     */
    public static void parseFieldAnnotations(Class<?> clazz) {
        for (Field field : clazz.getDeclaredFields()) {
            System.out.println("字段: " + field.getName());
            
            // 检查@Id注解
            if (field.isAnnotationPresent(Id.class)) {
                Id id = field.getAnnotation(Id.class);
                System.out.println("  - 主键, 自增: " + id.autoIncrement());
            }
            
            // 检查@Column注解
            if (field.isAnnotationPresent(Column.class)) {
                Column column = field.getAnnotation(Column.class);
                System.out.println("  - 列名: " + 
                    (column.name().isEmpty() ? field.getName() : column.name()));
                System.out.println("  - 可空: " + column.nullable());
                System.out.println("  - 长度: " + column.length());
            }
            
            // 检查@Ignore注解
            if (field.isAnnotationPresent(Ignore.class)) {
                System.out.println("  - 忽略该字段");
            }
        }
    }
    
    /**
     * 解析方法上的注解
     */
    public static void parseMethodAnnotations(Class<?> clazz) {
        for (Method method : clazz.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Log.class)) {
                Log log = method.getAnnotation(Log.class);
                System.out.println("方法: " + method.getName() + 
                    ", 日志级别: " + log.level() + 
                    ", 描述: " + log.value());
            }
        }
    }
    
    /**
     * 解析重复注解
     */
    public static void parseRepeatableAnnotation(Class<?> clazz) {
        // 方式1:获取容器注解
        if (clazz.isAnnotationPresent(Roles.class)) {
            Roles roles = clazz.getAnnotation(Roles.class);
            for (Role role : roles.value()) {
                System.out.println("角色: " + role.value());
            }
        }
        
        // 方式2:Java 8+ 直接获取重复注解
        Role[] roles = clazz.getAnnotationsByType(Role.class);
        for (Role role : roles) {
            System.out.println("角色: " + role.value());
        }
    }
}

三、可运行Java代码示例

完整示例:ORM框架核心

import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;

// === 注解定义 ===

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Entity {
    String tableName() default "";
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface ID {
    String columnName() default "";
    boolean autoIncrement() default true;
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Column {
    String name() default "";
    String type() default "VARCHAR";
    int length() default 255;
    boolean nullable() default true;
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Transient {}

// === 实体类 ===

@Entity(tableName = "users")
class User {
    @ID(columnName = "user_id")
    private Long id;
    
    @Column(name = "username", length = 50, nullable = false)
    private String username;
    
    @Column(name = "email", length = 100)
    private String email;
    
    @Transient
    private String password; // 不映射到数据库
    
    @Column(name = "created_at", type = "DATETIME")
    private Date createdAt;
    
    // 构造器、getter、setter
    public User() {}
    
    public User(String username, String email) {
        this.username = username;
        this.email = email;
        this.createdAt = new Date();
    }
    
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public Date getCreatedAt() { return createdAt; }
    public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; }
}

// === ORM核心处理 ===

class SimpleORM {
    
    /**
     * 根据实体类生成建表SQL
     */
    public static String generateCreateTableSQL(Class<?> entityClass) {
        StringBuilder sql = new StringBuilder("CREATE TABLE ");
        
        // 表名
        Entity entity = entityClass.getAnnotation(Entity.class);
        String tableName = entity.tableName().isEmpty() ? 
            entityClass.getSimpleName().toLowerCase() : entity.tableName();
        sql.append(tableName).append(" (\n");
        
        // 字段
        List<String> columns = new ArrayList<>();
        for (Field field : entityClass.getDeclaredFields()) {
            if (field.isAnnotationPresent(Transient.class)) continue;
            
            String columnDef = generateColumnDefinition(field);
            columns.add("    " + columnDef);
        }
        
        // 主键约束
        String primaryKey = findPrimaryKey(entityClass);
        if (primaryKey != null) {
            columns.add("    PRIMARY KEY (" + primaryKey + ")");
        }
        
        sql.append(String.join(",\n", columns));
        sql.append("\n)");
        
        return sql.toString();
    }
    
    private static String generateColumnDefinition(Field field) {
        StringBuilder def = new StringBuilder();
        
        // 列名
        String columnName;
        if (field.isAnnotationPresent(ID.class)) {
            columnName = field.getAnnotation(ID.class).columnName();
            if (columnName.isEmpty()) columnName = field.getName();
        } else if (field.isAnnotationPresent(Column.class)) {
            columnName = field.getAnnotation(Column.class).name();
            if (columnName.isEmpty()) columnName = field.getName();
        } else {
            columnName = field.getName();
        }
        def.append(columnName);
        
        // 类型
        String type = "VARCHAR";
        int length = 255;
        if (field.isAnnotationPresent(Column.class)) {
            Column column = field.getAnnotation(Column.class);
            type = column.type();
            length = column.length();
        }
        
        // 根据Java类型映射SQL类型
        Class<?> fieldType = field.getType();
        if (fieldType == Long.class || fieldType == long.class) {
            def.append(" BIGINT");
        } else if (fieldType == Integer.class || fieldType == int.class) {
            def.append(" INT");
        } else if (fieldType == String.class) {
            def.append(" ").append(type);
            if (length > 0 && !"TEXT".equalsIgnoreCase(type)) {
                def.append("(").append(length).append(")");
            }
        } else if (fieldType == Date.class) {
            def.append(" DATETIME");
        } else if (fieldType == Boolean.class || fieldType == boolean.class) {
            def.append(" TINYINT(1)");
        }
        
        // 可空
        if (field.isAnnotationPresent(Column.class)) {
            if (!field.getAnnotation(Column.class).nullable()) {
                def.append(" NOT NULL");
            }
        }
        
        // 自增
        if (field.isAnnotationPresent(ID.class)) {
            if (field.getAnnotation(ID.class).autoIncrement()) {
                def.append(" AUTO_INCREMENT");
            }
        }
        
        return def.toString();
    }
    
    private static String findPrimaryKey(Class<?> entityClass) {
        for (Field field : entityClass.getDeclaredFields()) {
            if (field.isAnnotationPresent(ID.class)) {
                ID id = field.getAnnotation(ID.class);
                return id.columnName().isEmpty() ? field.getName() : id.columnName();
            }
        }
        return null;
    }
    
    /**
     * 生成INSERT语句
     */
    public static String generateInsertSQL(Object entity) throws Exception {
        Class<?> clazz = entity.getClass();
        Entity entityAnnotation = clazz.getAnnotation(Entity.class);
        String tableName = entityAnnotation.tableName().isEmpty() ?
            clazz.getSimpleName().toLowerCase() : entityAnnotation.tableName();
        
        List<String> columns = new ArrayList<>();
        List<String> values = new ArrayList<>();
        
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(Transient.class)) continue;
            
            field.setAccessible(true);
            Object value = field.get(entity);
            if (value == null) continue;
            
            // 列名
            String columnName;
            if (field.isAnnotationPresent(ID.class)) {
                columnName = field.getAnnotation(ID.class).columnName();
                if (columnName.isEmpty()) columnName = field.getName();
            } else if (field.isAnnotationPresent(Column.class)) {
                columnName = field.getAnnotation(Column.class).name();
                if (columnName.isEmpty()) columnName = field.getName();
            } else {
                columnName = field.getName();
            }
            columns.add(columnName);
            
            // 值
            if (value instanceof String || value instanceof Date) {
                values.add("'" + value + "'");
            } else {
                values.add(value.toString());
            }
        }
        
        return String.format("INSERT INTO %s (%s) VALUES (%s)",
            tableName,
            String.join(", ", columns),
            String.join(", ", values));
    }
    
    /**
     * 根据ID生成查询语句
     */
    public static String generateSelectByIdSQL(Class<?> entityClass, Object id) {
        Entity entity = entityClass.getAnnotation(Entity.class);
        String tableName = entity.tableName().isEmpty() ?
            entityClass.getSimpleName().toLowerCase() : entity.tableName();
        
        String pkColumn = findPrimaryKey(entityClass);
        
        return String.format("SELECT * FROM %s WHERE %s = %s",
            tableName, pkColumn,
            id instanceof String ? "'" + id + "'" : id);
    }
}

// === 运行示例 ===
class ORMDemo {
    public static void main(String[] args) throws Exception {
        // 生成建表SQL
        System.out.println("=== 建表SQL ===");
        System.out.println(SimpleORM.generateCreateTableSQL(User.class));
        
        // 生成插入SQL
        System.out.println("\n=== 插入SQL ===");
        User user = new User("zhangsan", "zhangsan@example.com");
        System.out.println(SimpleORM.generateInsertSQL(user));
        
        // 生成查询SQL
        System.out.println("\n=== 查询SQL ===");
        System.out.println(SimpleORM.generateSelectByIdSQL(User.class, 1L));
    }
}

完整示例:方法权限控制

import java.lang.annotation.*;
import java.lang.reflect.*;

// === 注解定义 ===

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequireRole {
    String[] value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequirePermission {
    String value();
}

// === 用户角色枚举 ===
enum Role {
    ADMIN, MANAGER, USER, GUEST
}

// === 服务类 ===
class UserService {
    
    @RequireRole("ADMIN")
    public void deleteUser(Long userId) {
        System.out.println("删除用户: " + userId);
    }
    
    @RequireRole({"ADMIN", "MANAGER"})
    public void updateUser(Long userId, String newName) {
        System.out.println("更新用户: " + userId + ", 新名称: " + newName);
    }
    
    @RequirePermission("user:read")
    public User getUser(Long userId) {
        System.out.println("查询用户: " + userId);
        return new User("test", "test@example.com");
    }
    
    public void listUsers() {
        System.out.println("列出所有用户");
    }
}

// === 权限检查器 ===
class SecurityInterceptor {
    private Role currentRole = Role.USER;
    private Set<String> currentPermissions = new HashSet<>();
    
    public void setRole(Role role) {
        this.currentRole = role;
    }
    
    public void addPermission(String permission) {
        this.currentPermissions.add(permission);
    }
    
    /**
     * 方法调用拦截
     */
    public Object invoke(Object target, String methodName, Object... args) throws Exception {
        Method method = findMethod(target.getClass(), methodName, args);
        
        // 检查角色
        if (method.isAnnotationPresent(RequireRole.class)) {
            RequireRole requireRole = method.getAnnotation(RequireRole.class);
            boolean hasRole = false;
            for (String role : requireRole.value()) {
                if (currentRole.name().equals(role)) {
                    hasRole = true;
                    break;
                }
            }
            if (!hasRole) {
                throw new SecurityException("权限不足: 需要角色 " + 
                    Arrays.toString(requireRole.value()) + ", 当前角色: " + currentRole);
            }
        }
        
        // 检查权限
        if (method.isAnnotationPresent(RequirePermission.class)) {
            RequirePermission requirePerm = method.getAnnotation(RequirePermission.class);
            if (!currentPermissions.contains(requirePerm.value())) {
                throw new SecurityException("权限不足: 需要 " + requirePerm.value());
            }
        }
        
        // 执行方法
        return method.invoke(target, args);
    }
    
    private Method findMethod(Class<?> clazz, String name, Object[] args) {
        for (Method method : clazz.getDeclaredMethods()) {
            if (method.getName().equals(name) && 
                method.getParameterCount() == args.length) {
                return method;
            }
        }
        throw new IllegalArgumentException("方法不存在: " + name);
    }
}

// === 运行示例 ===
class SecurityDemo {
    public static void main(String[] args) throws Exception {
        UserService userService = new UserService();
        SecurityInterceptor interceptor = new SecurityInterceptor();
        
        // 场景1:普通用户尝试删除
        System.out.println("=== 场景1: USER角色尝试删除用户 ===");
        interceptor.setRole(Role.USER);
        try {
            interceptor.invoke(userService, "deleteUser", 1L);
        } catch (SecurityException e) {
            System.out.println("异常: " + e.getMessage());
        }
        
        // 场景2:管理员删除用户
        System.out.println("\n=== 场景2: ADMIN角色删除用户 ===");
        interceptor.setRole(Role.ADMIN);
        interceptor.invoke(userService, "deleteUser", 1L);
        
        // 场景3:管理员更新用户
        System.out.println("\n=== 场景3: ADMIN角色更新用户 ===");
        interceptor.invoke(userService, "updateUser", 1L, "新名字");
        
        // 场景4:经理更新用户
        System.out.println("\n=== 场景4: MANAGER角色更新用户 ===");
        interceptor.setRole(Role.MANAGER);
        interceptor.invoke(userService, "updateUser", 1L, "新名字");
        
        // 场景5:检查权限
        System.out.println("\n=== 场景5: 检查权限 ===");
        interceptor.setRole(Role.USER);
        try {
            interceptor.invoke(userService, "getUser", 1L);
        } catch (SecurityException e) {
            System.out.println("异常: " + e.getMessage());
        }
        
        interceptor.addPermission("user:read");
        interceptor.invoke(userService, "getUser", 1L);
    }
}

四、实战应用场景

场景1:参数校验注解

import java.lang.annotation.*;
import java.lang.reflect.*;

// === 校验注解 ===

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface NotNull {
    String message() default "不能为空";
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Size {
    int min() default 0;
    int max() default Integer.MAX_VALUE;
    String message() default "长度不符合要求";
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Pattern {
    String regex();
    String message() default "格式不正确";
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Range {
    long min() default Long.MIN_VALUE;
    long max() default Long.MAX_VALUE;
    String message() default "数值范围不正确";
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Valid {}

// === 实体类 ===

@Valid
class RegisterRequest {
    @NotNull(message = "用户名不能为空")
    @Size(min = 3, max = 20, message = "用户名长度需在3-20之间")
    private String username;
    
    @NotNull(message = "密码不能为空")
    @Size(min = 6, max = 30, message = "密码长度需在6-30之间")
    private String password;
    
    @Pattern(regex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$", message = "邮箱格式不正确")
    private String email;
    
    @Range(min = 18, max = 120, message = "年龄需在18-120之间")
    private Integer age;
    
    // getter/setter
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
}

// === 校验器 ===

class Validator {
    
    public static List<String> validate(Object obj) {
        List<String> errors = new ArrayList<>();
        
        if (!obj.getClass().isAnnotationPresent(Valid.class)) {
            return errors;
        }
        
        for (Field field : obj.getClass().getDeclaredFields()) {
            field.setAccessible(true);
            Object value;
            try {
                value = field.get(obj);
            } catch (IllegalAccessException e) {
                continue;
            }
            
            // @NotNull
            if (field.isAnnotationPresent(NotNull.class)) {
                if (value == null || (value instanceof String && ((String) value).isEmpty())) {
                    errors.add(field.getName() + ": " + field.getAnnotation(NotNull.class).message());
                }
            }
            
            // @Size
            if (field.isAnnotationPresent(Size.class) && value != null) {
                Size size = field.getAnnotation(Size.class);
                int length = value instanceof String ? ((String) value).length() : 0;
                if (length < size.min() || length > size.max()) {
                    errors.add(field.getName() + ": " + size.message());
                }
            }
            
            // @Pattern
            if (field.isAnnotationPresent(Pattern.class) && value != null) {
                Pattern pattern = field.getAnnotation(Pattern.class);
                if (!java.util.regex.Pattern.matches(pattern.regex(), value.toString())) {
                    errors.add(field.getName() + ": " + pattern.message());
                }
            }
            
            // @Range
            if (field.isAnnotationPresent(Range.class) && value instanceof Number) {
                Range range = field.getAnnotation(Range.class);
                long numValue = ((Number) value).longValue();
                if (numValue < range.min() || numValue > range.max()) {
                    errors.add(field.getName() + ": " + range.message());
                }
            }
        }
        
        return errors;
    }
}

// === 运行示例 ===

class ValidationDemo {
    public static void main(String[] args) {
        RegisterRequest request = new RegisterRequest();
        request.setUsername("ab"); // 太短
        request.setPassword("123"); // 太短
        request.setEmail("invalid-email"); // 格式错误
        request.setAge(15); // 年龄太小
        
        List<String> errors = Validator.validate(request);
        
        if (errors.isEmpty()) {
            System.out.println("校验通过");
        } else {
            System.out.println("校验失败:");
            errors.forEach(System.out::println);
        }
    }
}

场景2:缓存注解

import java.lang.annotation.*;
import java.util.concurrent.*;

// === 缓存注解 ===

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Cacheable {
    String key() default "";
    int expire() default 300; // 秒
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface CacheEvict {
    String key();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface CachePut {
    String key();
}

// === 缓存管理器 ===

class CacheManager {
    private static final ConcurrentHashMap<String, CacheEntry> cache = new ConcurrentHashMap<>();
    
    static class CacheEntry {
        Object value;
        long expireTime;
        
        CacheEntry(Object value, int expireSeconds) {
            this.value = value;
            this.expireTime = System.currentTimeMillis() + expireSeconds * 1000L;
        }
        
        boolean isExpired() {
            return System.currentTimeMillis() > expireTime;
        }
    }
    
    public static Object get(String key) {
        CacheEntry entry = cache.get(key);
        if (entry == null || entry.isExpired()) {
            cache.remove(key);
            return null;
        }
        return entry.value;
    }
    
    public static void put(String key, Object value, int expireSeconds) {
        cache.put(key, new CacheEntry(value, expireSeconds));
    }
    
    public static void evict(String key) {
        cache.remove(key);
    }
}

// === 服务类 ===

class ProductService {
    private int callCount = 0;
    
    @Cacheable(key = "product:", expire = 60)
    public String getProduct(String productId) {
        callCount++;
        System.out.println("执行getProduct方法,第" + callCount + "次");
        return "Product-" + productId + "-" + System.currentTimeMillis();
    }
    
    @CacheEvict(key = "product:")
    public void updateProduct(String productId, String newName) {
        System.out.println("更新产品: " + productId);
    }
    
    @CachePut(key = "product:")
    public String saveProduct(String productId, String name) {
        System.out.println("保存产品: " + productId);
        return name;
    }
}

// === 缓存代理 ===

class CacheProxy {
    public static Object invoke(Object target, Method method, Object... args) throws Exception {
        // 处理 @Cacheable
        if (method.isAnnotationPresent(Cacheable.class)) {
            Cacheable cacheable = method.getAnnotation(Cacheable.class);
            String key = cacheable.key() + (args.length > 0 ? args[0].toString() : "");
            
            Object cached = CacheManager.get(key);
            if (cached != null) {
                System.out.println("缓存命中: " + key);
                return cached;
            }
            
            System.out.println("缓存未命中: " + key);
            Object result = method.invoke(target, args);
            CacheManager.put(key, result, cacheable.expire());
            return result;
        }
        
        // 处理 @CacheEvict
        if (method.isAnnotationPresent(CacheEvict.class)) {
            CacheEvict evict = method.getAnnotation(CacheEvict.class);
            String key = evict.key() + (args.length > 0 ? args[0].toString() : "");
            CacheManager.evict(key);
            System.out.println("清除缓存: " + key);
            return method.invoke(target, args);
        }
        
        // 处理 @CachePut
        if (method.isAnnotationPresent(CachePut.class)) {
            CachePut put = method.getAnnotation(CachePut.class);
            Object result = method.invoke(target, args);
            String key = put.key() + (args.length > 0 ? args[0].toString() : "");
            CacheManager.put(key, result, 300);
            System.out.println("更新缓存: " + key);
            return result;
        }
        
        return method.invoke(target, args);
    }
}

// === 运行示例 ===

class CacheDemo {
    public static void main(String[] args) throws Exception {
        ProductService service = new ProductService();
        
        Method getProduct = ProductService.class.getMethod("getProduct", String.class);
        Method updateProduct = ProductService.class.getMethod("updateProduct", String.class, String.class);
        
        // 第一次调用,缓存未命中
        System.out.println("=== 第一次调用 ===");
        String result1 = (String) CacheProxy.invoke(service, getProduct, "P001");
        System.out.println("结果: " + result1);
        
        // 第二次调用,缓存命中
        System.out.println("\n=== 第二次调用 ===");
        String result2 = (String) CacheProxy.invoke(service, getProduct, "P001");
        System.out.println("结果: " + result2);
        
        // 更新产品,清除缓存
        System.out.println("\n=== 更新产品 ===");
        CacheProxy.invoke(service, updateProduct, "P001", "New Product");
        
        // 再次调用,缓存重新加载
        System.out.println("\n=== 更新后调用 ===");
        String result3 = (String) CacheProxy.invoke(service, getProduct, "P001");
        System.out.println("结果: " + result3);
    }
}

五、总结与最佳实践

核心要点回顾

概念说明
内置注解@Override、@Deprecated、@SuppressWarnings等
元注解定义注解的注解:@Retention、@Target、@Documented、@Inherited
自定义注解使用 @interface 关键字定义
注解属性只能是基本类型、String、Class、枚举、注解及其数组
保留策略SOURCE、CLASS、RUNTIME
注解处理APT(编译时)、反射(运行时)

最佳实践

  1. 选择合适的保留策略

    • 编译时检查用 SOURCE
    • 运行时处理用 RUNTIME
    • 生成文档用 RUNTIME + @Documented
  2. 合理设置目标

    @Target(ElementType.METHOD)  // 方法级注解
    @Target({ElementType.TYPE, ElementType.METHOD})  // 类或方法
    
  3. 使用默认值提高易用性

    public @interface MyAnnotation {
        String value() default "";
        boolean enabled() default true;
    }
    
  4. 善用 @Repeatable

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Repeatable(Roles.class)
    public @interface Role {
        String value();
    }
    
  5. 结合反射实现框架功能

    • 依赖注入
    • AOP拦截
    • ORM映射
    • 参数校验
  6. 注意性能

    • 反射读取注解有一定开销
    • 高频场景考虑缓存注解信息

常见框架注解

框架常用注解
Spring@Component、@Autowired、@Transactional、@RequestMapping
Spring Boot@SpringBootApplication、@ConfigurationProperties
MyBatis@Select、@Insert、@Update、@Delete
JPA@Entity、@Table、@Column、@Id
Lombok@Data、@Getter、@Setter、@Builder
Validation@NotNull、@Size、@Pattern、@Email

扩展阅读

  • Java 语言规范:注解的正式定义
  • Annotation Processing Tool (APT):编译时代码生成
  • Lombok 原理:如何通过注解生成代码
  • Spring 注解驱动开发:@Autowired、@Transactional 的实现原理