Java 注解体系详解
Java 注解不仅是元数据,更是框架设计的核心机制。
一、注解基础
1.1 什么是注解
// 内置注解
@Override
public String toString() {
return "Hello";
}
@Deprecated
public void oldMethod() {}
@SuppressWarnings("unchecked")
public void genericMethod() {}
1.2 元注解
// @Target:注解作用目标
@Target(ElementType.METHOD) // 只能用于方法
@Target({ElementType.FIELD, ElementType.METHOD}) // 多个目标
// @Retention:保留策略
@Retention(RetentionPolicy.SOURCE) // 源码阶段丢弃
@Retention(RetentionPolicy.CLASS) // 类加载时丢弃(默认)
@Retention(RetentionPolicy.RUNTIME) // 运行时可用(反射)
// @Documented:是否包含在 Javadoc
@Documented
// @Inherited:是否可继承
@Inherited
二、自定义注解
2.1 定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogExecution {
// 属性定义
String value() default ""; // value 属性可省略名称
boolean logParams() default true;
boolean logResult() default false;
}
2.2 使用注解
public class UserService {
@LogExecution("创建用户")
public User createUser(String name) {
// ...
}
@LogExecution(value = "删除用户", logParams = false)
public void deleteUser(Long id) {
// ...
}
}
2.3 注解处理器
@SupportedAnnotationTypes("com.example.LogExecution")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class LogExecutionProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(LogExecution.class)) {
LogExecution annotation = element.getAnnotation(LogExecution.class);
String methodName = element.getSimpleName().toString();
// 生成代码或验证
processingEnv.getMessager().printMessage(
Diagnostic.Kind.NOTE,
"Found @LogExecution on method: " + methodName
);
}
return true;
}
}
三、运行时注解处理
3.1 反射读取注解
public class AnnotationReader {
public static void readAnnotations(Method method) {
if (method.isAnnotationPresent(LogExecution.class)) {
LogExecution annotation = method.getAnnotation(LogExecution.class);
System.out.println("Value: " + annotation.value());
System.out.println("LogParams: " + annotation.logParams());
}
}
}
3.2 AOP 实现
@Aspect
public class LoggingAspect {
@Around("@annotation(logExecution)")
public Object logExecution(ProceedingJoinPoint pjp,
LogExecution logExecution) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed();
long duration = System.currentTimeMillis() - start;
System.out.println(logExecution.value() +
" executed in " + duration + "ms");
return result;
}
}
四、APT(注解处理器)
4.1 编译时代码生成
@SupportedAnnotationTypes("com.example.Builder")
public class BuilderProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(Builder.class)) {
TypeElement typeElement = (TypeElement) element;
String className = typeElement.getQualifiedName().toString();
// 生成 Builder 类
generateBuilderClass(typeElement, className);
}
return true;
}
private void generateBuilderClass(TypeElement element, String className) {
// 使用 JavaPoet 生成代码
TypeSpec builder = TypeSpec.classBuilder(className + "Builder")
.addMethod(MethodSpec.methodBuilder("build")
.returns(ClassName.get(element))
.addCode("return new " + className + "();")
.build())
.build();
// 写入文件
// ...
}
}
4.2 Lombok 原理
// Lombok 注解
@Data
@AllArgsConstructor
public class User {
private Long id;
private String name;
}
// 编译后生成
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; }
// equals, hashCode, toString 等
}
五、最佳实践
5.1 注解设计原则
// ✅ 推荐:简洁明了
@Cacheable(ttl = 3600)
// ❌ 避免:过于复杂
@Cacheable(key = "#id",
condition = "#id != null && #id > 0",
unless = "#result == null",
sync = true,
cacheManager = "primaryCacheManager")
5.2 注解组合
// 创建组合注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Transactional
@Cacheable
@LogExecution
public @interface BusinessOperation {
String value() default "";
}
// 使用
@BusinessOperation("创建订单")
public Order createOrder(OrderRequest request) {
// ...
}
六、总结
注解核心要点:
| 特性 | 说明 | 应用场景 |
|---|---|---|
| 元注解 | 定义注解的注解 | 自定义注解 |
| 运行时注解 | 反射读取 | AOP、框架配置 |
| 编译时注解 | APT 处理 | 代码生成、验证 |
| 组合注解 | 多个注解组合 | 简化配置 |
注解是 Java 框架的基石,理解其原理有助于更好地使用 Spring、Lombok 等框架。