Java 注解(Annotations)深度笔记

一、注解基础概念

1. 注解的本质

  • 一种元数据形式,为代码提供附加信息
  • 不会直接影响代码逻辑,但可以被编译器或运行时环境使用
  • @符号开头,如@Override

2. 注解的作用

  • 编译检查:如@Override确保方法正确重写
  • 代码生成:如Lombok的@Data自动生成getter/setter
  • 运行时处理:如Spring的@Autowired依赖注入

二、元注解(Meta-Annotations)

元注解是指用来注解其他注解的注解,Java提供了5种标准元注解:

1. @Retention - 定义注解的生命周期

保留策略作用范围典型应用场景
RetentionPolicy.SOURCE仅保留在源码阶段@Override, @SuppressWarnings
RetentionPolicy.CLASS保留到class文件但JVM不加载字节码处理工具使用
RetentionPolicy.RUNTIME运行时可通过反射获取Spring框架注解, JPA注解
1
2
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRuntimeAnnotation {}

2. @Target - 指定注解可以应用的位置

目标类型(ElementType)可应用位置
TYPE类、接口、枚举
FIELD字段(包括枚举常量)
METHOD方法
PARAMETER方法参数
CONSTRUCTOR构造函数
LOCAL_VARIABLE局部变量
ANNOTATION_TYPE注解类型
PACKAGE包声明
TYPE_PARAMETER类型参数(Java 8+)
TYPE_USE类型使用处(Java 8+)
1
2
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface MyMethodAndClassAnnotation {}

3. @Documented - 控制是否出现在Javadoc中

1
2
@Documented
public @interface MyDocumentedAnnotation {}

4. @Inherited - 允许子类继承父类的注解

1
2
3
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyInheritedAnnotation {}

5. @Repeatable (Java 8+) - 允许重复使用同一注解

1
2
3
4
5
6
7
8
9
10
11
12
13
@Repeatable(Authorities.class)
public @interface Authority {
String value();
}

public @interface Authorities {
Authority[] value();
}

// 使用
@Authority("admin")
@Authority("user")
public class MyService {}

三、自定义注解开发

1. 基本语法

1
2
3
4
public @interface 注解名称 {
// 注解元素
元素类型 元素名称() default 默认值;
}

2. 注解元素类型限制

  • 基本数据类型(int, float, boolean等)
  • String
  • Class
  • 枚举
  • 其他注解
  • 以上类型的数组

3. 完整自定义注解示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 用户权限验证注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auth {
// 必需的角色
String[] roles() default {};

// 权限等级(默认0)
int level() default 0;

// 错误提示信息
String message() default "无访问权限";
}

4. 使用自定义注解

1
2
3
4
5
6
public class UserService {
@Auth(roles = {"admin", "superuser"}, level = 2)
public void deleteUser(String userId) {
// 方法实现
}
}

四、注解的运行时处理

1. 反射API获取注解

1
2
3
4
5
6
7
Method method = UserService.class.getMethod("deleteUser", String.class);
Auth authAnnotation = method.getAnnotation(Auth.class);

if (authAnnotation != null) {
System.out.println("所需角色: " + Arrays.toString(authAnnotation.roles()));
System.out.println("权限等级: " + authAnnotation.level());
}

2. Spring风格的注解处理器示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {

HandlerMethod handlerMethod = (HandlerMethod) handler;
Auth auth = handlerMethod.getMethodAnnotation(Auth.class);

if (auth != null) {
// 实际权限验证逻辑
if (!checkAuth(request, auth.roles(), auth.level())) {
throw new AuthException(auth.message());
}
}
return true;
}

private boolean checkAuth(HttpServletRequest request,
String[] requiredRoles,
int requiredLevel) {
// 实现验证逻辑
return true;
}
}

五、高级特性

1. 注解与泛型结合

1
2
3
4
5
6
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
public @interface NotNull {}

// 使用
List<@NotNull String> names = new ArrayList<>();

2. 注解处理器(编译时处理)

通过实现AbstractProcessor创建注解处理器:

1
2
3
4
5
6
7
8
9
10
@SupportedAnnotationTypes("com.example.MyAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_11)
public class MyAnnotationProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
// 处理注解逻辑
return true;
}
}

六、常见框架注解对比

注解类型Java标准Spring框架JPA/Hibernate
类级别@Deprecated@Component@Entity
字段级别@SuppressWarnings@Autowired@Column
方法级别@Override@RequestMapping@Transient
参数级别-@RequestParam@Param

七、最佳实践

  1. 命名规范

    • 注解名称应明确表达其用途
    • 使用名词或形容词(如@Nullable, @Test
  2. 文档说明

    • 使用JavaDoc说明注解用途
    • 标注是否线程安全
  3. 性能考虑

    • 运行时注解会增加反射开销
    • 频繁调用的代码避免过多注解检查
  4. 组合注解

    • Spring风格的元注解组合
      1
      2
      3
      4
      @RestController
      @RequestMapping("/api/v1")
      @ResponseBody
      public @interface ApiV1Controller {}
  5. 验证注解

    • 结合Bean Validation使用
      1
      2
      3
      4
      5
      6
      7
      8
      @Retention(RetentionPolicy.RUNTIME)
      @Target(ElementType.FIELD)
      @Constraint(validatedBy = PhoneValidator.class)
      public @interface ValidPhone {
      String message() default "Invalid phone number";
      Class<?>[] groups() default {};
      Class<? extends Payload>[] payload() default {};
      }

通过合理使用注解,可以极大提高代码的可读性和可维护性,同时减少样板代码。在Spring等现代框架中,注解已成为核心编程范式之一。