Java注解深度解析:从原理到实战应用

管理员
> 注解(Annotation)是Java 5引入的元数据机制,它让程序能够为代码添加"标签",配合反射可以实现配置驱动、代码生成、运行时校验等强大功能。Spring Boot、MyBatis、JUnit等框架的核心都建立在注解之上。 ## 目录 1. [什么是注解](#什么是注解) 2. [内置注解详解](#内置注解详解) 3. [自定义注解](#自定义注解) 4. [元注解](#元注解) 5. [注解处理器](#注解处理器) 6. [反射读取注解](#反射读取注解) 7. [实战应用案例](#实战应用案例) 8. [注解最佳实践](#注解最佳实践) 9. [总结](#总结) --- ## 什么是注解 ### 定义 注解(Annotation)是一种**用于在代码中添加元数据的标记**,它不会直接影响代码的执行,但可以被编译器、注解处理器或运行时环境读取和使用。 ### 注解 vs 注释 vs XML配置 | 特性 | 注解 | 注释 | XML配置 | |-----|------|------|---------| | **编译期保留** | 可选(@Retention) | ❌ 不保留 | ✅ 保留 | | **运行时保留** | 可选 | ❌ 不保留 | ✅ 保留 | | **程序读取** | ✅ 支持 | ❌ 不支持 | ✅ 支持 | | **类型安全** | ✅ 强类型 | ❌ 无类型 | ❌ 弱类型 | | **IDE支持** | ✅ 强支持 | ✅ 基础支持 | ✅ 中等支持 | | **冗余度** | 低 | 中 | 高 | ### 注解的演进历程 ```java // Java 1.4:使用注释和XML /** * 这是一个Service类 */ public class UserService { public void login(String username, String password) { // ... } } // Java 5+:使用注解(配置零散) @Service public class UserService { public void login(String username, String password) { // ... } } // Java 8+:注解增强(可重复、类型注解) @Service @Transactional @RestController public class UserService { @GetMapping("/login") public Result<@Valid LoginRequest> login( @RequestBody LoginRequest request ) { // ... } } ``` --- ## 内置注解详解 ### 1. @Override **作用**:标识方法覆盖父类方法 ```java public class Animal { public void eat() { System.out.println("动物吃东西"); } } public class Dog extends Animal { @Override public void eat() { System.out.println("狗吃骨头"); } // ❌ 编译错误:未覆盖父类方法 // @Override // public void sleep() { // System.out.println("狗睡觉"); // } } ``` **编译期检查**: - 确保方法签名正确 - 防止拼写错误 - 提高代码可读性 ### 2. @Deprecated **作用**:标记已过时的方法或类 ```java public class UserService { /** * @deprecated 使用 {@link #loginV2(String, String)} 代替 * @see #loginV2(String, String) */ @Deprecated public void login(String username, String password) { System.out.println("登录方法已过时,请使用loginV2"); } /** * 新版登录方法 */ public void loginV2(String username, String password) { System.out.println("新版登录"); } } // 使用时会有警告 UserService userService = new UserService(); userService.login("admin", "123456"); // 警告:已过时 ``` ### 3. @SuppressWarnings **作用**:抑制编译器警告 ```java public class Example { @SuppressWarnings("unchecked") public void uncheckedCast() { List list = new ArrayList(); List strings = (List) list; // 未经检查的转换 } @SuppressWarnings({"rawtypes", "unchecked"}) public void multipleWarnings() { List list = new ArrayList(); // rawtypes警告 list.add("test"); } @SuppressWarnings("unused") private String unusedField = "test"; // 未使用的字段警告 } ``` **常用警告类型**: - `unchecked` - 未经检查的转换 - `rawtypes` - 使用原始类型 - `unused` - 未使用的变量/方法 - `deprecation` - 使用过时方法 - `null` - 空指针分析警告 ### 4. @SafeVarargs(Java 7+) **作用**:抑制堆污染警告 ```java public class Example { @SafeVarargs public static void printAll(T... items) { for (T item : items) { System.out.println(item); } } // 使用示例 public static void main(String[] args) { printAll("A", "B", "C"); printAll(1, 2, 3); } } ``` **注意**:只有在确保方法类型安全时才使用此注解 ### 5. @FunctionalInterface(Java 8+) **作用**:标识函数式接口 ```java @FunctionalInterface public interface Calculator { int calculate(int a, int b); // ✅ 可以有默认方法 default int add(int a, int b) { return a + b; } // ✅ 可以有Object的方法 @Override String toString(); // ❌ 编译错误:只能有一个抽象方法 // int multiply(int a, int b); } // 使用示例 Calculator calc = (a, b) -> a * b; ``` ### 6. @Native(Java 8+) **作用**:标识常量字段可能被本地代码引用 ```java public class System { @Native public static final int OUT = 0; @Native public static final int ERR = 1; @Native public static final int IN = 2; } ``` --- ## 自定义注解 ### 基本语法 ```java // 定义注解 public @interface MyAnnotation { } ``` ### 注解元素 ```java public @interface UserInfo { // String类型元素 String username(); // int类型元素 int age(); // 带默认值的元素 String role() default "user"; // 数组类型元素 String[] permissions() default {}; // 枚举类型元素 Gender gender() default Gender.MALE; // Class类型元素 Class handler() default Object.class; // 嵌套注解 ContactInfo contact() default @ContactInfo; } // 枚举 enum Gender { MALE, FEMALE } // 嵌套注解 @interface ContactInfo { String email() default ""; String phone() default ""; } ``` ### 注解元素类型限制 ```java public @interface ValidAnnotation { // ✅ 基本类型 int intValue(); boolean booleanValue(); double doubleValue(); char charValue(); long longValue(); short shortValue(); byte byteValue(); // ✅ String String stringValue(); // ✅ Class Class classValue(); // ✅ 枚举 MyEnum enumValue(); // ✅ 注解 NestedAnnotation annotationValue(); // ✅ 数组(以上类型的数组) String[] arrayValue(); int[] intArrayValue(); // ❌ 不支持的类型 // List listValue(); // 编译错误 // Map mapValue(); // 编译错误 // Object objectValue(); // 编译错误 } ``` ### 使用自定义注解 ```java @UserInfo( username = "admin", age = 30, role = "admin", permissions = {"read", "write", "delete"}, gender = Gender.MALE, handler = AdminHandler.class, contact = @ContactInfo( email = "admin@example.com", phone = "13800138000" ) ) public class AdminUser { // ... } ``` --- ## 元注解 ### 1. @Target **作用**:指定注解的使用目标 ```java import java.lang.annotation.*; public @interface TargetDemo { // 应用于类、接口、枚举 @Target(ElementType.TYPE) @interface TypeAnnotation { } // 应用于字段 @Target(ElementType.FIELD) @interface FieldAnnotation { } // 应用于方法 @Target(ElementType.METHOD) @interface MethodAnnotation { } // 应用于参数 @Target(ElementType.PARAMETER) @interface ParameterAnnotation { } // 应用于构造器 @Target(ElementType.CONSTRUCTOR) @interface ConstructorAnnotation { } // 应用于局部变量 @Target(ElementType.LOCAL_VARIABLE) @interface LocalVariableAnnotation { } // 应用于注解类型 @Target(ElementType.ANNOTATION_TYPE) @interface MetaAnnotation { } // 应用于包 @Target(ElementType.PACKAGE) @interface PackageAnnotation { } // 应用于类型参数(Java 8+) @Target(ElementType.TYPE_PARAMETER) @interface TypeParameterAnnotation { } // 应用于类型使用(Java 8+) @Target(ElementType.TYPE_USE) @interface TypeUseAnnotation { } // 应用于模块(Java 9+) @Target(ElementType.MODULE) @interface ModuleAnnotation { } } ``` **多个目标**: ```java @Target({ElementType.TYPE, ElementType.METHOD}) @interface MultiTargetAnnotation { } ``` ### 2. @Retention **作用**:指定注解的保留策略 ```java public @interface RetentionDemo { // 源码级别保留(编译器使用,不进入class文件) @Retention(RetentionPolicy.SOURCE) @interface SourceLevelAnnotation { } // 类级别保留(编译进class文件,JVM不保留) @Retention(RetentionPolicy.CLASS) @interface ClassLevelAnnotation { } // 运行时级别保留(编译进class文件,JVM保留,可通过反射读取) @Retention(RetentionPolicy.RUNTIME) @interface RuntimeLevelAnnotation { } } ``` **保留策略对比**: | 保留策略 | 源码 | Class文件 | 运行时 | 反射读取 | 典型应用 | |---------|------|----------|--------|---------|---------| | SOURCE | ✅ | ❌ | ❌ | ❌ | Lombok、编译器检查 | | CLASS | ✅ | ✅ | ❌ | ❌ | 字节码增强工具 | | RUNTIME | ✅ | ✅ | ✅ | ✅ | Spring、JUnit | ### 3. @Documented **作用**:指定注解是否包含在JavaDoc中 ```java import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented // 会出现在JavaDoc中 public @interface DocumentedAnnotation { String value(); } public class Example { /** * 这个方法使用了@DocumentedAnnotation * @param name 参数名称 */ @DocumentedAnnotation("示例方法") public void method(String name) { // JavaDoc中会包含这个注解 } } ``` ### 4. @Inherited **作用**:指定注解是否可以被继承 ```java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Inherited // 允许子类继承 public @interface InheritedAnnotation { String value(); } @InheritedAnnotation("父类注解") public class Parent { // ... } public class Child extends Parent { // Child类会继承@InheritedAnnotation } // 测试 Class childClass = Child.class; InheritedAnnotation annotation = childClass.getAnnotation(InheritedAnnotation.class); System.out.println(annotation.value()); // 输出:父类注解 ``` **注意**: - 只对类继承有效,对接口实现无效 - 注解在接口上,实现类不会继承 - 子类覆盖父类方法时,方法上的注解不会继承 ### 5. @Repeatable(Java 8+) **作用**:允许注解在同一目标上重复使用 ```java import java.lang.annotation.*; // 容器注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Authors { Author[] value(); } // 可重复注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Repeatable(Authors.class) public @interface Author { String name(); String email(); } // 使用示例 @Author(name = "张三", email = "zhangsan@example.com") @Author(name = "李四", email = "lisi@example.com") @Author(name = "王五", email = "wangwu@example.com") public class Book { // ... } // 读取注解 public class Main { public static void main(String[] args) { // 方式1:直接获取重复注解 Author[] authors = Book.class.getAnnotationsByType(Author.class); for (Author author : authors) { System.out.println(author.name() + ": " + author.email()); } // 方式2:通过容器注解获取 Authors authorsAnnotation = Book.class.getAnnotation(Authors.class); for (Author author : authorsAnnotation.value()) { System.out.println(author.name() + ": " + author.email()); } } } ``` --- ## 注解处理器 ### 什么是注解处理器 注解处理器(Annotation Processor)是**在编译期处理注解的工具**,可以生成代码、检查错误、生成文档等。 ### 注解处理器工作流程 ``` 源代码(.java) ↓ 编译器解析 ↓ 识别注解 ↓ 调用注解处理器 ↓ 生成新代码 ↓ 重新编译 ↓ 生成class文件 ``` ### 实现注解处理器 ```java import javax.annotation.processing.*; import javax.lang.model.SourceVersion; import javax.lang.model.element.*; import javax.tools.Diagnostic; import java.util.Set; /** * 自定义注解处理器 */ @SupportedAnnotationTypes("com.example.Builder") // 支持的注解 @SupportedSourceVersion(SourceVersion.RELEASE_8) // 支持的Java版本 public class BuilderProcessor extends AbstractProcessor { @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { // 遍历所有使用@Builder注解的元素 for (TypeElement annotation : annotations) { Set annotatedElements = roundEnv.getElementsAnnotatedWith(annotation); for (Element element : annotatedElements) { if (element.getKind() == ElementKind.CLASS) { // 生成Builder代码 generateBuilderClass((TypeElement) element); } } } return true; // 已处理该注解 } private void generateBuilderClass(TypeElement classElement) { String className = classElement.getSimpleName().toString(); String builderClassName = className + "Builder"; // 这里可以生成Java代码文件 String builderCode = generateBuilderCode(className, builderClassName); // 写入文件 writeJavaFile(builderClassName, builderCode); } private String generateBuilderCode(String className, String builderClassName) { StringBuilder code = new StringBuilder(); code.append("public class ").append(builderClassName).append(" {\n"); code.append(" private ").append(className).append(" instance = new ") .append(className).append("();\n"); // 添加setter方法 // ... 生成setter代码 code.append(" public ").append(className).append(" build() {\n"); code.append(" return instance;\n"); code.append(" }\n"); code.append("}\n"); return code.toString(); } private void writeJavaFile(String className, String code) { // 使用JavaFileBuilder写入文件 processingEnv.getMessager().printMessage( Diagnostic.Kind.NOTE, "生成Builder类: " + className ); // ... } } ``` ### 注册注解处理器 **方式1:使用@ServiceProvider(Java 9之前)** 创建文件:`META-INF/services/javax.annotation.processing.Processor` ``` com.example.BuilderProcessor ``` **方式2:使用@AutoService(推荐)** ```java import com.google.auto.service.AutoService; @AutoService(Processor.class) @SupportedAnnotationTypes("com.example.Builder") @SupportedSourceVersion(SourceVersion.RELEASE_8) public class BuilderProcessor extends AbstractProcessor { // ... } ``` ### 使用注解处理器 **Maven配置**: ```xml org.apache.maven.plugins maven-compiler-plugin 3.8.1 com.example builder-processor 1.0.0 ``` ### 实战案例:简化版的Lombok @Data ```java // 注解定义 @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) public @interface Data { } // 注解处理器 @SupportedAnnotationTypes("com.example.Data") @SupportedSourceVersion(SourceVersion.RELEASE_8) public class DataProcessor extends AbstractProcessor { @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { for (TypeElement annotation : annotations) { for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) { if (element.getKind() == ElementKind.CLASS) { TypeElement classElement = (TypeElement) element; generateGettersAndSetters(classElement); } } } return true; } private void generateGettersAndSetters(TypeElement classElement) { String packageName = processingEnv.getElementUtils() .getPackageOf(classElement).getQualifiedName().toString(); String className = classElement.getSimpleName().toString(); // 生成getter和setter方法 // ... } } ``` --- ## 反射读取注解 ### 读取类注解 ```java // 定义注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Entity { String table() default ""; } // 使用注解 @Entity(table = "users") public class User { private Long id; private String username; } // 读取注解 public class AnnotationReader { public static void main(String[] args) { Class clazz = User.class; // 检查是否有注解 if (clazz.isAnnotationPresent(Entity.class)) { Entity entity = clazz.getAnnotation(Entity.class); System.out.println("表名: " + entity.table()); } // 获取所有注解 Annotation[] annotations = clazz.getAnnotations(); for (Annotation annotation : annotations) { System.out.println("注解: " + annotation.annotationType().getName()); } // 获取指定类型的注解(包括继承的) Entity entity = clazz.getAnnotation(Entity.class); System.out.println(entity); } } ``` ### 读取方法注解 ```java // 定义注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Transactional { boolean readOnly() default false; int timeout() default 30; } // 使用注解 public class UserService { @Transactional(timeout = 60) public void createUser(String username) { System.out.println("创建用户"); } @Transactional(readOnly = true) public User getUser(Long id) { return new User(); } } // 读取注解 public class MethodAnnotationReader { public static void main(String[] args) throws Exception { Class clazz = UserService.class; // 获取所有方法 Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { System.out.println("\n方法: " + method.getName()); // 检查是否有@Transactional注解 if (method.isAnnotationPresent(Transactional.class)) { Transactional transactional = method.getAnnotation(Transactional.class); System.out.println(" 是否只读: " + transactional.readOnly()); System.out.println(" 超时时间: " + transactional.timeout()); } } } } ``` ### 读取字段注解 ```java // 定义注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Column { String name() default ""; boolean nullable() default true; int length() default 255; } // 使用注解 public class User { @Column(name = "id", nullable = false) private Long id; @Column(name = "username", nullable = false, length = 50) private String username; @Column(name = "email", length = 100) private String email; } // 读取注解 public class FieldAnnotationReader { public static void main(String[] args) throws Exception { Class clazz = User.class; // 获取所有字段 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { System.out.println("\n字段: " + field.getName()); // 检查是否有@Column注解 if (field.isAnnotationPresent(Column.class)) { Column column = field.getAnnotation(Column.class); System.out.println(" 列名: " + column.name()); System.out.println(" 是否可空: " + column.nullable()); System.out.println(" 长度: " + column.length()); } } } } ``` ### 读取参数注解 ```java // 定义注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface Valid { String message() default "参数验证失败"; } // 使用注解 public class UserService { public void registerUser( @Valid(message = "用户名不能为空") String username, @Valid(message = "密码不能为空") String password, String email // 无注解 ) { System.out.println("注册用户"); } } // 读取注解 public class ParameterAnnotationReader { public static void main(String[] args) throws Exception { Class clazz = UserService.class; // 获取registerUser方法 Method method = clazz.getMethod("registerUser", String.class, String.class, String.class); // 获取方法参数 Parameter[] parameters = method.getParameters(); for (int i = 0; i < parameters.length; i++) { Parameter param = parameters[i]; System.out.println("\n参数 " + (i + 1) + ": " + param.getName()); // 检查是否有@Valid注解 if (param.isAnnotationPresent(Valid.class)) { Valid valid = param.getAnnotation(Valid.class); System.out.println(" 验证信息: " + valid.message()); } } } } ``` ### 综合示例:基于注解的ORM映射 ```java // 定义注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Table { String name(); } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Column { String name(); boolean primaryKey() default false; boolean autoIncrement() default false; } // 实体类 @Table(name = "users") public class User { @Column(name = "id", primaryKey = true, autoIncrement = true) private Long id; @Column(name = "username") private String username; @Column(name = "email") private String email; // getters and setters } // ORM工具类 public class OrmUtils { /** * 根据对象生成INSERT SQL */ public static String generateInsertSql(Object obj) { Class clazz = obj.getClass(); // 检查是否有@Table注解 if (!clazz.isAnnotationPresent(Table.class)) { throw new RuntimeException("类缺少@Table注解"); } Table table = clazz.getAnnotation(Table.class); String tableName = table.name(); // 收集字段信息 List columns = new ArrayList<>(); List values = new ArrayList<>(); for (Field field : clazz.getDeclaredFields()) { if (field.isAnnotationPresent(Column.class)) { Column column = field.getAnnotation(Column.class); // 跳过自增主键 if (column.autoIncrement()) { continue; } columns.add(column.name()); field.setAccessible(true); try { values.add(field.get(obj)); } catch (IllegalAccessException e) { throw new RuntimeException("读取字段失败", e); } } } // 生成SQL String sql = "INSERT INTO " + tableName + " (" + String.join(", ", columns) + ") VALUES (" + String.join(", ", Collections.nCopies(values.size(), "?")) + ")"; System.out.println("生成SQL: " + sql); System.out.println("参数: " + values); return sql; } } // 使用示例 public class OrmExample { public static void main(String[] args) { User user = new User(); user.setUsername("admin"); user.setEmail("admin@example.com"); String sql = OrmUtils.generateInsertSql(user); // 输出: INSERT INTO users (username, email) VALUES (?, ?) } } ``` --- ## 实战应用案例 ### 实战1:自定义注解实现依赖注入 ```java // 定义注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Autowired { } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Component { String value() default ""; } // Service实现 @Component public class UserService { public void login(String username, String password) { System.out.println("用户登录: " + username); } } // Controller使用注入 @Component public class UserController { @Autowired private UserService userService; public void handleLogin() { userService.login("admin", "123456"); } } // 简易IoC容器 public class SimpleIoCContainer { private final Map, Object> beans = new ConcurrentHashMap<>(); /** * 扫描包并创建Bean */ public void scan(String basePackage) { // 实际项目中使用反射扫描包 // 这里简化处理,手动注册 beans.put(UserService.class, new UserService()); } /** * 依赖注入 */ public void autowire(Object bean) { Class clazz = bean.getClass(); for (Field field : clazz.getDeclaredFields()) { if (field.isAnnotationPresent(Autowired.class)) { field.setAccessible(true); // 获取依赖的Bean Object dependency = beans.get(field.getType()); if (dependency == null) { throw new RuntimeException("依赖Bean不存在: " + field.getType()); } try { field.set(bean, dependency); System.out.println("注入依赖: " + field.getName()); } catch (IllegalAccessException e) { throw new RuntimeException("依赖注入失败", e); } } } } } // 使用示例 public class IocExample { public static void main(String[] args) { SimpleIoCContainer container = new SimpleIoCContainer(); container.scan("com.example"); UserController controller = new UserController(); container.autowire(controller); controller.handleLogin(); // 输出: 用户登录: admin } } ``` ### 实战2:自定义注解实现参数校验 ```java // 定义校验注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface NotNull { String message() default "字段不能为空"; } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Min { long value(); String message() default "值不能小于{value}"; } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Max { long value(); String message() default "值不能大于{value}"; } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Email { String message() default "邮箱格式不正确"; } // 校验异常 public class ValidationException extends RuntimeException { private final List errors; public ValidationException(List errors) { super("校验失败: " + String.join(", ", errors)); this.errors = errors; } public List getErrors() { return errors; } } // 校验器 public class Validator { public static void validate(Object obj) { List errors = new ArrayList<>(); Class clazz = obj.getClass(); for (Field field : clazz.getDeclaredFields()) { field.setAccessible(true); try { Object value = field.get(obj); // @NotNull校验 if (field.isAnnotationPresent(NotNull.class)) { NotNull notNull = field.getAnnotation(NotNull.class); if (value == null) { errors.add(field.getName() + ": " + notNull.message()); } } // @Min校验 if (field.isAnnotationPresent(Min.class) && value != null) { Min min = field.getAnnotation(Min.class); if (value instanceof Number && ((Number) value).longValue() < min.value()) { errors.add(field.getName() + ": " + min.message().replace("{value}", String.valueOf(min.value()))); } } // @Max校验 if (field.isAnnotationPresent(Max.class) && value != null) { Max max = field.getAnnotation(Max.class); if (value instanceof Number && ((Number) value).longValue() > max.value()) { errors.add(field.getName() + ": " + max.message().replace("{value}", String.valueOf(max.value()))); } } // @Email校验 if (field.isAnnotationPresent(Email.class) && value != null) { Email email = field.getAnnotation(Email.class); if (!isValidEmail(value.toString())) { errors.add(field.getName() + ": " + email.message()); } } } catch (IllegalAccessException e) { throw new RuntimeException("字段访问失败", e); } } if (!errors.isEmpty()) { throw new ValidationException(errors); } } private static boolean isValidEmail(String email) { return email.matches("^[A-Za-z0-9+_.-]+@(.+)$"); } } // 使用示例 public class User { @NotNull(message = "用户名不能为空") private String username; @Min(value = 18, message = "年龄不能小于18岁") @Max(value = 120, message = "年龄不能大于120岁") private Integer age; @Email(message = "邮箱格式不正确") private String email; // getters and setters } public class ValidationExample { public static void main(String[] args) { User user = new User(); user.setUsername("admin"); user.setAge(25); user.setEmail("admin@example.com"); try { Validator.validate(user); System.out.println("校验通过"); } catch (ValidationException e) { System.out.println("校验失败:"); e.getErrors().forEach(System.out::println); } } } ``` ### 实战3:自定义注解实现日志切面 ```java // 定义注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Log { String value() default ""; // 操作描述 String module() default ""; // 模块名称 } // 切面 public class LogAspect { /** * 创建代理对象 */ @SuppressWarnings("unchecked") public static T createProxy(T target) { return (T) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 检查方法是否有@Log注解 if (method.isAnnotationPresent(Log.class)) { return logExecution(target, method, args); } return method.invoke(target, args); } } ); } /** * 执行日志记录 */ private static Object logExecution(Object target, Method method, Object[] args) throws Exception { Log log = method.getAnnotation(Log.class); long startTime = System.currentTimeMillis(); // 前置通知 System.out.println("========================================"); System.out.println("[LOG] 开始执行"); System.out.println("[LOG] 模块: " + log.module()); System.out.println("[LOG] 操作: " + (log.value().isEmpty() ? method.getName() : log.value())); System.out.println("[LOG] 类: " + target.getClass().getSimpleName()); System.out.println("[LOG] 方法: " + method.getName()); System.out.println("[LOG] 参数: " + Arrays.toString(args)); try { // 执行目标方法 Object result = method.invoke(target, args); // 返回通知 long duration = System.currentTimeMillis() - startTime; System.out.println("[LOG] 执行成功"); System.out.println("[LOG] 返回值: " + result); System.out.println("[LOG] 耗时: " + duration + "ms"); System.out.println("========================================"); return result; } catch (InvocationTargetException e) { // 异常通知 long duration = System.currentTimeMillis() - startTime; System.out.println("[LOG] 执行失败"); System.out.println("[LOG] 异常: " + e.getTargetException().getMessage()); System.out.println("[LOG] 耗时: " + duration + "ms"); System.out.println("========================================"); throw e; } } } // 使用示例 public interface UserService { void createUser(String username, String email); String getUser(String username); } public class UserServiceImpl implements UserService { @Log(module = "用户管理", value = "创建用户") @Override public void createUser(String username, String email) { System.out.println("创建用户: " + username); // 模拟业务逻辑 } @Log(module = "用户管理", value = "查询用户") @Override public String getUser(String username) { System.out.println("查询用户: " + username); return "User: " + username; } } public class LogExample { public static void main(String[] args) { UserService userService = new UserServiceImpl(); UserService proxy = LogAspect.createProxy(userService); proxy.createUser("admin", "admin@example.com"); System.out.println(); proxy.getUser("admin"); } } ``` ### 实战4:自定义注解实现缓存 ```java // 定义注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Cacheable { String key() default ""; // 缓存key long timeout() default 60000; // 超时时间(毫秒) } // 缓存项 class CacheItem { private final Object value; private final long expireTime; public CacheItem(Object value, long timeout) { this.value = value; this.expireTime = System.currentTimeMillis() + timeout; } public Object getValue() { return value; } public boolean isExpired() { return System.currentTimeMillis() > expireTime; } } // 缓存管理器 public class CacheManager { private static final Map cache = new ConcurrentHashMap<>(); /** * 获取缓存 */ public static Object get(String key) { CacheItem item = cache.get(key); if (item == null) { return null; } if (item.isExpired()) { cache.remove(key); return null; } return item.getValue(); } /** * 设置缓存 */ public static void put(String key, Object value, long timeout) { cache.put(key, new CacheItem(value, timeout)); } /** * 清除缓存 */ public static void clear() { cache.clear(); } /** * 清除指定缓存 */ public static void evict(String key) { cache.remove(key); } } // 缓存切面 public class CacheAspect { @SuppressWarnings("unchecked") public static T createProxy(T target) { return (T) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 检查是否有@Cacheable注解 if (method.isAnnotationPresent(Cacheable.class)) { return cacheExecute(target, method, args); } return method.invoke(target, args); } } ); } private static Object cacheExecute(Object target, Method method, Object[] args) throws Exception { Cacheable cacheable = method.getAnnotation(Cacheable.class); String key = generateKey(cacheable.key(), method, args); // 检查缓存 Object cachedValue = CacheManager.get(key); if (cachedValue != null) { System.out.println("[CACHE] 命中缓存: " + key); return cachedValue; } // 执行方法 System.out.println("[CACHE] 未命中缓存,执行方法"); Object result = method.invoke(target, args); // 设置缓存 CacheManager.put(key, result, cacheable.timeout()); System.out.println("[CACHE] 设置缓存: " + key + ", 超时: " + cacheable.timeout() + "ms"); return result; } private static String generateKey(String keyPattern, Method method, Object[] args) { if (keyPattern.isEmpty()) { // 默认使用类名+方法名+参数 return method.getDeclaringClass().getSimpleName() + "." + method.getName() + Arrays.toString(args); } // 支持简单的占位符替换(实际项目可以使用SpEL) String key = keyPattern; for (int i = 0; i < args.length; i++) { key = key.replace("{" + i + "}", String.valueOf(args[i])); } return key; } } // 使用示例 public interface UserService { String getUser(String username); } public class UserServiceImpl implements UserService { @Cacheable(key = "user:{0}", timeout = 30000) @Override public String getUser(String username) { System.out.println("查询数据库: " + username); return "User: " + username; } } public class CacheExample { public static void main(String[] args) { UserService userService = new UserServiceImpl(); UserService proxy = CacheAspect.createProxy(userService); // 第一次调用,查询数据库 System.out.println(proxy.getUser("admin")); System.out.println(); // 第二次调用,命中缓存 System.out.println(proxy.getUser("admin")); System.out.println(); // 第三次调用,命中缓存 System.out.println(proxy.getUser("admin")); } } ``` ### 实战5:自定义注解实现权限控制 ```java // 定义注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface RequiresPermission { String value(); // 权限标识 } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface RequiresRole { String value(); // 角色标识 } // 权限异常 public class PermissionDeniedException extends RuntimeException { public PermissionDeniedException(String message) { super(message); } } // 用户上下文 public class UserContext { private static final ThreadLocal USER_HOLDER = new ThreadLocal<>(); public static void setUser(User user) { USER_HOLDER.set(user); } public static User getUser() { return USER_HOLDER.get(); } public static void clear() { USER_HOLDER.remove(); } } // 用户模型 public class User { private String username; private Set roles = new HashSet<>(); private Set permissions = new HashSet<>(); public User(String username) { this.username = username; } public boolean hasRole(String role) { return roles.contains(role); } public boolean hasPermission(String permission) { return permissions.contains(permission); } // getters and setters } // 权限切面 public class PermissionAspect { @SuppressWarnings("unchecked") public static T createProxy(T target) { return (T) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { checkPermission(method); return method.invoke(target, args); } } ); } private static void checkPermission(Method method) { User user = UserContext.getUser(); if (user == null) { throw new PermissionDeniedException("用户未登录"); } // 检查@RequiresRole if (method.isAnnotationPresent(RequiresRole.class)) { RequiresRole requiresRole = method.getAnnotation(RequiresRole.class); if (!user.hasRole(requiresRole.value())) { throw new PermissionDeniedException( "需要角色: " + requiresRole.value()); } } // 检查@RequiresPermission if (method.isAnnotationPresent(RequiresPermission.class)) { RequiresPermission requiresPermission = method.getAnnotation(RequiresPermission.class); if (!user.hasPermission(requiresPermission.value())) { throw new PermissionDeniedException( "需要权限: " + requiresPermission.value()); } } } } // 使用示例 public interface UserService { void deleteUser(String username); void exportData(); } public class UserServiceImpl implements UserService { @RequiresRole("admin") @Override public void deleteUser(String username) { System.out.println("删除用户: " + username); } @RequiresPermission("data:export") @Override public void exportData() { System.out.println("导出数据"); } } public class PermissionExample { public static void main(String[] args) { UserService userService = new UserServiceImpl(); UserService proxy = PermissionAspect.createProxy(userService); // 测试1:普通用户 User normalUser = new User("user1"); normalUser.getRoles().add("user"); normalUser.getPermissions().add("data:view"); UserContext.setUser(normalUser); try { proxy.deleteUser("user1"); } catch (PermissionDeniedException e) { System.out.println("权限拒绝: " + e.getMessage()); } // 测试2:管理员用户 User adminUser = new User("admin"); adminUser.getRoles().add("admin"); adminUser.getPermissions().add("data:export"); UserContext.setUser(adminUser); proxy.deleteUser("user1"); proxy.exportData(); UserContext.clear(); } } ``` --- ## 注解最佳实践 ### 1. 注解命名规范 ```java // ✅ 推荐:使用驼峰命名,首字母大写 public @interface Service { } public @interface Component { } public @interface Transactional { } // ❌ 避免:使用下划线或缩写 public @interface service { } public @interface Cmpnt { } ``` ### 2. 注解元素设计 ```java // ✅ 推荐:为元素提供默认值 public @interface Column { String name(); // 必填 boolean nullable() default true; // 可选,有默认值 int length() default 255; // 可选,有默认值 } // ❌ 避免:所有元素都必须指定值 public @interface BadColumn { String name(); boolean nullable(); // 用户每次都必须指定 int length(); // 用户每次都必须指定 } ``` ### 3. 注解保留策略选择 ```java // ✅ SOURCE:编译器检查,不进入class文件 @Retention(RetentionPolicy.SOURCE) public @interface Override { } // ✅ CLASS:字节码增强工具使用 @Retention(RetentionPolicy.CLASS) public @interface ClassAnnotation { } // ✅ RUNTIME:需要运行时读取(框架开发) @Retention(RetentionPolicy.RUNTIME) public @interface Service { } ``` ### 4. 注解组合使用 ```java // 定义组合注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Service { String value() default ""; } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface TransactionManagement { } // 组合注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Service @TransactionalManagement public @interface TransactionalService { String value() default ""; } // 使用组合注解 @TransactionalService("userService") public class UserServiceImpl implements UserService { // 相当于同时使用了@Service和@TransactionalManagement } ``` ### 5. 注解性能考虑 ```java // ✅ 推荐:缓存注解信息 public class AnnotationCache { private static final Map, Map> METHOD_CACHE = new ConcurrentHashMap<>(); public static Method getAnnotatedMethod(Class clazz, Class annotationType) { return METHOD_CACHE .computeIfAbsent(clazz, k -> cacheMethods(k, annotationType)) .values() .stream() .findFirst() .orElse(null); } private static Map cacheMethods(Class clazz, Class annotationType) { Map map = new HashMap<>(); for (Method method : clazz.getDeclaredMethods()) { if (method.isAnnotationPresent(annotationType)) { map.put(method.getName(), method); } } return map; } } // ❌ 避免:每次都通过反射获取注解 public class BadAnnotationUsage { public void process() { for (int i = 0; i < 10000; i++) { // 每次都反射获取注解,性能差 if (userService.getClass().isAnnotationPresent(Service.class)) { // ... } } } } ``` ### 6. 注解文档 ```java /** * 标识一个类为Service层组件 *

* 该注解标记的类会被Spring容器自动扫描并注册为Bean *

* * @see Component * @see Repository */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Service { /** * 指定Bean的名称 *

* 如果不指定,默认使用类名首字母小写 *

* * @return Bean名称 */ String value() default ""; } ``` --- ## 总结 ### 注解的核心价值 1. **声明式编程**:通过注解声明意图,减少代码 2. **元数据支持**:为代码提供额外的元数据信息 3. **编译期处理**:通过注解处理器生成代码、检查错误 4. **运行时反射**:配合反射实现动态功能 5. **框架基石**:Spring Boot、MyBatis、JUnit等框架的核心 ### 注解的发展历程 | 版本 | 特性 | 影响力 | |-----|------|--------| | Java 5 | 引入注解基础 | ⭐⭐⭐⭐⭐ | | Java 6 | 支持插件化注解处理器 | ⭐⭐⭐⭐ | | Java 7 | @SafeVarargs | ⭐⭐⭐ | | Java 8 | 类型注解、重复注解 | ⭐⭐⭐⭐⭐ | | Java 9+ | 模块系统对反射的限制 | ⭐⭐⭐⭐ | ### 注解 vs 反射 | 特性 | 注解 | 反射 | |-----|------|------| | **作用** | 声明元数据 | 读取和操作 | | **时机** | 编译期、运行时 | 运行时 | | **性能** | 高(编译期) | 低(运行时) | | **用途** | 配置、标记、说明 | 动态调用、检查 | ### 学习路线图 ``` 理解注解概念 ↓ 掌握内置注解 ↓ 学习元注解 ↓ 自定义注解 ↓ 反射读取注解 ↓ 注解处理器(编译期) ↓ 实战:依赖注入、参数校验、AOP ↓ 深入学习框架注解(Spring、MyBatis) ``` ### 常见框架注解速查 #### Spring Framework | 注解 | 用途 | |-----|------| | @Component | 通用组件 | | @Service | Service层 | | @Repository | DAO层 | | @Controller | Controller层 | | @Autowired | 自动装配 | | @Transactional | 事务管理 | | @RequestMapping | 请求映射 | | @RequestParam | 请求参数 | | @PathVariable | 路径变量 | | @RequestBody | 请求体 | | @ResponseBody | 响应体 | #### Spring Boot | 注解 | 用途 | |-----|------| | @SpringBootApplication | 应用主类 | | @Configuration | 配置类 | | @Bean | Bean定义 | | @Value | 配置注入 | | @ConditionalOnClass | 条件装配 | | @EnableAutoConfiguration | 自动配置 | #### MyBatis | 注解 | 用途 | |-----|------| | @Mapper | Mapper接口 | | @Select | 查询语句 | | @Insert | 插入语句 | | @Update | 更新语句 | | @Delete | 删除语句 | | @Results | 结果映射 | | @Param | 参数映射 | #### JUnit | 注解 | 用途 | |-----|------| | @Test | 测试方法 | | @Before | 前置方法 | | @After | 后置方法 | | @BeforeClass | 类前置方法 | | @AfterClass | 类后置方法 | | @Ignore | 忽略测试 | --- ## 参考资源 ### 官方文档 - [Java注解教程](https://docs.oracle.com/javase/tutorial/java/annotations/) - [注解处理器指南](https://docs.oracle.com/javase/8/docs/technotes/guides/apt/GettingStarted.html) ### 推荐书籍 - 《Java核心技术 卷I》- 注解章节 - 《Effective Java》- 第39条:注解优于命名模式 ### 开源项目 - Lombok - 编译期注解处理器 - Spring Framework - 注解驱动框架 - MapStruct - 注解驱动的映射器 - ButterKnife - Android视图绑定 ### 实战参考 - Spring Framework源码 - MyBatis源码 - Hibernate Validator源码 --- ## 互动环节 **思考题:** 1. 注解 vs XML配置,各有什么优缺点? 2. 为什么Spring Boot选择注解优先而非XML? 3. 如何设计一个注解处理器生成Builder类? **实战任务:** 1. 实现一个@NotNull注解的参数校验框架 2. 实现一个@Cache注解的缓存框架 3. 实现一个@Builder注解的代码生成器 --- **作者的话:** 注解是Java语言最优雅的特性之一,它让代码变得更加简洁、声明式、易于理解。从简单的@Override到复杂的Spring Boot自动配置,注解无处不在。掌握注解,不仅能让你写出更优雅的代码,更能让你深入理解现代Java框架的设计理念。 **欢迎关注我的博客,获取更多Java技术深度文章!**
评论 0

发表评论 取消回复

Shift+Enter 换行  ·  Enter 发送
还没有评论,来发表第一条吧