Java注解深度剖析与实战应用

35 阅读19分钟

Java注解深度剖析与实战应用

目录


一、注解概述

1.1 什么是注解

Java注解(Annotation)是JDK 5.0引入的一种特殊标记,可以附加在包、类、方法、字段等程序元素上。注解不会直接影响代码的执行,但可以被编译器、工具或运行时环境读取和处理。

+-------------------+
|   源代码层面      |  @Override, @Deprecated
+-------------------++-------------------+
|   编译期处理      |  Lombok, APT
+-------------------++-------------------+
|   运行期处理      |  Spring, MyBatis
+-------------------+

1.2 注解的作用

作用类型说明示例
编译检查让编译器进行语法检查@Override@SuppressWarnings
代码分析通过注解进行代码分析@Deprecated@FunctionalInterface
生成文档生成JavaDoc文档@param@return
代码生成自动生成代码Lombok的@Data@Builder
运行时处理运行时通过反射获取注解信息Spring的@Autowired@Transactional

1.3 注解 vs 注释

// 这是注释 - 给人看的,编译后会被删除
/**
 * JavaDoc注释 - 可以生成文档
 */

// 这是注解 - 给程序看的,可以保留到运行时
@Override
public String toString() {
    return "Annotation Example";
}

二、Java内置注解

2.1 基本内置注解

package com.example.annotation;

/**
 * Java内置注解示例
 */
public class BuiltInAnnotationDemo {

    /**
     * @Override - 表示方法重写父类方法
     * 作用: 编译器会检查是否真的重写了父类方法
     */
    @Override
    public String toString() {
        return "BuiltInAnnotationDemo";
    }

    /**
     * @Deprecated - 表示已过时
     * 作用: 编译器会给出警告,提示不建议使用
     */
    @Deprecated
    public void oldMethod() {
        System.out.println("这是一个过时的方法");
    }

    /**
     * @SuppressWarnings - 抑制编译警告
     * 常用参数:
     *   - "unchecked": 抑制未检查的转换警告
     *   - "deprecation": 抑制使用废弃API的警告
     *   - "rawtypes": 抑制原始类型警告
     *   - "all": 抑制所有警告
     */
    @SuppressWarnings("deprecation")
    public void callOldMethod() {
        oldMethod(); // 不会有警告
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    public void useRawType() {
        java.util.List list = new java.util.ArrayList();
        list.add("item"); // 不会有警告
    }

    /**
     * @FunctionalInterface - 标记函数式接口
     * 作用: 确保接口只有一个抽象方法
     */
    @FunctionalInterface
    interface Calculator {
        int calculate(int a, int b);

        // 可以有default方法
        default void print() {
            System.out.println("Calculator");
        }
    }

    /**
     * @SafeVarargs - 抑制可变参数泛型警告
     */
    @SafeVarargs
    public final <T> void printAll(T... items) {
        for (T item : items) {
            System.out.println(item);
        }
    }

    public static void main(String[] args) {
        BuiltInAnnotationDemo demo = new BuiltInAnnotationDemo();

        // 使用函数式接口
        Calculator add = (a, b) -> a + b;
        System.out.println("5 + 3 = " + add.calculate(5, 3));

        // 使用可变参数方法
        demo.printAll("A", "B", "C");
    }
}

2.2 JDK 9+ 新增注解

package com.example.annotation;

/**
 * JDK 9+ 新增注解示例
 */
public class NewAnnotationDemo {

    /**
     * @since 9 - Java 9新增
     * 用于标记已废弃的API,并提供更详细的信息
     */
    @Deprecated(since = "9", forRemoval = true)
    public void willBeRemoved() {
        System.out.println("此方法将在未来版本中移除");
    }

    /**
     * 使用被标记为移除的方法会收到更严重的警告
     */
    public void useDeprecatedMethod() {
        willBeRemoved(); // 会有警告: 此方法计划被移除
    }
}

三、元注解详解

元注解(Meta-Annotation)是用来定义其他注解的注解,位于java.lang.annotation包中。

3.1 @Retention - 保留策略

package com.example.annotation.meta;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * @Retention - 定义注解的生命周期
 *
 * 三种保留策略:
 * +-----------------+------------------+-------------------+
 * | RetentionPolicy | 保留阶段         | 典型应用          |
 * +-----------------+------------------+-------------------+
 * | SOURCE          | 源码阶段         | @Override         |
 * | CLASS           | 字节码阶段(默认) | APT处理器         |
 * | RUNTIME         | 运行时           | Spring, MyBatis   |
 * +-----------------+------------------+-------------------+
 */

// SOURCE - 只在源码中保留,编译后丢弃
@Retention(RetentionPolicy.SOURCE)
@interface SourceAnnotation {
    String value();
}

// CLASS - 保留到字节码,运行时不可见(默认)
@Retention(RetentionPolicy.CLASS)
@interface ClassAnnotation {
    String value();
}

// RUNTIME - 运行时可见,可通过反射读取
@Retention(RetentionPolicy.RUNTIME)
@interface RuntimeAnnotation {
    String value();
}

/**
 * 演示不同保留策略
 */
@SourceAnnotation("源码注解")
@ClassAnnotation("字节码注解")
@RuntimeAnnotation("运行时注解")
public class RetentionDemo {

    public static void main(String[] args) {
        Class<RetentionDemo> clazz = RetentionDemo.class;

        System.out.println("=== 通过反射读取注解 ===");

        // SOURCE注解: 读不到(已在编译时丢弃)
        SourceAnnotation source = clazz.getAnnotation(SourceAnnotation.class);
        System.out.println("SOURCE注解: " + source);

        // CLASS注解: 读不到(运行时不可见)
        ClassAnnotation classAnn = clazz.getAnnotation(ClassAnnotation.class);
        System.out.println("CLASS注解: " + classAnn);

        // RUNTIME注解: 能读到
        RuntimeAnnotation runtime = clazz.getAnnotation(RuntimeAnnotation.class);
        System.out.println("RUNTIME注解: " + runtime);
        if (runtime != null) {
            System.out.println("  value = " + runtime.value());
        }
    }
}

3.2 @Target - 作用目标

package com.example.annotation.meta;

import java.lang.annotation.*;

/**
 * @Target - 定义注解可以用在哪些地方
 */

// 只能用在类上
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Entity {
    String tableName();
}

// 只能用在字段上
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Column {
    String name();
    boolean nullable() default true;
}

// 只能用在方法上
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Transactional {
    String value() default "";
}

// 可以用在多个地方
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface Validate {
    String pattern();
}

/**
 * ElementType枚举值说明:
 * +------------------+------------------------+
 * | ElementType      | 说明                   |
 * +------------------+------------------------+
 * | TYPE             | 类、接口、枚举         |
 * | FIELD            | 字段                   |
 * | METHOD           | 方法                   |
 * | PARAMETER        | 方法参数               |
 * | CONSTRUCTOR      | 构造器                 |
 * | LOCAL_VARIABLE   | 局部变量               |
 * | ANNOTATION_TYPE  | 注解类型               |
 * | PACKAGE          | 包                     |
 * | TYPE_PARAMETER   | 类型参数(泛型)         |
 * | TYPE_USE         | 任何类型使用的地方     |
 * +------------------+------------------------+
 */

@Entity(tableName = "user")
public class TargetDemo {

    @Column(name = "user_id")
    @Validate(pattern = "\\d+")
    private Long id;

    @Column(name = "username", nullable = false)
    @Validate(pattern = "[a-zA-Z0-9_]+")
    private String username;

    @Transactional
    @Validate(pattern = ".*")
    public void save() {
        System.out.println("保存数据");
    }
}

3.3 @Documented - 生成文档

package com.example.annotation.meta;

import java.lang.annotation.*;

/**
 * @Documented - 将注解包含在JavaDoc中
 */

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface ApiDoc {
    String description();
    String version() default "1.0";
}

public class DocumentedDemo {

    /**
     * 用户登录接口
     * 此方法的注解会出现在JavaDoc中
     */
    @ApiDoc(description = "用户登录", version = "2.0")
    public void login(String username, String password) {
        System.out.println("登录: " + username);
    }
}

3.4 @Inherited - 注解继承

package com.example.annotation.meta;

import java.lang.annotation.*;

/**
 * @Inherited - 允许子类继承父类的注解
 * 注意: 只对类有效,对方法/字段无效
 */

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface ParentAnnotation {
    String value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface NoInheritedAnnotation {
    String value();
}

@ParentAnnotation("父类注解")
@NoInheritedAnnotation("不继承的注解")
class Parent {
}

// 子类会继承@ParentAnnotation,但不会继承@NoInheritedAnnotation
class Child extends Parent {
}

public class InheritedDemo {

    public static void main(String[] args) {
        Class<Child> clazz = Child.class;

        ParentAnnotation parent = clazz.getAnnotation(ParentAnnotation.class);
        System.out.println("@ParentAnnotation: " +
            (parent != null ? parent.value() : "null"));

        NoInheritedAnnotation noInherited = clazz.getAnnotation(NoInheritedAnnotation.class);
        System.out.println("@NoInheritedAnnotation: " +
            (noInherited != null ? noInherited.value() : "null"));
    }
}

3.5 @Repeatable - 重复注解

package com.example.annotation.meta;

import java.lang.annotation.*;

/**
 * @Repeatable - 允许在同一位置多次使用同一注解(Java 8+)
 */

@Repeatable(Schedules.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Schedule {
    String day();
    String time();
}

// 容器注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Schedules {
    Schedule[] value();
}

public class RepeatableDemo {

    // Java 8之前需要这样写:
    // @Schedules({
    //     @Schedule(day = "Monday", time = "09:00"),
    //     @Schedule(day = "Friday", time = "14:00")
    // })

    // Java 8+可以直接重复使用:
    @Schedule(day = "Monday", time = "09:00")
    @Schedule(day = "Wednesday", time = "10:00")
    @Schedule(day = "Friday", time = "14:00")
    public void meeting() {
        System.out.println("开会");
    }

    public static void main(String[] args) throws Exception {
        var method = RepeatableDemo.class.getMethod("meeting");

        // 获取所有Schedule注解
        Schedule[] schedules = method.getAnnotationsByType(Schedule.class);

        System.out.println("=== 会议时间表 ===");
        for (Schedule schedule : schedules) {
            System.out.println(schedule.day() + " " + schedule.time());
        }
    }
}

四、自定义注解

4.1 自定义注解语法

package com.example.annotation.custom;

import java.lang.annotation.*;

/**
 * 自定义注解语法结构
 */

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CustomAnnotation {

    // 1. 基本属性(无默认值,使用时必须指定)
    String name();

    // 2. 带默认值的属性
    int age() default 0;

    // 3. 数组类型属性
    String[] tags() default {};

    // 4. 枚举类型属性
    Priority priority() default Priority.MEDIUM;

    // 5. Class类型属性
    Class<?> type() default Void.class;

    // 6. 其他注解类型
    Description description() default @Description(value = "默认描述");

    // 7. value属性(特殊名称,使用时可省略"value=")
    String value() default "";
}

enum Priority {
    LOW, MEDIUM, HIGH
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Description {
    String value();
}

/**
 * 使用自定义注解
 */
// 完整写法
@CustomAnnotation(
    name = "测试类",
    age = 10,
    tags = {"test", "demo"},
    priority = Priority.HIGH,
    type = String.class,
    description = @Description("这是一个测试类"),
    value = "简化写法"
)
class FullDemo {
}

// 简化写法(只有value时)
@CustomAnnotation("简化写法")
class SimpleDemo {
}

4.2 实战案例:Excel导出注解

package com.example.annotation.custom;

import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * Excel导出注解(类似EasyExcel)
 */

// 标记在类上,指定Sheet名称
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface ExcelSheet {
    String name() default "Sheet1";
}

// 标记在字段上,指定列名和顺序
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface ExcelColumn {
    String name(); // 列名
    int order() default 0; // 列顺序
    String format() default ""; // 格式化(日期等)
    boolean ignore() default false; // 是否忽略
}

/**
 * 用户实体
 */
@ExcelSheet(name = "用户列表")
class User {

    @ExcelColumn(name = "用户ID", order = 1)
    private Long id;

    @ExcelColumn(name = "用户名", order = 2)
    private String username;

    @ExcelColumn(name = "邮箱", order = 3)
    private String email;

    @ExcelColumn(name = "年龄", order = 4)
    private Integer age;

    @ExcelColumn(name = "创建时间", order = 5, format = "yyyy-MM-dd HH:mm:ss")
    private java.util.Date createTime;

    @ExcelColumn(name = "密码", ignore = true) // 敏感信息不导出
    private String password;

    public User(Long id, String username, String email, Integer age, String password) {
        this.id = id;
        this.username = username;
        this.email = email;
        this.age = age;
        this.password = password;
        this.createTime = new java.util.Date();
    }

    // Getters
    public Long getId() { return id; }
    public String getUsername() { return username; }
    public String getEmail() { return email; }
    public Integer getAge() { return age; }
    public java.util.Date getCreateTime() { return createTime; }
    public String getPassword() { return password; }
}

/**
 * Excel导出工具类
 */
class ExcelExporter {

    /**
     * 导出数据(简化版,实际应使用POI库)
     */
    public static <T> void export(List<T> dataList) throws Exception {

        if (dataList == null || dataList.isEmpty()) {
            System.out.println("数据为空");
            return;
        }

        Class<?> clazz = dataList.get(0).getClass();

        // 1. 获取Sheet名称
        String sheetName = "Sheet1";
        if (clazz.isAnnotationPresent(ExcelSheet.class)) {
            ExcelSheet sheet = clazz.getAnnotation(ExcelSheet.class);
            sheetName = sheet.name();
        }

        System.out.println("=== 导出Excel: " + sheetName + " ===\n");

        // 2. 获取所有需要导出的字段
        List<FieldInfo> fieldInfos = new ArrayList<>();
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(ExcelColumn.class)) {
                ExcelColumn column = field.getAnnotation(ExcelColumn.class);
                if (!column.ignore()) {
                    fieldInfos.add(new FieldInfo(field, column));
                }
            }
        }

        // 3. 按order排序
        fieldInfos.sort((a, b) -> a.column.order() - b.column.order());

        // 4. 打印表头
        for (FieldInfo info : fieldInfos) {
            System.out.print(info.column.name() + "\t");
        }
        System.out.println();
        System.out.println("-----------------------------------------------------------");

        // 5. 打印数据
        for (T data : dataList) {
            for (FieldInfo info : fieldInfos) {
                info.field.setAccessible(true);
                Object value = info.field.get(data);

                // 格式化处理
                if (value instanceof java.util.Date && !info.column.format().isEmpty()) {
                    value = new java.text.SimpleDateFormat(info.column.format()).format(value);
                }

                System.out.print(value + "\t");
            }
            System.out.println();
        }
    }

    static class FieldInfo {
        Field field;
        ExcelColumn column;

        FieldInfo(Field field, ExcelColumn column) {
            this.field = field;
            this.column = column;
        }
    }
}

/**
 * 测试Excel导出
 */
class ExcelExportDemo {

    public static void main(String[] args) throws Exception {

        List<User> users = new ArrayList<>();
        users.add(new User(1L, "zhangsan", "zhangsan@example.com", 25, "pass123"));
        users.add(new User(2L, "lisi", "lisi@example.com", 30, "pass456"));
        users.add(new User(3L, "wangwu", "wangwu@example.com", 28, "pass789"));

        // 导出Excel
        ExcelExporter.export(users);
    }
}

五、注解处理器

5.1 运行时注解处理器

package com.example.annotation.processor;

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

/**
 * 运行时注解处理器 - 通过反射读取注解
 */

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface PerformanceTest {
    int iterations() default 1;
}

/**
 * 性能测试工具
 */
class PerformanceTester {

    /**
     * 执行所有带@PerformanceTest注解的方法
     */
    public static void runTests(Object obj) throws Exception {

        Class<?> clazz = obj.getClass();
        Method[] methods = clazz.getDeclaredMethods();

        System.out.println("=== 性能测试报告 ===\n");

        for (Method method : methods) {
            if (method.isAnnotationPresent(PerformanceTest.class)) {
                PerformanceTest test = method.getAnnotation(PerformanceTest.class);

                // 执行测试
                method.setAccessible(true);
                long startTime = System.nanoTime();

                for (int i = 0; i < test.iterations(); i++) {
                    method.invoke(obj);
                }

                long endTime = System.nanoTime();
                double avgTime = (endTime - startTime) / 1_000_000.0 / test.iterations();

                System.out.println("方法: " + method.getName());
                System.out.println("迭代次数: " + test.iterations());
                System.out.println("平均耗时: " + String.format("%.3f", avgTime) + "ms");
                System.out.println("---");
            }
        }
    }
}

/**
 * 测试类
 */
class MyService {

    @PerformanceTest(iterations = 1000)
    public void quickMethod() {
        // 快速方法
        int sum = 0;
        for (int i = 0; i < 100; i++) {
            sum += i;
        }
    }

    @PerformanceTest(iterations = 100)
    public void slowMethod() {
        // 慢方法
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void normalMethod() {
        // 没有注解,不会被测试
        System.out.println("普通方法");
    }
}

/**
 * 运行测试
 */
class RuntimeProcessorDemo {

    public static void main(String[] args) throws Exception {
        MyService service = new MyService();
        PerformanceTester.runTests(service);
    }
}

5.2 编译期注解处理器(APT)

package com.example.annotation.processor;

/**
 * 编译期注解处理器 - APT(Annotation Processing Tool)
 *
 * 典型应用:
 * 1. Lombok: @Data, @Builder等自动生成代码
 * 2. Dagger: 依赖注入框架
 * 3. ButterKnife: Android视图绑定
 * 4. MapStruct: 对象映射工具
 *
 * APT处理流程:
 * +------------------+
 * |   源代码(.java)  |
 * +------------------+
 *          ↓
 * +------------------+
 * | 注解处理器(APT)  |  <-- 读取注解,生成新代码
 * +------------------+
 *          ↓
 * +------------------+
 * |  生成代码(.java) |
 * +------------------+
 *          ↓
 * +------------------+
 * |  编译成字节码    |
 * +------------------+
 */

/**
 * Lombok @Data注解原理演示
 *
 * 使用@Data前:
 * @Data
 * public class User {
 *     private Long id;
 *     private String name;
 * }
 *
 * APT生成后的代码:
 * public class User {
 *     private Long id;
 *     private String name;
 *
 *     public Long getId() { return id; }
 *     public void setId(Long id) { this.id = id; }
 *     public String getName() { return name; }
 *     public void setName(String name) { this.name = name; }
 *
 *     @Override
 *     public boolean equals(Object o) { ... }
 *     @Override
 *     public int hashCode() { ... }
 *     @Override
 *     public String toString() { ... }
 * }
 */

public class AptDemo {

    public static void main(String[] args) {
        System.out.println("=== 编译期注解处理器(APT) ===\n");

        System.out.println("APT的优势:");
        System.out.println("1. 编译期生成代码,运行时零成本");
        System.out.println("2. 减少样板代码,提高开发效率");
        System.out.println("3. 类型安全,编译期检查");
        System.out.println("4. 性能优于反射");

        System.out.println("\n常见APT框架:");
        System.out.println("• Lombok - 自动生成getter/setter/toString等");
        System.out.println("• MapStruct - Bean映射");
        System.out.println("• Dagger/Hilt - 依赖注入");
        System.out.println("• ButterKnife - 视图绑定");
        System.out.println("• AutoService - SPI自动注册");
    }
}

六、Spring框架中的注解

6.1 Spring核心注解

package com.example.annotation.spring;

import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 模拟Spring核心注解
 */

// === 组件注解 ===

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

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

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

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

// === 依赖注入注解 ===

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})
@interface Autowired {
    boolean required() default true;
}

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@interface Qualifier {
    String value();
}

// === 配置注解 ===

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Bean {
    String name() default "";
}

// === 切面注解 ===

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Transactional {
    String value() default "";
    boolean readOnly() default false;
}

/**
 * 简化版Spring容器
 */
class MiniSpringContainer {

    private Map<Class<?>, Object> beans = new HashMap<>();

    /**
     * 扫描并注册Bean
     */
    public void scan(Class<?>... classes) throws Exception {
        for (Class<?> clazz : classes) {
            if (clazz.isAnnotationPresent(Component.class) ||
                clazz.isAnnotationPresent(Service.class) ||
                clazz.isAnnotationPresent(Repository.class) ||
                clazz.isAnnotationPresent(Controller.class)) {

                // 创建实例
                Object instance = clazz.getDeclaredConstructor().newInstance();
                beans.put(clazz, instance);
                System.out.println("注册Bean: " + clazz.getSimpleName());
            }
        }

        // 处理依赖注入
        for (Object bean : beans.values()) {
            injectDependencies(bean);
        }
    }

    /**
     * 依赖注入
     */
    private void injectDependencies(Object bean) throws Exception {
        Field[] fields = bean.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(Autowired.class)) {
                field.setAccessible(true);
                Object dependency = beans.get(field.getType());
                if (dependency != null) {
                    field.set(bean, dependency);
                    System.out.println("  注入: " + bean.getClass().getSimpleName() +
                        "." + field.getName());
                }
            }
        }
    }

    /**
     * 获取Bean
     */
    @SuppressWarnings("unchecked")
    public <T> T getBean(Class<T> clazz) {
        return (T) beans.get(clazz);
    }

    /**
     * 执行带@Transactional的方法(AOP)
     */
    public Object executeWithTransaction(Object bean, String methodName) throws Exception {
        Method method = bean.getClass().getDeclaredMethod(methodName);

        if (method.isAnnotationPresent(Transactional.class)) {
            Transactional tx = method.getAnnotation(Transactional.class);
            System.out.println("\n[事务开始] readOnly=" + tx.readOnly());
        }

        Object result = method.invoke(bean);

        if (method.isAnnotationPresent(Transactional.class)) {
            System.out.println("[事务提交]\n");
        }

        return result;
    }
}

/**
 * 业务层示例
 */

@Repository
class UserRepository {
    public void save(String username) {
        System.out.println("    [DAO] 保存用户: " + username);
    }
}

@Service
class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional(readOnly = false)
    public void registerUser(String username) {
        System.out.println("  [Service] 执行注册逻辑");
        userRepository.save(username);
    }

    @Transactional(readOnly = true)
    public void queryUser(String username) {
        System.out.println("  [Service] 查询用户: " + username);
    }
}

@Controller
class UserController {

    @Autowired
    private UserService userService;

    public void handleRegister(String username) {
        System.out.println("[Controller] 接收注册请求");
        userService.registerUser(username);
    }
}

/**
 * 测试Spring注解
 */
class SpringAnnotationDemo {

    public static void main(String[] args) throws Exception {

        // 创建容器并扫描
        MiniSpringContainer container = new MiniSpringContainer();
        container.scan(UserRepository.class, UserService.class, UserController.class);

        System.out.println("\n=== 测试依赖注入和事务 ===\n");

        // 获取Controller并调用
        UserController controller = container.getBean(UserController.class);
        controller.handleRegister("zhangsan");

        // 测试事务注解
        UserService service = container.getBean(UserService.class);
        container.executeWithTransaction(service, "queryUser");
    }
}

6.2 Spring MVC注解

package com.example.annotation.spring;

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

/**
 * Spring MVC核心注解
 */

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

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@interface RequestMapping {
    String value() default "";
    String method() default "GET";
}

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

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@interface RequestParam {
    String value();
    boolean required() default true;
    String defaultValue() default "";
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@interface PathVariable {
    String value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@interface RequestBody {
}

/**
 * REST API Controller
 */
@RestController
@RequestMapping("/api/users")
class UserRestController {

    @GetMapping("/list")
    public String listUsers(@RequestParam(value = "page", defaultValue = "1") int page,
                           @RequestParam(value = "size", defaultValue = "10") int size) {
        return "用户列表: page=" + page + ", size=" + size;
    }

    @GetMapping("/{id}")
    public String getUser(@PathVariable("id") Long id) {
        return "获取用户: id=" + id;
    }

    @PostMapping("/create")
    public String createUser(@RequestBody String userData) {
        return "创建用户: " + userData;
    }
}

/**
 * 简化版MVC请求分发器
 */
class SimpleDispatcherServlet {

    /**
     * 模拟处理HTTP请求
     */
    public static String handleRequest(Object controller, String uri, String method,
                                      Map<String, String> params) throws Exception {

        Class<?> clazz = controller.getClass();

        // 获取Controller路径
        String basePath = "";
        if (clazz.isAnnotationPresent(RequestMapping.class)) {
            basePath = clazz.getAnnotation(RequestMapping.class).value();
        }

        // 查找匹配的方法
        for (Method m : clazz.getDeclaredMethods()) {
            String methodPath = getMethodPath(m);
            if (methodPath == null) continue;

            String fullPath = basePath + methodPath;

            // 简化的路径匹配
            if (matchPath(uri, fullPath)) {
                System.out.println("\n[DispatcherServlet] " + method + " " + uri);
                System.out.println("[DispatcherServlet] 匹配到方法: " + m.getName());

                // 准备参数
                Object[] args = prepareArguments(m, uri, params);

                // 调用方法
                return (String) m.invoke(controller, args);
            }
        }

        return "404 Not Found";
    }

    private static String getMethodPath(Method method) {
        if (method.isAnnotationPresent(GetMapping.class)) {
            return method.getAnnotation(GetMapping.class).value();
        }
        if (method.isAnnotationPresent(PostMapping.class)) {
            return method.getAnnotation(PostMapping.class).value();
        }
        return null;
    }

    private static boolean matchPath(String uri, String pattern) {
        // 简化的路径匹配
        if (pattern.contains("{")) {
            String regex = pattern.replaceAll("\\{[^}]+\\}", "[^/]+");
            return uri.matches(regex);
        }
        return uri.equals(pattern);
    }

    private static Object[] prepareArguments(Method method, String uri,
                                            Map<String, String> params) {
        Parameter[] parameters = method.getParameters();
        Object[] args = new Object[parameters.length];

        for (int i = 0; i < parameters.length; i++) {
            Parameter param = parameters[i];

            if (param.isAnnotationPresent(RequestParam.class)) {
                RequestParam rp = param.getAnnotation(RequestParam.class);
                String value = params.getOrDefault(rp.value(), rp.defaultValue());
                args[i] = convertType(value, param.getType());
            } else if (param.isAnnotationPresent(PathVariable.class)) {
                PathVariable pv = param.getAnnotation(PathVariable.class);
                // 简化:从URI中提取值
                args[i] = 1L;
            } else if (param.isAnnotationPresent(RequestBody.class)) {
                args[i] = "{\"username\":\"zhangsan\"}";
            }
        }

        return args;
    }

    private static Object convertType(String value, Class<?> type) {
        if (type == int.class || type == Integer.class) {
            return Integer.parseInt(value);
        }
        return value;
    }
}

/**
 * 测试Spring MVC注解
 */
class SpringMvcDemo {

    public static void main(String[] args) throws Exception {

        UserRestController controller = new UserRestController();

        // 测试GET请求
        Map<String, String> params1 = new HashMap<>();
        params1.put("page", "2");
        params1.put("size", "20");
        String result1 = SimpleDispatcherServlet.handleRequest(
            controller, "/api/users/list", "GET", params1);
        System.out.println("响应: " + result1);

        // 测试路径变量
        String result2 = SimpleDispatcherServlet.handleRequest(
            controller, "/api/users/123", "GET", new HashMap<>());
        System.out.println("响应: " + result2);

        // 测试POST请求
        String result3 = SimpleDispatcherServlet.handleRequest(
            controller, "/api/users/create", "POST", new HashMap<>());
        System.out.println("响应: " + result3);
    }
}

七、MyBatis注解应用

package com.example.annotation.mybatis;

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

/**
 * MyBatis注解式开发
 */

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

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

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

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@interface Param {
    String value();
}

/**
 * Mapper接口
 */
interface UserMapper {

    @Select("SELECT * FROM user WHERE id = #{id}")
    User findById(@Param("id") Long id);

    @Select("SELECT * FROM user WHERE username = #{username}")
    User findByUsername(@Param("username") String username);

    @Insert("INSERT INTO user(id, username, email) VALUES(#{id}, #{username}, #{email})")
    int insert(@Param("user") User user);

    @Update("UPDATE user SET email = #{email} WHERE id = #{id}")
    int updateEmail(@Param("id") Long id, @Param("email") String email);

    @Delete("DELETE FROM user WHERE id = #{id}")
    int deleteById(@Param("id") Long id);
}

/**
 * 实体类
 */
class User {
    private Long id;
    private String username;
    private String email;

    public User() {}

    public User(Long id, String username, String email) {
        this.id = id;
        this.username = username;
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{id=" + id + ", username='" + username + "', email='" + email + "'}";
    }

    // Getters
    public Long getId() { return id; }
    public String getUsername() { return username; }
    public String getEmail() { return email; }
}

/**
 * 简化版MyBatis - Mapper代理工厂
 */
class MapperProxyFactory {

    // 模拟数据库
    private static Map<Long, User> database = new HashMap<>();

    static {
        database.put(1L, new User(1L, "zhangsan", "zhangsan@example.com"));
        database.put(2L, new User(2L, "lisi", "lisi@example.com"));
    }

    @SuppressWarnings("unchecked")
    public static <T> T getMapper(Class<T> mapperInterface) {
        return (T) Proxy.newProxyInstance(
            mapperInterface.getClassLoader(),
            new Class[]{mapperInterface},
            (proxy, method, args) -> {

                // 解析SQL注解
                String sql = null;
                String sqlType = null;

                if (method.isAnnotationPresent(Select.class)) {
                    sql = method.getAnnotation(Select.class).value();
                    sqlType = "SELECT";
                } else if (method.isAnnotationPresent(Insert.class)) {
                    sql = method.getAnnotation(Insert.class).value();
                    sqlType = "INSERT";
                } else if (method.isAnnotationPresent(Update.class)) {
                    sql = method.getAnnotation(Update.class).value();
                    sqlType = "UPDATE";
                } else if (method.isAnnotationPresent(Delete.class)) {
                    sql = method.getAnnotation(Delete.class).value();
                    sqlType = "DELETE";
                }

                if (sql == null) {
                    throw new RuntimeException("未找到SQL注解");
                }

                // 解析参数
                Map<String, Object> paramMap = parseParams(method, args);

                // 执行SQL(模拟)
                System.out.println("\n[MyBatis] " + sqlType + ": " + sql);
                System.out.println("[MyBatis] 参数: " + paramMap);

                // 模拟执行并返回结果
                return executeSql(sqlType, paramMap);
            }
        );
    }

    private static Map<String, Object> parseParams(Method method, Object[] args) {
        Map<String, Object> paramMap = new HashMap<>();
        Parameter[] parameters = method.getParameters();

        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            if (parameter.isAnnotationPresent(Param.class)) {
                String paramName = parameter.getAnnotation(Param.class).value();
                paramMap.put(paramName, args[i]);
            }
        }

        return paramMap;
    }

    private static Object executeSql(String sqlType, Map<String, Object> params) {
        switch (sqlType) {
            case "SELECT":
                Long id = (Long) params.get("id");
                if (id != null) {
                    User user = database.get(id);
                    System.out.println("[MyBatis] 查询结果: " + user);
                    return user;
                }
                String username = (String) params.get("username");
                if (username != null) {
                    User user = database.values().stream()
                        .filter(u -> u.getUsername().equals(username))
                        .findFirst().orElse(null);
                    System.out.println("[MyBatis] 查询结果: " + user);
                    return user;
                }
                break;

            case "INSERT":
            case "UPDATE":
            case "DELETE":
                System.out.println("[MyBatis] 影响行数: 1");
                return 1;
        }

        return null;
    }
}

/**
 * 测试MyBatis注解
 */
class MyBatisAnnotationDemo {

    public static void main(String[] args) {

        // 获取Mapper代理
        UserMapper userMapper = MapperProxyFactory.getMapper(UserMapper.class);

        // 查询
        userMapper.findById(1L);
        userMapper.findByUsername("lisi");

        // 插入
        userMapper.insert(new User(3L, "wangwu", "wangwu@example.com"));

        // 更新
        userMapper.updateEmail(1L, "new_email@example.com");

        // 删除
        userMapper.deleteById(2L);
    }
}

八、参数校验注解(JSR-303)

package com.example.annotation.validation;

import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * JSR-303 Bean Validation注解
 */

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface NotEmpty {
    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 Email {
    String message() default "邮箱格式不正确";
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Pattern {
    String regexp();
    String message() default "格式不匹配";
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Min {
    long value();
    String message() default "值太小";
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Max {
    long value();
    String message() default "值太大";
}

/**
 * 用户注册DTO
 */
class UserRegisterDTO {

    @NotNull(message = "用户名不能为空")
    @NotEmpty(message = "用户名不能为空字符串")
    @Size(min = 3, max = 20, message = "用户名长度必须在3-20之间")
    @Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "用户名只能包含字母数字下划线")
    private String username;

    @NotNull(message = "密码不能为空")
    @Size(min = 6, max = 20, message = "密码长度必须在6-20之间")
    private String password;

    @NotNull(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    private String email;

    @NotNull(message = "年龄不能为空")
    @Min(value = 18, message = "年龄必须大于等于18")
    @Max(value = 100, message = "年龄必须小于等于100")
    private Integer age;

    public UserRegisterDTO(String username, String password, String email, Integer age) {
        this.username = username;
        this.password = password;
        this.email = email;
        this.age = age;
    }

    // Getters
    public String getUsername() { return username; }
    public String getPassword() { return password; }
    public String getEmail() { return email; }
    public Integer getAge() { return age; }
}

/**
 * 校验结果
 */
class ValidationResult {
    private boolean success;
    private List<String> errors = new ArrayList<>();

    public boolean isSuccess() { return success; }
    public void setSuccess(boolean success) { this.success = success; }
    public List<String> getErrors() { return errors; }
    public void addError(String error) { this.errors.add(error); }
}

/**
 * 简化版参数校验器
 */
class Validator {

    public static ValidationResult validate(Object obj) throws Exception {

        ValidationResult result = new ValidationResult();
        result.setSuccess(true);

        Field[] fields = obj.getClass().getDeclaredFields();

        for (Field field : fields) {
            field.setAccessible(true);
            Object value = field.get(obj);

            // @NotNull校验
            if (field.isAnnotationPresent(NotNull.class)) {
                if (value == null) {
                    result.setSuccess(false);
                    result.addError(field.getAnnotation(NotNull.class).message());
                    continue;
                }
            }

            // @NotEmpty校验
            if (field.isAnnotationPresent(NotEmpty.class)) {
                if (value instanceof String && ((String) value).isEmpty()) {
                    result.setSuccess(false);
                    result.addError(field.getAnnotation(NotEmpty.class).message());
                    continue;
                }
            }

            // @Size校验
            if (field.isAnnotationPresent(Size.class) && value instanceof String) {
                Size size = field.getAnnotation(Size.class);
                int len = ((String) value).length();
                if (len < size.min() || len > size.max()) {
                    result.setSuccess(false);
                    result.addError(size.message());
                }
            }

            // @Email校验
            if (field.isAnnotationPresent(Email.class) && value instanceof String) {
                String email = (String) value;
                if (!email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$")) {
                    result.setSuccess(false);
                    result.addError(field.getAnnotation(Email.class).message());
                }
            }

            // @Pattern校验
            if (field.isAnnotationPresent(Pattern.class) && value instanceof String) {
                Pattern pattern = field.getAnnotation(Pattern.class);
                if (!((String) value).matches(pattern.regexp())) {
                    result.setSuccess(false);
                    result.addError(pattern.message());
                }
            }

            // @Min校验
            if (field.isAnnotationPresent(Min.class) && value instanceof Number) {
                Min min = field.getAnnotation(Min.class);
                if (((Number) value).longValue() < min.value()) {
                    result.setSuccess(false);
                    result.addError(min.message());
                }
            }

            // @Max校验
            if (field.isAnnotationPresent(Max.class) && value instanceof Number) {
                Max max = field.getAnnotation(Max.class);
                if (((Number) value).longValue() > max.value()) {
                    result.setSuccess(false);
                    result.addError(max.message());
                }
            }
        }

        return result;
    }
}

/**
 * 测试参数校验
 */
class ValidationDemo {

    public static void main(String[] args) throws Exception {

        System.out.println("=== 测试1: 正确的数据 ===");
        UserRegisterDTO validUser = new UserRegisterDTO(
            "zhangsan", "pass123456", "zhangsan@example.com", 25);
        testValidation(validUser);

        System.out.println("\n=== 测试2: 用户名太短 ===");
        UserRegisterDTO shortUsername = new UserRegisterDTO(
            "ab", "pass123456", "zhangsan@example.com", 25);
        testValidation(shortUsername);

        System.out.println("\n=== 测试3: 邮箱格式错误 ===");
        UserRegisterDTO invalidEmail = new UserRegisterDTO(
            "zhangsan", "pass123456", "invalid-email", 25);
        testValidation(invalidEmail);

        System.out.println("\n=== 测试4: 年龄不满足 ===");
        UserRegisterDTO youngAge = new UserRegisterDTO(
            "zhangsan", "pass123456", "zhangsan@example.com", 16);
        testValidation(youngAge);

        System.out.println("\n=== 测试5: 多个错误 ===");
        UserRegisterDTO multiErrors = new UserRegisterDTO(
            "ab", "123", "bad", 10);
        testValidation(multiErrors);
    }

    private static void testValidation(UserRegisterDTO dto) throws Exception {
        ValidationResult result = Validator.validate(dto);

        if (result.isSuccess()) {
            System.out.println("✓ 校验通过");
        } else {
            System.out.println("✗ 校验失败:");
            for (String error : result.getErrors()) {
                System.out.println("  - " + error);
            }
        }
    }
}

九、注解实战:自定义权限校验

package com.example.annotation.security;

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

/**
 * 实战案例:基于注解的权限校验系统
 */

// === 权限注解 ===

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequiresPermission {
    String[] value(); // 需要的权限
    Logical logical() default Logical.AND; // 逻辑关系
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequiresRole {
    String[] value(); // 需要的角色
    Logical logical() default Logical.AND;
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequiresLogin {
}

enum Logical {
    AND, // 所有权限都需要
    OR   // 只需要其中一个权限
}

/**
 * 用户信息
 */
class UserContext {
    private String username;
    private String[] roles;
    private String[] permissions;

    public UserContext(String username, String[] roles, String[] permissions) {
        this.username = username;
        this.roles = roles;
        this.permissions = permissions;
    }

    public String getUsername() { return username; }
    public String[] getRoles() { return roles; }
    public String[] getPermissions() { return permissions; }

    public boolean hasRole(String role) {
        if (roles == null) return false;
        for (String r : roles) {
            if (r.equals(role)) return true;
        }
        return false;
    }

    public boolean hasPermission(String permission) {
        if (permissions == null) return false;
        for (String p : permissions) {
            if (p.equals(permission)) return true;
        }
        return false;
    }
}

/**
 * 当前用户上下文(ThreadLocal)
 */
class SecurityContext {
    private static ThreadLocal<UserContext> context = new ThreadLocal<>();

    public static void setUser(UserContext user) {
        context.set(user);
    }

    public static UserContext getUser() {
        return context.get();
    }

    public static void clear() {
        context.remove();
    }
}

/**
 * 权限校验器
 */
class PermissionChecker {

    /**
     * 检查方法权限
     */
    public static boolean check(Method method) {

        UserContext user = SecurityContext.getUser();

        // 1. 检查登录
        if (method.isAnnotationPresent(RequiresLogin.class)) {
            if (user == null) {
                System.out.println("[权限拒绝] 未登录");
                return false;
            }
        }

        // 2. 检查角色
        if (method.isAnnotationPresent(RequiresRole.class)) {
            RequiresRole requiresRole = method.getAnnotation(RequiresRole.class);
            if (!checkRole(user, requiresRole)) {
                System.out.println("[权限拒绝] 缺少角色: " +
                    java.util.Arrays.toString(requiresRole.value()));
                return false;
            }
        }

        // 3. 检查权限
        if (method.isAnnotationPresent(RequiresPermission.class)) {
            RequiresPermission requiresPermission = method.getAnnotation(RequiresPermission.class);
            if (!checkPermission(user, requiresPermission)) {
                System.out.println("[权限拒绝] 缺少权限: " +
                    java.util.Arrays.toString(requiresPermission.value()));
                return false;
            }
        }

        return true;
    }

    private static boolean checkRole(UserContext user, RequiresRole requiresRole) {
        if (user == null) return false;

        String[] requiredRoles = requiresRole.value();
        Logical logical = requiresRole.logical();

        if (logical == Logical.AND) {
            // 需要所有角色
            for (String role : requiredRoles) {
                if (!user.hasRole(role)) {
                    return false;
                }
            }
            return true;
        } else {
            // 只需要其中一个角色
            for (String role : requiredRoles) {
                if (user.hasRole(role)) {
                    return true;
                }
            }
            return false;
        }
    }

    private static boolean checkPermission(UserContext user, RequiresPermission requiresPermission) {
        if (user == null) return false;

        String[] requiredPermissions = requiresPermission.value();
        Logical logical = requiresPermission.logical();

        if (logical == Logical.AND) {
            for (String permission : requiredPermissions) {
                if (!user.hasPermission(permission)) {
                    return false;
                }
            }
            return true;
        } else {
            for (String permission : requiredPermissions) {
                if (user.hasPermission(permission)) {
                    return true;
                }
            }
            return false;
        }
    }
}

/**
 * 业务服务(带权限控制)
 */
class AdminService {

    @RequiresLogin
    public void viewProfile() {
        System.out.println("  [执行] 查看个人资料");
    }

    @RequiresRole("ADMIN")
    public void manageUsers() {
        System.out.println("  [执行] 管理用户");
    }

    @RequiresPermission({"user:create", "user:update"})
    public void createAndUpdateUser() {
        System.out.println("  [执行] 创建并更新用户");
    }

    @RequiresPermission(value = {"user:delete", "user:ban"}, logical = Logical.OR)
    public void removeUser() {
        System.out.println("  [执行] 移除用户");
    }

    @RequiresRole("ADMIN")
    @RequiresPermission("system:config")
    public void modifySystemConfig() {
        System.out.println("  [执行] 修改系统配置");
    }
}

/**
 * 方法拦截器(AOP)
 */
class SecurityInterceptor {

    public static Object invoke(Object target, String methodName) throws Exception {

        Method method = target.getClass().getMethod(methodName);

        System.out.println("\n[拦截器] 调用方法: " + methodName);

        // 权限检查
        if (!PermissionChecker.check(method)) {
            throw new RuntimeException("权限不足");
        }

        System.out.println("[权限通过]");

        // 执行方法
        return method.invoke(target);
    }
}

/**
 * 测试权限系统
 */
class SecurityAnnotationDemo {

    public static void main(String[] args) {

        AdminService service = new AdminService();

        // === 场景1: 未登录用户 ===
        System.out.println("=== 场景1: 未登录用户 ===");
        SecurityContext.clear();
        testInvoke(service, "viewProfile");

        // === 场景2: 普通用户 ===
        System.out.println("\n=== 场景2: 普通用户 ===");
        UserContext normalUser = new UserContext(
            "zhangsan",
            new String[]{"USER"},
            new String[]{"user:view"}
        );
        SecurityContext.setUser(normalUser);
        testInvoke(service, "viewProfile");
        testInvoke(service, "manageUsers");

        // === 场景3: 管理员(有角色无权限) ===
        System.out.println("\n=== 场景3: 管理员(有角色无权限) ===");
        UserContext adminNoPermission = new UserContext(
            "admin1",
            new String[]{"ADMIN"},
            new String[]{}
        );
        SecurityContext.setUser(adminNoPermission);
        testInvoke(service, "manageUsers");
        testInvoke(service, "modifySystemConfig");

        // === 场景4: 超级管理员(有所有权限) ===
        System.out.println("\n=== 场景4: 超级管理员 ===");
        UserContext superAdmin = new UserContext(
            "superadmin",
            new String[]{"ADMIN", "SUPER_ADMIN"},
            new String[]{"user:create", "user:update", "user:delete", "system:config"}
        );
        SecurityContext.setUser(superAdmin);
        testInvoke(service, "createAndUpdateUser");
        testInvoke(service, "modifySystemConfig");

        // === 场景5: OR逻辑(只需一个权限) ===
        System.out.println("\n=== 场景5: OR逻辑测试 ===");
        UserContext partialPermission = new UserContext(
            "user1",
            new String[]{"USER"},
            new String[]{"user:delete"} // 只有delete权限
        );
        SecurityContext.setUser(partialPermission);
        testInvoke(service, "removeUser"); // OR逻辑,应该通过
    }

    private static void testInvoke(Object service, String methodName) {
        try {
            SecurityInterceptor.invoke(service, methodName);
        } catch (Exception e) {
            System.out.println("  [失败] " + e.getMessage());
        }
    }
}

十、注解最佳实践

10.1 注解设计原则

package com.example.annotation.best;

import java.lang.annotation.*;

/**
 * 注解设计最佳实践
 */
public class AnnotationBestPractices {

    // ✓ 好的设计: 语义清晰,命名规范
    @interface Service {
        String value() default "";
    }

    // ✓ 好的设计: 提供合理的默认值
    @interface CacheConfig {
        int ttl() default 3600; // 默认1小时
        String key() default "";
        boolean enabled() default true;
    }

    // ✓ 好的设计: 使用枚举限制取值
    @interface Transaction {
        Propagation propagation() default Propagation.REQUIRED;
        Isolation isolation() default Isolation.DEFAULT;
    }

    enum Propagation { REQUIRED, REQUIRES_NEW, SUPPORTS }
    enum Isolation { DEFAULT, READ_COMMITTED, REPEATABLE_READ }

    // ✗ 不好的设计: 属性过多,难以使用
    @interface BadDesign {
        String value();
        String name();
        String description();
        String author();
        String version();
        String date();
        String category();
        int priority();
        boolean enabled();
        String[] tags();
        // ... 太多属性
    }

    // ✓ 好的设计: 拆分成多个注解
    @interface Metadata {
        String author();
        String version();
        String date();
    }

    @interface Config {
        String name();
        String description();
        boolean enabled() default true;
    }

    public static void printBestPractices() {
        System.out.println("=== 注解设计最佳实践 ===\n");

        System.out.println("1. 命名规范");
        System.out.println("   ✓ 使用清晰的名词或动词");
        System.out.println("   ✓ 遵循驼峰命名规则");
        System.out.println("   ✓ 避免缩写和歧义");

        System.out.println("\n2. 属性设计");
        System.out.println("   ✓ 提供合理的默认值");
        System.out.println("   ✓ 使用枚举限制取值范围");
        System.out.println("   ✓ 属性不要过多(建议<5个)");
        System.out.println("   ✓ value属性用于最常用的配置");

        System.out.println("\n3. 元注解使用");
        System.out.println("   ✓ 明确指定@Retention");
        System.out.println("   ✓ 明确指定@Target");
        System.out.println("   ✓ 需要时添加@Documented");
        System.out.println("   ✓ 谨慎使用@Inherited");

        System.out.println("\n4. 性能考虑");
        System.out.println("   ✓ 缓存反射获取的注解信息");
        System.out.println("   ✓ 编译期处理优于运行期");
        System.out.println("   ✓ 避免过度使用注解");

        System.out.println("\n5. 文档和示例");
        System.out.println("   ✓ 添加详细的JavaDoc");
        System.out.println("   ✓ 提供使用示例");
        System.out.println("   ✓ 说明注解的作用时机");
    }

    public static void main(String[] args) {
        printBestPractices();
    }
}

10.2 注解使用场景总结

+---------------------------+---------------------------+
|        使用场景           |        典型注解           |
+---------------------------+---------------------------+
| 依赖注入                  | @Autowired, @Resource     |
| 事务管理                  | @Transactional            |
| AOP切面                   | @Aspect, @Before, @After  |
| Web请求映射               | @RequestMapping, @GetMapping |
| 参数校验                  | @NotNull, @Size, @Email   |
| ORM映射                   | @Entity, @Table, @Column  |
| 缓存管理                  | @Cacheable, @CacheEvict   |
| 异步处理                  | @Async                    |
| 定时任务                  | @Scheduled                |
| 权限控制                  | @PreAuthorize, @RolesAllowed |
| API文档                   | @ApiOperation, @ApiParam  |
| 序列化控制                | @JsonProperty, @JsonIgnore |
| 测试                      | @Test, @Before, @After    |
| 代码生成                  | @Data, @Builder (Lombok)  |
+---------------------------+---------------------------+

总结

核心知识点回顾

本文深入探讨了Java注解机制,主要内容包括:

  1. 注解基础

    • Java内置注解(@Override、@Deprecated等)
    • 元注解(@Retention、@Target、@Documented等)
    • 自定义注解语法与规范
  2. 注解处理

    • 运行时注解处理器(反射)
    • 编译期注解处理器(APT)
    • 注解的生命周期
  3. 框架应用

    • Spring框架的IoC、AOP、MVC注解
    • MyBatis的SQL映射注解
    • JSR-303参数校验注解
  4. 实战案例

    • Excel导出注解设计
    • 权限校验注解系统
    • 性能测试注解处理器

注解 vs 配置文件

维度注解XML配置文件
简洁性
耦合度高(侵入代码)低(外部配置)
维护性分散在代码中集中管理
类型安全编译期检查运行期检查
灵活性低(需重新编译)高(可动态修改)

学习建议

学习路径:
  内置注解 → 元注解 → 自定义注解 → 注解处理器 → 框架源码
     ↓         ↓         ↓           ↓            ↓
  基础语法  生命周期   实战案例    反射/APT    Spring/MyBatis

进阶方向:

  1. 深入研究Spring注解原理
  2. 学习APT开发(如Lombok源码)
  3. 掌握字节码增强技术
  4. 理解JSR规范(如JSR-303、JSR-250)