Java自定义注解揭秘:简单有效的权限认证实现
在现代 Java 开发中,注解是我们开发中最常用的,在使用 springboot 进行开发的时候,都是面向注解式开发,内置了我们开发中常用的注解。有时候我们会想着自己去自定义下注解,在开发过程中看到别人写的项目中也常见自定义注解。这篇文章将介绍自定义注解的概念,并通过一个具体的案例展示其实际应用。
什么是自定义注解?
自定义注解就是开发者自己定义的一种“标签”,用来标记代码中的某些部分。通过这些标签,我们可以在程序运行的时候做一些特殊的处理,比如检查某个方法的执行时间、验证数据的正确性等。自定义注解可以帮助我们减少重复的代码,提高开发效率。主要的用途就在于当我们在处理一些重覆的操作的时候,我们可以通过自定义注解,根据需求对这些操作进行处理
元注解
元注解的作用就是负责注解其他注解。Java5.0 定义了 4 个标准的 meta-annotation 类型,它们被用来提供对其它 annotation 类型作说明。Java5.0 定义的元注解:
- @Target,
- @Retention,
- @Documented,
- @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 权限的用户可以访问。
到此我们就可以通过自定义注解实现一个简单的权限认证功能
码云笔记 » Java自定义注解揭秘:简单有效的权限认证实现