前言
在现代 Java 开发中,注解是我们开发中最常用的,在使用springboot进行开发的时候,都是面向注解式开发,内置了我们开发中常用的注解。有时候我们会想着自己去自定义下注解,在开发过程中看到别人写的项目中也常见自定义注解。这篇文章将介绍自定义注解的概念,并通过一个具体的案例展示其实际应用。
什么是自定义注解?
自定义注解就是开发者自己定义的一种“标签”,用来标记代码中的某些部分。通过这些标签,我们可以在程序运行的时候做一些特殊的处理,比如检查某个方法的执行时间、验证数据的正确性等。自定义注解可以帮助我们减少重复的代码,提高开发效率。主要的用途就在于当我们在处理一些重覆的操作的时候,我们可以通过自定义注解,根据需求对这些操作进行处理
元注解:
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
1.@Target,
2.@Retention,
3.@Documented,
4.@Inherited
这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应分参数的使用说明。
这些注解都是 Java 中用于定义自定义注解行为的元注解(Meta-Annotation),它们决定了自定义注解的适用范围、生命周期、是否包含在 Javadoc 中等。以下是每个元注解的详细解释:
1. @Target
@Target 用于指定自定义注解可以应用的程序元素类型。可以限制自定义注解只能用于类、方法、字段等特定的地方。其常用的取值包括:
- ElementType.TYPE:可以用在类、接口、枚举上。
- ElementType.FIELD:可以用在字段(包括枚举常量)上。
- ElementType.METHOD:可以用在方法上。
- ElementType.PARAMETER:可以用在方法参数上。
- ElementType.CONSTRUCTOR:可以用在构造函数上。
- ElementType.LOCAL_VARIABLE:可以用在局部变量上。
- ElementType.ANNOTATION_TYPE:可以用在注解类型上。
- ElementType.PACKAGE:可以用在包声明上。
@Target(ElementType.METHOD)
public @interface MyAnnotation {
// 注解属性
}
在这个例子中,MyAnnotation 注解只能用于方法。
2. @Retention
@Retention 用于指定自定义注解的保留策略,即该注解在生命周期中的哪个阶段被保留。取值包括:
- RetentionPolicy.SOURCE:注解只保留在源代码中,编译时被丢弃。
- RetentionPolicy.CLASS:注解保留在字节码文件中,但在运行时不可见。是默认值。
- RetentionPolicy.RUNTIME:注解在运行时保留,可以通过反射机制读取。这种方式最常用,适合需要在运行时处理的注解。
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
// 注解属性
}
在这个例子中,MyAnnotation 注解在运行时仍然有效,可以通过反射获取。
3. @Documented
@Documented 是一个标记注解(没有属性),表示使用这个注解的元素应当被 javadoc 或类似工具文档化。默认情况下,注解是不会被包括在 javadoc 中的,使用 @Documented 可以将其包含进去。
示例:
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Validate {
String message() default "This method needs validation";
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequirePermission {
/**
* 这个需要权限
*/
String value() default "USER"; // 权限名称
}
public class UserService {
@Validate(message = "User registration needs validation")
public void registerUser(String username, String password) {
// 用户注册逻辑
}
@RequirePermission("admin")
public void getByIdUser(Long id) {
}
}
4. @Inherited
@Inherited 是一个标记注解,表示这个注解可以被自动继承。具体来说,当某个类使用了带有 @Inherited 的注解时,如果该类的子类没有显式地声明该注解,那么子类将自动继承父类的该注解。
注意:
@Inherited 仅适用于类级别的注解,对方法、字段等无效。
继承的注解不会在子类中显示,但可以通过反射获取。
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
// 注解属性
}
@MyAnnotation
public class ParentClass {
}
public class ChildClass extends ParentClass {
}
自定义注解案例
使用自定义注解实现权限认证。该示例包括自定义注解、权限检查切面、控制器和简单的用户权限获取逻辑
1. 创建自定义注解
package com.yunzhi.studyAnnotaion.annotaion;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequirePermission {
String value(); // 权限名称
}
2. 创建权限检查切面
import com.yunzhi.studyAnnotaion.annotaion.RequirePermission;
import com.yunzhi.studyAnnotaion.exception.AccessDeniedException;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class PermissionAspect {
@Before("@annotation(requirePermission)")
public void checkPermission(RequirePermission requirePermission) {
String requiredPermission = requirePermission.value();
String userPermission = getCurrentUserPermission();
if (!hasPermission(userPermission, requiredPermission)) {
throw new AccessDeniedException("No permission to access this resource");
}
}
private String getCurrentUserPermission() {
return "USER";
}
private boolean hasPermission(String userPermission, String requiredPermission) {
return userPermission.equals(requiredPermission);
}
}
3. 创建控制器
package com.yunzhi.studyAnnotaion.controller;
import com.yunzhi.studyAnnotaion.annotaion.RequirePermission;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping("/admin")
@RequirePermission("ADMIN")
public String adminEndpoint() {
return "Welcome, admin!";
}
@GetMapping("/user")
@RequirePermission("USER")
public String userEndpoint() {
return "Welcome, user!";
}
}
测试和运行
访问 /api/user:具有USER权限的用户可以访问。
访问 /api/admin:只有具有ADMIN权限的用户可以访问。
到此我们就可以通过自定义注解实现一个简单的权限认证功能
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。