AOP的另类用法 (权限校验自定义注解)
👳我亲爱的各位大佬们好😘😘😘
♨️本篇文章记录的为 AOP的另类用法 (权限校验&&自定义注解) 相关内容,适合在学Java的小白,帮助新手快速上手,也适合复习中,面试中的大佬🙉🙉🙉。
♨️如果文章有什么需要改进的地方还请大佬不吝赐教❤️🧡💛
👨🔧 个人主页 : 阿千弟
🔥 上期内容👉👉👉 : “速通“ 老生常谈的HashMap [实现原理&&源码解读]
前言 :
告别了OOP编程, 迎来了一个新的AOP编程时代👍👍👍, 最近有同学问我AOP除了写日志还能干什么, 其实AOP能干的事情挺多的, 可能只是他们写的代码中暂时用不到. 其实如果当我们写一些简单的程序的时候, SpringSecurity完全用不到的时候, 就可以使用AOP与自定义注解来为角色的访问权限进行鉴定, 绝对比Security更轻量👉👉👉.

文章目录
- 前言 :
- 自定义注解
- AOP回顾
- 基本概念
- 声明一个切入点
- 切入点指示器(PCD)
- 基本通知
- 通知的参数
- AOP整合自定义注解校验接口权限
- 引入依赖
- 自定义注解
- 定义切面
- AopController
- 测试结果
自定义注解
我们在接触框架的时候经常会用到注解, 但是我们自己自定义注解的情况比较少, 一般都是配合切面编程使用
自定义一个注解非常简单, 它就和创建一个接口一样, 如果我们创建的是一个接口的话, 那么就用interface关键字表示, 如果我们是要自定义一个注解, 那么就在interface关键字前面加上一个@符号
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HasRole {String name() default "";String value() default "";
}
- 自定义注解里面还存在一些属性, 这些属性有点类似与我们的抽象方法, 是不能加方法体的, 加了是会报错的

- 自定义的属性是可以赋默认值的
// name的默认值是 ""
String name() default "";
-
它的返回类型必须是基础类型或者是String类型, 不可以是封装类型
-
@Target标志自定义的注解的作用范围
| 类型 | 作用范围 |
|---|---|
| TYPE | 允许被修饰的注解作用在类, 接口和枚举上 |
| FIELD | 允许作用在属性字段上 |
| METHOD | 允许作用在方法上 |
| PARAMETER | 允许作用在方法参数上 |
| CONSTRUCTOR | 允许作用在构造器上 |
| LOCAL_VARIABLE | 允许作用在本地局部变量上 |
| ANNOTATION_TYPE | 允许作用在注解上 |
| PACKAGE | 允许作用在包上 |
5. @Retention 标志自定义的作用是定义被它所注解的注解保留多久(生命周期)
一共有三种策略,定义在 RetentionPolicy 枚举中. 从注释上看:
| 类型 | 解释 |
|---|---|
| source | 注解只保留在源文件,当 Java 文件编译成 cláss 文件的时候,注解被遗弃;被编译器忽略 |
| class | 注解被保留到 class 文件,但 jvm 加载 class 文件时候被遗弃,这是默认的生命周期 |
| runtime | 注解不仅被保存到 class 文件中,jym 加载 class 文件之后,仍然存在 |
AOP回顾
基本概念
Aspect(切面): 一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。Join point(连接点 ): 在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。Advice(通知): 在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。 通知的类型将在后面部分进行讨论。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。Pointcut(切入点 ): 匹配连接点(Joinpoint)的断言。通知和一个【切入点表】达式关联,并在满足这个切入点的连接点上运行。 【切入点表达式如何和连接点匹配】是AOP的核心:Spring缺省使用AspectJ切入点语法。Introduction(引入): Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。Target object(目标对象):被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做 被通知(advised) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。AOP代理 AOP proxy: 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
8 .Weaving(织入): 把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象,这个过程叫织入。 这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。 Spring和其他纯Java AOP框架一样,在运行时完成织入。
声明一个切入点
【切入点确定感兴趣的连接点】,从而使我们能够控制通知何时运行。
切入点声明由两部分组成:包含【名称和方法签名】,以及确定我们感兴趣的方法执行的【切入点表达式】。
怎么确定一个方法:public void com.ddd.service.impl.*(…)
@Pointcut("execution(* transfer(..))") // the pointcut expression
private void anyOldTransfer() {} // the pointcut signature
切入点指示器(PCD)
这里只先回顾一下这两个常用的注解
@execution: (常用)用于匹配方法执行的连接点,这是在使用Spring AOP时使用的主要切入点指示符。(匹配方法)
| 模式 | 描述 |
|---|---|
| public * *(…) | 任何公共方法的执行 |
| cn.javass…IPointcutService.*() | cn.javass包及所有子包下IPointcutService接口中的任何无参方法 |
| cn.javass….*(…) | cn.javass包及所有子包下任何类的任何方法 |
| cn.javass…IPointcutService.(*) | cn.javass包及所有子包下IPointcutService接口的任何只有一个参数方法 |
| (!cn.javass…IPointcutService+).(…) | 非“cn.javass包及所有子包下IPointcutService接口及子类型”的任何方法 |
| cn.javass…IPointcutService+.() | cn.javass包及所有子包下IPointcutService接口及子类型的的任何无参方法 |
| cn.javass…IPointcut.test*(java.util.Date) | cn.javass包及所有子包下IPointcut前缀类型的的以test开头的只有一个参数类型为java.util.Date的方法,注意该匹配是根据方法签名的参数类型进行匹配的,而不是根据执行时传入的参数类型决定的.如定义方法:public void test(Object obj);即使执行时传入java.util.Date,也不会匹配的; |
@annotation: (常用)于匹配当前执行方法持有指定注解的方法。(方法上的注解)

基本通知
| 注解 | 说明 |
|---|---|
| @Before | 前置通知,在被切的方法执行前执行 |
| @After | 后置通知,在被切的方法执行后执行,比return更后 |
| @AfterRunning | 返回通知,在被切的方法return后执行 |
| @AfterThrowing | 异常通知,在被切的方法抛异常时执行 |
| @Around | 环绕通知,这是功能最强大的Advice,可以自定义执行顺序 |
通知的参数
任何通知方法都可以声明一个类型为【org.aspectj.lang.JoinPoint】的参数作为它的【第一个参数】(注意,around通知需要声明类型为( ProceedingJoinPoint )的第一个参数,它是【JoinPoint】的一个子类。 【JoinPoint】接口提供了许多有用的方法:
getArgs(): 返回方法参数。getThis(): 返回代理对象。getTarget(): 返回目标对象。getSignature(): 返回被通知的方法的签名。toString(): 打印被建议的方法的有用描述。

AOP整合自定义注解校验接口权限
在我们的业务开发中, 常常会遇到这样的问题 : 每当我们进行一个对数据库的操作, 通常需要鉴权用户是否具有一个正确的访问权限, 然而每次都对不同的业务流程中添加相同的鉴权的执行流程, 势必会造成代码的冗余, 而且也不利于后期代码的拓展
这时候我们可以对鉴权的业务进行切点织入, 织入切面, 化繁为简
引入依赖
pom.xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>29.0-jre</version></dependency>
自定义注解
这里先模拟一个缓存的类, 因为在真实业务交易权限的过程中我们一般都是把查出的用户数据放在缓存中, 以至于不用每次使用用户信息时都需要从数据库中查询
public class CacheManager {//保存用户和具有的角色之间对应关系public static final Map<String, Set<String>> USER_ROLE_MAP = new HashMap<>();static{//用户zhangsan具有user和admin两个角色Set<String> roleSet3 = Sets.newHashSet("admin","user");USER_ROLE_MAP.put("zhangsan",roleSet3);//用户lisi具有user一个角色Set<String> roleSet4 = Sets.newHashSet("user");USER_ROLE_MAP.put("lisi",roleSet4);}}
定义切面
【编写方法】声明一个切入点,该切入点在匹配连接点时“提供”‘Account’对象值,然后从通知中引用指定的切入点
@Component
@Aspect
public class AopConfig {//定义一个切点(通过注解)@Pointcut("@annotation(com.example.aopdemo.annotation.HasRole))")public void pointcut(){}//前置通知@Before("pointcut()")public void before(JoinPoint joinPoint){System.out.println("before-------------");//获取到HttpServletRequest,ThreadLocalRequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;HttpServletRequest request = servletRequestAttributes.getRequest();String username = request.getParameter("username");//获取当前用户的角色集合Set<String> userRoles = CacheManager.USER_ROLE_MAP.get(username);//获取当前请求的方法上的注解hasRole中设置的角色MethodSignature signature = (MethodSignature)joinPoint.getSignature();//反射获取当前被调用的方法Method method = signature.getMethod();//判断当前方法是否有hasRole注解//如果有,判断是否用户具有注解属性中要求的角色//如果没有hasRole注解,那么说明方法不需要判断用户的角色,可以匿名访问HasRole hasRole = method.getDeclaredAnnotation(HasRole.class);if(hasRole != null && (userRoles == null || !userRoles.contains(hasRole.value()))){throw new RuntimeException("用户没有访问权限");}}
}
这里只是配置了一个固定的注解再在pointcut上,是不需要判断的。但是如果我们不是指定某一个具体的注解的话,那么需要增加判断。因为我们的前置通知里面除了判断接口权限,还可以做很多其他的事情
AopController
@RestController
public class AopController {//访问这个方法需要用户具有admin的角色@HasRole("admin")@GetMapping("query1")public String query1(){return "query1 需要 admin 角色";}//访问这个方法需要用户具有user的角色@HasRole("user")@GetMapping("query2")public String query2(){return "query2 需要 user 角色";}//任何用户都可以访问@GetMapping("query3")public String query3(){return "query3 可以匿名访问";}
}
测试结果
测试1


因为我们本次的传参是username=lbw, 然而lbw并没有admin权限, 所以此时我们的AOP生效进行拦截
测试2

测试3

这里可以匿名访问是因为, 我们并没有在query3方法上添加@HasRole注解, 这时请求的参数不会走AOP, AOP拦截不生效, 所以可以匿名访问

如果这篇【文章】有帮助到你💖,希望可以给我点个赞👍,创作不易,如果有对Java后端或者对
spring感兴趣的朋友,请多多关注💖💖💖
👨🔧 个人主页 : 阿千弟
相关文章:
AOP的另类用法 (权限校验自定义注解)
👳我亲爱的各位大佬们好😘😘😘 ♨️本篇文章记录的为 AOP的另类用法 (权限校验&&自定义注解) 相关内容,适合在学Java的小白,帮助新手快速上手,也适合复习中,面试中的大佬🙉🙉…...
[数据结构]:12-快速排序(顺序表指针实现形式)(C语言实现)
目录 前言 已完成内容 快速排序实现 01-开发环境 02-文件布局 03-代码 01-主函数 02-头文件 03-PSeqListFunction.cpp 04-SortCommon.cpp 05-SortFunction.cpp 结语 前言 此专栏包含408考研数据结构全部内容,除其中使用到C引用外,全为C语言代…...
运算符——“Python”
各位CSDN的uu们你们好呀,好久没有更新Python文章了,今天,小雅兰的内容就是Python中的操作符啦,那么现在,就让我们进入Python的世界吧 注释 注释是什么 注释的语法 注释的规范 输入输出 和用户交互 通过控制台输出 通…...
2022 IoTDB Summit:华为王超《Apache IoTDB 在华为云的实践》
12 月 3 日、4日,2022 Apache IoTDB 物联网生态大会在线上圆满落幕。大会上发布 Apache IoTDB 的分布式 1.0 版本,并分享 Apache IoTDB 实现的数据管理技术与物联网场景实践案例,深入探讨了 Apache IoTDB 与物联网企业如何共建活跃生态&#…...
C 语言网络编程 — PF_NETLINK sockets
目录 文章目录目录PF_NETLINK socketsPF_NETLINK sockets Linux 提供了 4 种 User Process 和 Kernel 之间进行通信的 IPC(Inter-Process Communicate,进程间通信)方式: /procioctlsysfsPF_NETLINK sockets(Netlink …...
广州银行冲刺A股上市:不良贷款规模突破100亿元,不良率飙升
又一家城商行平移申报IPO。近日,广州银行股份有限公司(下称“广州银行”)递交招股书,准备在深圳证券交易所主板上市。本次冲刺上市,广州银行计划募资约94.79亿元,国泰君安证券为其保荐机构。 截至目前&…...
【C++】bsearch函数的使用及二分法查找介绍
写程序的时候,肯定避免不了需要从集合中找到符合条件的元素,一般情况下,最简单也最常用的就是循环遍历元素,这种方法虽然写的简单,但是小数据量还行,但是数据过大的话,这样效率就低了。循环的时…...
分布式系统中的补偿机制设计问题
我们知道,应用系统在分布式的情况下,在通信时会有着一个显著的问题,即一个业务流程往往需要组合一组服务,且单单一次通信可能会经过 DNS 服务,网卡、交换机、路由器、负载均衡等设备,而这些服务于设备都不一…...
类成员的方法
初识对象 生活中或是程序中,我们都可以使用设计表格、生产表格、填写表格的形式组织数据进行对比,在程序中: 设计表格,称之为:设计类(class) 打印表格,称之为:创建对象 …...
华为OD机试真题Python实现【端口合并】真题+解题思路+代码(20222023)
端口合并 题目 有M(1<=M<=10)个端口组, 每个端口组是长度为N(1<=N<=100)的整数数组, 如果端口组间存在 2 个及以上不同端口相同, 则认为这 2 个端口组互相关联,可以合并 第一行输入端口组个数 M,再输入 M 行,每行逗号分隔,代表端口组。 输出合并后的端口组…...
自考本科计算机网络原理(04741)历年大题真题【18年10月-22年10月】
文章目录一、简答题(历年真题)18年10月-22年10月历年简答题出题情况分析2018年10月2019年4月2019年10月2020年8月2020年10月2021年4月2021年10月2022年4月2022年10月二、综合题(历年真题)2018年10月2019年4月2019年10月2020年8月2…...
计算机SCI期刊投稿,除了投稿信,还要做什么准备? - 易智编译EaseEditing
投稿信的准备 期刊的编辑往往需要一些有关作者及其论文的信息。 而作者也希望给编辑提供一些有助于其全文送审及决策的信息。 这些信息都应该包括在投稿信中。 投稿信应包括以下几方面的内容: 文题和所有作者的姓名;稿件适宜的栏目; 为什么此论文适合于在该刊而…...
Allegro如何刷新封装和库里的封装同步操作指导
Allegro如何刷新封装和库里的封装同步操作指导 在做PCB设计的过程中,有时会因为库里的封装有更新,所以PCB上使用到了这个封装时候需要和库里的同步,如下图 如何刷新,具体操作如下 点击Place点击Update Symbols...
基于Vue3手写选课组件(含时区切换,拖拽选择)
环境说明 基于vue3vite 无关联别的ui框架,组件化 初次使用vue3,技术菜,大佬勿喷 main.ts "moment": "^2.29.4","moment-timezone": "^0.5.41",import moment from moment; import momentTz from &…...
准备好了吗?加入 GDE 成长计划,成为下一位谷歌开发者专家!
谷歌开发者专家 (Google Developer Experts,GDE),又称谷歌开发者专家项目,是由一群经验丰富的技术专家、具有社交影响力的开发者和思想领袖组成的全球性社区。通过在各项活动演讲以及各个平台上发布优质内容来积极助力开发者、企业和技术社区…...
搭建帮助中心的 8 个最佳工具
网站帮助中心的作用通过向客户表明您了解他们所面临的问题以及如何提供帮助来建立信任;通过回答常见问题来改善客户服务,增强专业的品牌形象;通过减少重复发送给支持人员的电话和电子邮件,节省时间和金钱;增强您在搜索…...
LQB小板焊接V3版本的小板原理图,PCB图,注意事项和步骤
第一部分,这个部分,可以不焊接,直接用买的下载器进行下载代码,外接一个下载器,网上大概是10元左右,以后学习stm32的芯片的时候,这个下载器就是一个串口转换器,也可以使用。。 当然也…...
华为OD机试真题Python实现【翻转单词顺序】真题+解题思路+代码(20222023)
翻转单词顺序 题目 输入一个英文文章片段 翻转指定区间的单词顺序,标点符号和普通字母一样处理 例如输入字符串 I am a developer. 区间[0,3]则输出 developer. a am I 🔥🔥🔥🔥🔥👉👉👉👉👉👉 华为OD机试(Python)真题目录汇总 ## 输入 使用换行隔…...
微机原理和计算机组成原理复习
1:冯诺依曼机器的主要特点? 1)计算机由运算器、存储器、控制器、输入设备和输出设备五大部分组成; 2)指令和数据存储在存储器中,并可以按地址访问; 3)指令和数据均以二进制表示&…...
mysql5.7.33安装配置教程【保姆级安装教程】
MySQL5.7.33安装教程 1、官方网站下载 点击这里跳转页面下载 1.1、看下你是什么系统,系统是64位还是32位 2、解压到D盘跟路径或者其下面纯英文路径 2.1、可见它没有data、log等文件夹,不需手动添加(下面执行命令自动初始化)!! …...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...
数据库正常,但后端收不到数据原因及解决
从代码和日志来看,后端SQL查询确实返回了数据,但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离,并且ai辅助开发的时候,很容易出现前后端变量名不一致情况,还不报错,只是单…...
医疗AI模型可解释性编程研究:基于SHAP、LIME与Anchor
1 医疗树模型与可解释人工智能基础 医疗领域的人工智能应用正迅速从理论研究转向临床实践,在这一过程中,模型可解释性已成为确保AI系统被医疗专业人员接受和信任的关键因素。基于树模型的集成算法(如RandomForest、XGBoost、LightGBM)因其卓越的预测性能和相对良好的解释性…...
鸿蒙Navigation路由导航-基本使用介绍
1. Navigation介绍 Navigation组件是路由导航的根视图容器,一般作为Page页面的根容器使用,其内部默认包含了标题栏、内容区和工具栏,其中内容区默认首页显示导航内容(Navigation的子组件)或非首页显示(Nav…...
职坐标物联网全栈开发全流程解析
物联网全栈开发涵盖从物理设备到上层应用的完整技术链路,其核心流程可归纳为四大模块:感知层数据采集、网络层协议交互、平台层资源管理及应用层功能实现。每个模块的技术选型与实现方式直接影响系统性能与扩展性,例如传感器选型需平衡精度与…...
SpringCloud优势
目录 完善的微服务支持 高可用性和容错性 灵活的配置管理 强大的服务网关 分布式追踪能力 丰富的社区生态 易于与其他技术栈集成 完善的微服务支持 Spring Cloud 提供了一整套工具和组件来支持微服务架构的开发,包括服务注册与发现、负载均衡、断路器、配置管理等功能…...
若依项目部署--传统架构--未完待续
若依项目介绍 项目源码获取 #Git工具下载 dnf -y install git #若依项目获取 git clone https://gitee.com/y_project/RuoYi-Vue.git项目背景 随着企业信息化需求的增加,传统开发模式存在效率低,重复劳动多等问题。若依项目通过整合主流技术框架&…...
