65 切面AOP

65 切面AOP

切面基础概念

  • AOP:Aspect Oriented Programming,面向切面编程。是通过预编译方式(aspectj)或者运行期动态代理(Spring)实现程序功能的统一维护的技术。

面试问题:
Spring的两大核心是什么:IoC和AOP
分别有什么作用
IoC:控制反转,目的用于解耦,底层使用的技术是反射+工厂模式
AOP:面向切面编程,目的是在不修改目标对象源码的情况下,进行功能增强,底层使用的是动态代理技术

  • AOP作用:不修改源码的情况下,进行功能增强,通过动态代理实现的;
  • AOP的底层是通过动态代理实现的。在运行期间,通过代理技术动态生成代理对象,代理对象方法执行时进行功能的增强介入,再去调用目标方法,从而完成功能增强。
  • 常用的动态代理技术有:
    • JDK的动态代理:基于接口实现的
    • cglib的动态代理:基于子类实现的
  • Spring的AOP采用了哪种代理方式?
    • 如果目标对象有接口,就采用JDK的动态代理技术
    • 如果目标对象没有接口,就采用cglib技术
  • AOP相关概念

    • 目标对象(Target):要代理的/要增强的目标对象。

    • 代理对象(Proxy):目标对象被AOP织入增强后,就得到一个代理对象

    • 连接点(JoinPoint):能够被拦截到的点,在Spring里指的是方法。能增强的方法

    • 切入点(PointCut):要对哪些连接点进行拦截的定义。要增强的方法

    • 通知/增强(Advice):拦截到连接点之后要做的事情。如何增强,额外添加上去的功能和能力

    • 切面(Aspect):是切入点和通知的结合。 告诉Spring的AOP:要对哪个方法,做什么样的增强

    • 织入(Weaving):把增强/通知 应用到 目标对象来创建代理对象的过程
      在这里插入图片描述

  • AOP通知类型

    • @Before 前置通知 通知方法会在目标方法之前执行
    • @After 后置通知 通知方法会在目标方法之后执行
    • @Around 环绕通知 可以在目标方法之前和之后执行,可以更改方法执行之后的结果,自主性最大,需要掌握
    • @AfterReturning 通知方法将在目标方法正常结束之后执行
    • @AfterThrowing 通知方法会在目标方法爆出异常之后执行

切面应用

为了更好对AOP的使用有更深的了解,这里我们以下面这个场景进行实现:

现在在项目中有一些接口需要进行权限校验,即某些用户是无权访问这个接口的,如果无权限应进行拦截。同时这个接口很重要,应该避免某些人员进行恶意的刷接口,所以我们需要对这个接口进行防刷。对某些恶意刷的IP进行封禁,并进行限流,请你基于AOP来完成这个功能。

完整代码请查看:点击查看

注解

那么我们首先就需要写一个注解,来标识这种需要进行处理的接口。

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckPermission {}

这里介绍一下元注解的概念

@Retention

中文翻译为保留的意思,标明自定义注解的生命周期。

从编写Java代码到运行主要周期为源文件→ Class文件 → 运行时数据,@Retention则标注了自定义注解的信息要保留到哪个阶段,分别对应的value取值为SOURCE →CLASS→RUNTIME。

  1. SOURCE 源代码java文件,生成的class文件中就没有该信息了
  2. CLASS class文件中会保留注解,但是jvm加载运行时就没有了
  3. RUNTIME 运行时,如果想使用反射获取注解信息,则需要使用RUNTIME,反射是在运行阶段进行反射的
  4. 示例:当RentionPolicy取值为SOURCE时,Class文件中不会保留注解信息,而取值为CLASS时,Class反编译文件中则保留了注解的信息
  1. Source:一个最简单的用法,就是自定义一个注解例如@ThreadSafe,用来标识一个类时线程安全的,就和注释的作用一样,不过更引人注目罢了。
  2. Class:这个有啥用呢?个人觉得主要是起到标记作用,还没有做实验,例如标记一个@Proxy,JVM加载时就会生成对应的代理类。
  3. Runtime:反射实在运行阶段执行的,那么只有Runtime的生命周期才会保留到运行阶段,才能被反射读取,也是我们最常用的。
@Target

中文翻译为目标,描述自定义注解的使用范围,允许自定义注解标注在哪些Java元素上(类、方法、属性、局部属性、参数…)

在这里插入图片描述

切面

/*** @FileName SecurityAspect* @Description 权限校验 限流 防刷 AOP切面* @Author yaoHui* @date 2024-10-09**/
@Aspect
@Slf4j
@Component
public class SecurityAspect {// 用于记录每个IP的请求时间戳,用于限流private Map<String, List<Long>> requestTimestamps = new ConcurrentHashMap<>();// 用于封禁IP的列表private Set<String> bannedIps = ConcurrentHashMap.newKeySet();// 限流阈值private static final int MAX_REQUESTS = 10;  // 最多允许的请求次数private static final long TIME_WINDOW_MS = 10 * 1000; // 时间窗口,10秒// 切入点 指定被注解CheckPermission标记的就是连接点@Pointcut("@annotation(com.fang.screw.communal.annotation.CheckPermission)")public void checkPermission(){}/**** @Description 对连接点进行业务扩展 进行鉴权 限流 防刷等操作* @param proceedingJoinPoint* @return {@link Object }* @Author yaoHui* @Date 2024/10/9*/@Around("checkPermission()")public Object doPermissionCheck(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();String ipAddress = request.getRemoteAddr();UserPO userPO = CurrentUserHolder.getUser();// 检查IP是否被封禁if (bannedIps.contains(ipAddress)) {return R.failed("该IP已被封禁,请稍后再试!");}// 非超级管理员不可以访问该接口if (userPO.getUserType() != 0){return R.failed("无访问权限!");}// 限流机制if (isRequestTooFrequent(ipAddress)) {bannedIps.add(ipAddress);  // 封禁该IPlog.warn("IP {} 被封禁,因短时间内过多请求", ipAddress);return R.failed("请求过于频繁,请稍后再试!");}return proceedingJoinPoint.proceed();}/**** @Description 判断请求是否过于频繁* @param ipAddress* @return {@link boolean }* @Author yaoHui* @Date 2024/10/9*/private boolean isRequestTooFrequent(String ipAddress) {long currentTime = System.currentTimeMillis();requestTimestamps.putIfAbsent(ipAddress, new ArrayList<>());List<Long> timestamps = requestTimestamps.get(ipAddress);timestamps.add(currentTime);// 清理超过时间窗口的请求timestamps.removeIf(timestamp -> currentTime - timestamp > TIME_WINDOW_MS);return timestamps.size() > MAX_REQUESTS;}
}

权限注解的使用

    /**** @Description 查询分类文章List* @return {@link PoetryResult<Map<Integer,List<ArticleVO>>> }* @Author yaoHui* @Date 2024/9/22*/@CheckPermission@GetMapping("/getListSortArticle")public R<Map<Integer, List<ArticleVO>>> getListSortArticle() {return articleService.getListSortArticle();}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/443536.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【VUE】双端比较算法

假设我们有两个虚拟节点 oldVnode 和 newVnode&#xff0c;它们分别对应的DOM结构为&#xff1a; 我们需要将 oldVnode 更新为 newVnode&#xff0c;这时就可以使用双端比较算法了。算法本质上是将新旧节点进行一次交叉比较&#xff0c;尽可能地重复使用已有的节点来达到最小…

懒人笔记-QT程序UOS打包篇

懒人笔记-uos打包篇 前言1、deploy2、组织打包目录2.1 控制文件2.1.1 control的内容&#xff1a;2.1.2 postinst的内容&#xff1a;2.1.3 postrm的内容&#xff1a; 2.2 执行程序2.3 开机自启&#xff08;可选项&#xff09; 3、输出deb安装包4、服务卸载4.1 服务卸载4.2 程序按…

Web自动化Demo-PHP+Selenium

1.新建工程 打开PhpStorm新建工程如下&#xff1a; 打开终端输入如下命令安装selenium&#xff1a; composer require php-webdriver/webdriver 2.编写代码 <?php require vendor/autoload.php;use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver…

BMS-绝缘检测

一、为什么要进行绝缘检测 前言&#xff1a;BMS绝缘检测是指对电池组与车体之间的绝缘状态进行实时监测和检测。为了确保电池组与车体之间的绝缘性能良好&#xff0c;防止漏电和短路等安全隐患&#xff0c;BMS绝缘检测系统能够及时发现绝缘故障&#xff0c;并采取相应的措施进…

计算机毕业设计Python深度学习游戏推荐系统 Django PySpark游戏可视化 游戏数据分析 游戏爬虫 Scrapy 机器学习 人工智能 大数据毕设

主要功能如下&#xff1a; &#xff08;1&#xff09;用户管理模块&#xff1a;用户能够注册、登录及修改个人信息&#xff0c;查看热门游戏及攻略信息。 &#xff08;2&#xff09;数据采集与处理模块&#xff1a;主要通过Python编程&#xff0c;爬取Tap Tap社区中游戏热门榜…

python发送邮件带附件:配置全指南与步骤?

python发送邮件带附件教程&#xff1f;python如何发邮件带附件&#xff1f; 无论是工作报告、项目文档还是个人通知&#xff0c;邮件都能快速传递信息。而当这些信息需要附带文件时&#xff0c;Python发送邮件带附件的功能就显得尤为重要。AokSend将详细介绍如何使用Python发送…

简易入门:使用Docke 部署一个tomcat服务

简易入门&#xff1a;使用Docke 部署一个tomcat服务 # 拉取 >docker pull tomcat:9.0# 后台运行容器&#xff0c;端口映射为8080. -p 宿主机端口:容器端口 >docker run -d --name tomcat-c-01 -p 8080:8080 tomcat:9.0# 查看容器id >docker ps CONTAINER ID IMAG…

大数据毕业设计选题推荐-王者荣耀战队数据分析-Python数据可视化-Hive-Hadoop-Spark

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

图解 微信开发者工具 小程序源码 调试、断点标记方法 , 微信小程序调试器,真机调试断点调试方法,小程序网络API请求调试方法 总结

在我们使用微信开发者工具进行微信小程序开发的时候&#xff0c;在这个微信开发者工具的代码编辑框里面我们是无法像使用vscode, idea等IDE工具时那样直接对代码打断点进行调试&#xff0c; 原因是小程序实际上他就是一个web浏览器应用的包装, 在其内部使用的还是类似chrome的…

Mysql数据库安装与C++配置

本文档旨在为需要安装和配置MySQL 8.3、MySQL Workbench以及C Connector的用户提供详细的步骤指导。在安装过程中&#xff0c;可能会遇到一些常见问题&#xff0c;如DLL文件缺失等&#xff0c;本指南也会提供相应的解决办法。 1.安装Mysql8.3 安装Mysql有很多教程&#xff0c…

10.MySql全局参数优化

从上图可以看出SQL及索引的优化效果是最好的&#xff0c;而且成本最低&#xff0c;所以工作中我们要在这块花更多时间。 一、全局参数 配置文件my.ini(windows)或my.cnf(mac)的全局参数&#xff1a; 假设服务器配置为&#xff1a; CPU&#xff1a;32核 内存&#xff1a;64G…

《Linux运维总结:基于ARM64+X86_64架构CPU使用docker-compose一键离线部署mongodb 7.0.14容器版分片集群》

总结&#xff1a;整理不易&#xff0c;如果对你有帮助&#xff0c;可否点赞关注一下&#xff1f; 更多详细内容请参考&#xff1a;《Linux运维篇&#xff1a;Linux系统运维指南》 一、部署背景 由于业务系统的特殊性&#xff0c;我们需要面向不通的客户安装我们的业务系统&…

charAt,chartCodeAt,codePointAt,fromCodePoint,fromCharCode

生僻字的length算2,有些空格是特殊空格,比如\u3000 u3000不是全角空格&#xff0c;u3000是表意字空格&#xff08;Ideographic Space&#xff09;&#xff0c;宽度和一个表意字&#xff08;汉字&#xff09;相同。它应当被当做汉字来处理。比如&#xff0c;在一些排版中&#x…

Python安装|PyCharm Professional 下载安装教程。2024最新版,亲测使用!

一、下载地址&#xff1a; 二、Python的下载及安装&#xff1a; 1、从上面网址进入Python官网 2、安装流程图&#xff1a; 双击已经下载好的python-*.*.*-amd64.exe文件&#xff0c;开始安装 最后就等它自己安装完成就好了 3、检验是否安装完成&#xff1a; windowsR快捷键…

Spring系列 循环依赖

文章目录 注入方式循环依赖的场景单例创建流程getSingletoncreateBeandoCreateBeancreateBeanInstance 循环依赖分析为什么都使用构造函数无法解决&#xff1f;为什么使用Autowired可以解决&#xff1f;为什么要添加到 earlySingletonObjects 缓存中&#xff1f;allowCircularR…

计算机毕业设计 基于Python音乐平台的设计与实现 Python毕业设计 Python毕业设计选题 Vue 前后端分离【附源码+安装调试】

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

windows C++-移除界面工作线程(一)

本文档演示了如何使用并发运行时将 Microsoft 基础类 (MFC) 应用程序中由用户界面 (UI) 线程执行的工作移动到工作线程。 本文档还演示了如何提高冗长绘制操作的性能。 通过将阻塞性操作&#xff08;例如&#xff0c;绘制&#xff09;卸载到工作线程来从 UI 线程中移除工作&am…

浙大数据结构:08-图8 How Long Does It Take

这道题算是较为简单的拓扑排序题&#xff0c;难度不大 机翻 1、条件准备 n,m为n个结点&#xff0c;m条边。 tim数组存到该结点完成的最早时间&#xff0c;会一点点更新 graph存有向边的时间 indegree数组存每个结点的入度 #include <iostream> #include <vector&g…

采用反相正基准电压电路的反相运算放大器

1 简介 本设计使用采用反相正基准电压的反相放大器将 –5V 至 –1V 的输入信号转换为 3.3V 至 0.05V 的输出电压。该电路可用于将传感器负输出电压转换为可用的 ADC 输入电压范围。 2 设计目标 2.1 输入 2.2 输出 2.3 电源 3 电路设计 根据设计目标&#xff0c;最终设计的电…

Python 与 Pycharm 的简易安装教程,包含Pycharm的修改

一. 官方网站 Python网址&#xff1a;python唯一的官方网址。 Pycharm网址&#xff1a;Pycharm的官方网址。 二. python安装步骤 滑动到红色框内 Downloads 导航栏。 红色框是选择适合自己电脑系统和版本的部分&#xff0c;蓝色框是选择系统的部分&#xff0c;黄色框是版本号。…