自定义注解详解
1. 定义自定义注解
自定义注解通过@interface
关键字定义,需结合元注解(如@Target
、@Retention
)控制其行为。
语法模板
@Retention(RetentionPolicy.RUNTIME) // 注解保留到运行时
@Target(ElementType.METHOD) // 注解用于方法
public @interface MyAnnotation {
// 注解属性(类似无参方法)
String value() default "默认值"; // 默认值可选
int priority() default 1;
Class<?> targetClass() default Object.class;
}
核心元注解说明
@Retention
:RetentionPolicy.SOURCE
:仅保留在源码中(如Lombok的@Getter
)。RetentionPolicy.CLASS
:保留到字节码文件,但运行时不可见(默认)。RetentionPolicy.RUNTIME
:运行时可通过反射读取(如Spring的@Autowired
)。
@Target
:
指定注解可应用的位置,支持多个目标(用数组表示):@Target({ElementType.METHOD, ElementType.FIELD})
@Documented
:
注解信息包含在Javadoc中。@Inherited
:
允许子类继承父类上的注解(仅对类注解有效)。
2. 注解属性规则
类型限制:
属性类型只能是基本类型、String、Class、枚举、其他注解或这些类型的数组。 不能是Object类型。// 合法属性 int id(); String[] tags(); Class<?> target(); RetentionPolicy policy(); // 枚举类型
默认值:
通过default
关键字指定,未指定默认值的属性在使用时必须显式赋值。String value() default "unknown";
单值属性:
若属性名为value
且是唯一需要赋值的属性,可省略属性名:@MyAnnotation("直接赋值value")
3. 使用自定义注解
示例:标记需要权限验证的方法
// 定义权限注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiresPermission {
String[] roles(); // 必须显式赋值
String description() default "";
}
// 使用注解
public class UserService {
@RequiresPermission(roles = {"admin", "superuser"}, description = "删除用户权限")
public void deleteUser(String userId) {
// 删除用户逻辑
}
}
示例:标记API接口版本
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ApiVersion {
String value(); // 版本号,如"v1.2"
}
@ApiVersion("v1.0")
public class UserController {
// 控制器方法
}
4. 处理自定义注解
(1) 运行时反射处理
通过反射读取注解信息,动态执行逻辑(如权限校验、日志记录)。
示例:权限校验拦截器
public class PermissionInterceptor {
public static void checkPermission(Method method) {
if (method.isAnnotationPresent(RequiresPermission.class)) {
RequiresPermission annotation = method.getAnnotation(RequiresPermission.class);
String[] requiredRoles = annotation.roles();
String currentRole = getCurrentUserRole(); // 模拟获取当前用户角色
boolean hasPermission = false;
for (String role : requiredRoles) {
if (role.equals(currentRole)) {
hasPermission = true;
break;
}
}
if (!hasPermission) {
throw new SecurityException("权限不足: 需要角色 " + Arrays.toString(requiredRoles));
}
}
}
private static String getCurrentUserRole() {
return "user"; // 模拟返回当前用户角色
}
}
// 测试代码
public class Main {
public static void main(String[] args) throws NoSuchMethodException {
Method deleteMethod = UserService.class.getMethod("deleteUser", String.class);
PermissionInterceptor.checkPermission(deleteMethod); // 抛出SecurityException
}
}
(2) 编译时注解处理器(APT)
通过继承AbstractProcessor
生成额外代码(如Lombok)。
示例:生成Getter方法(简化版)
@SupportedAnnotationTypes("com.example.Getter")
@SupportedSourceVersion(SourceVersion.RELEASE_11)
public class GetterProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement annotation : annotations) {
for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {
// 生成Getter方法代码(具体实现略)
System.out.println("为字段生成Getter: " + element.getSimpleName());
}
}
return true;
}
}
5. 实际应用场景
场景 | 示例 |
---|---|
权限控制 | 方法级注解标记访问所需角色(如Spring Security的@PreAuthorize )。 |
日志切面 | 注解标记需要记录日志的方法(结合AOP实现)。 |
数据验证 | 字段注解定义校验规则(如Hibernate Validator的@NotNull )。 |
API文档生成 | 注解标记接口说明(如Swagger的@ApiOperation )。 |
依赖注入 | 自定义@Inject 注解实现简易IoC容器。 |
6. 高级特性
(1) 重复注解(Java 8+)
@Repeatable(Validations.class)
public @interface Validation {
String rule();
}
public @interface Validations {
Validation[] value();
}
// 使用
@Validation(rule = "notNull")
@Validation(rule = "maxLength:100")
public class User {}
(2) 类型注解(Java 8+)
public class Data {
List<@NonNull String> items; // 类型注解
}
7. 常见问题
- 注解属性必须赋值:
若未指定default
值,使用时必须显式赋值。 - 注解继承不生效:
@Inherited
仅对类注解有效,方法/字段注解默认不继承。 - 反射性能开销:
频繁反射读取注解可能影响性能,建议缓存结果。
总结
自定义注解是Java元编程的核心工具,通过合理设计注解,可以大幅提升代码的可维护性和框架的灵活性。掌握其定义、使用和处理方式,是进阶Java开发的必备技能!