Java 注解(Annotations)深度笔记
一、注解基础概念
1. 注解的本质
- 一种元数据形式,为代码提供附加信息
- 不会直接影响代码逻辑,但可以被编译器或运行时环境使用
- 以
@
符号开头,如@Override
2. 注解的作用
- 编译检查:如
@Override
确保方法正确重写 - 代码生成:如Lombok的
@Data
自动生成getter/setter - 运行时处理:如Spring的
@Autowired
依赖注入
元注解是指用来注解其他注解的注解,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 {}; 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 |
七、最佳实践
命名规范:
- 注解名称应明确表达其用途
- 使用名词或形容词(如
@Nullable
, @Test
)
文档说明:
性能考虑:
- 运行时注解会增加反射开销
- 频繁调用的代码避免过多注解检查
组合注解:
- Spring风格的元注解组合
1 2 3 4
| @RestController @RequestMapping("/api/v1") @ResponseBody public @interface ApiV1Controller {}
|
验证注解:
- 结合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等现代框架中,注解已成为核心编程范式之一。