SpringAOP---概念、实现、实战全打包(图文讲解)

目录

1.什么是AOP?

1.1基本概念

1.2具体应用

2.AOP是怎么怎么实现的?

2.1静态代理

2.2动态代理

2.2.1cglib 动态代理

2.2.2 JDK 动态代理

3.AOP中的核心概念

4.AOP具体实现(权限校验)

1.详细版

2.精简版

5总结


大家好!今天咱们来聊聊Spring框架中一个非常核心且实用的特性——AOP。很多小伙伴刚接触AOP时会觉得抽象,比如“什么是切面?”“动态代理到底是啥?”“实际开发中我该怎么用?”。这篇文章就从基础概念核心原理,再到实际应用,一步步把Spring AOP讲明白,小白也能轻松看懂~,发车咯~

使用 Spring 的面向切面编程 :: Spring 框架 - Spring 框架(官网地址)

1.什么是AOP?

1.1基本概念

英文名叫Aspect-Oriented Programming,就是面向切面编程嘛!,将冗余代码抽离出来,组成一个切面,想把刀子一样插入到原来的代码中,是为了让我们尽量少的写代码的。有个叫AspectJ的框架的东西,可以将属性、方法、代码块批量增强。AOP就借鉴到了AspecJ框架。

1.2具体应用

在许多情况下,我们需要对用户操作进行权限校验,因为在有的场景下只有系统中管理员才有权限操作的,我们就假设在我们的系统中新增用户更新用户需要管理员权限。

在下图中新增用户更新用户这两个方法里,都重复写了 “用户权限校验” 的代码 —— 如果有 10 个类似的方法,就要写 10 遍权限校验,既冗余又难维护。

这时天使宝宝AOP来了, 把 “用户权限校验” 抽成一个独立的切面,通过 AOP 动态 “切入” 到新增、更新方法的执行流程中。

总结一下:AOP将那些与业务逻辑无关,但多个业务模块都需要的公共功能(比如日志、权限、事务),抽取出来单独维护,然后在不修改原有业务代码的前提下,动态地切入到业务方法的指定位置

简单说,AOP就是“抽离公共代码,动态植入业务”,实现代码解耦复用

2.AOP是怎么怎么实现的?

AOP是通过代理来实现的,想象成一个小助理可以代理我们的类执行对应的代码逻辑。代理也分为静态代理动态代理两种。

2.1静态代理

静态代理,静态代理是通过代码运行前,通过修改class文件来完成代理,功能强大,较为复杂,运行效率比动态代理块。静态代理分为,编译前,编译后,加载时三种。这三种作为了解即可

  • 编译前:在代码编写完成后、编译为.class 文件前,手动编写代理类并关联目标类,代理逻辑与目标逻辑在编码阶段已绑定。
  • 编译后:通过字节码修改已编译生成的.class 文件,将代理逻辑织入目标类的字节码中。
  • 加载时:在类加载器将.class 文件加载到JVM的过程中,通过自定义类加载器拦截加载流程,动态修改类字节码以植入代理逻辑。

2.2动态代理

动态代理分为两种分为cglibjdk两种 Spring 框架会根据目标类是否实现接口,自动选择Jdkcglib动态代理

2.2.1cglib 动态代理

  • 基于字节码生成目标类的子类,可代理未实现接口的类;
  • 依赖第三方库(需引入 cglib 包),但不支持代理 final 类 / 方法。

2.2.2 JDK 动态代理

  • 基于接口实现,仅能代理实现了接口的类;
  • 利用 Java反射机制生成代理对象,无需额外依赖。

3.AOP中的核心概念

这些概念先在脑子里留个印象就信,我们等下将一些概念实际应用~~~

1.切面(Aspect):抽离出来的公共功能模块(比如“日志切面”“权限切面”)。一个切面里包含了“要做什么”(通知)和“在哪里做”(切入点)。

2.通知(Advice):切面里具体要执行的逻辑(比如“记录接口入参”“记录接口耗时”)。Spring提供了5种通知类型,对应不同的切入时机:

    • 前置通知(Before):业务方法执行前执行(比如记录请求开始时间)
    • 后置通知(After):业务方法执行后执行(无论成功还是失败,比如记录请求结束)
    • 返回通知(AfterReturning):业务方法成功执行后执行(比如记录接口返回结果)
    • 异常通知(AfterThrowing):业务方法抛出异常时执行(比如记录异常信息)
    • 环绕通知(Around):包裹业务方法,在方法执行前后都能执行(功能最强,比如统计接口耗时)

3.切入点(Pointcut):定义“哪些业务方法需要被切入”。切入点通常用表达式来描述。

4.连接点(JoinPoint):程序运行中可能被切入的(比如方法执行前、执行后、抛出异常时)。每个切入点对应的都是多个连接点。

5.目标对象(Target):被切入的业务对象(比如咱们的UserController、OrderService)。

6.代理对象(Proxy):Spring AOP通过动态代理技术,为目标对象创建的代理对象。实际调用时,咱们调用的是代理对象,代理对象会先执行切面逻辑,再执行目标对象的业务方法。

7.织入(Weaving):将切面逻辑动态植入到目标对象方法中的过程(Spring在运行时完成织入)。

其中,通知(Advice)切面核心逻辑,Spring 提供了 5 种通知类型,对应不同的切入时机,实战中最常用的是环绕通知。

4.AOP具体实现(权限校验)

了解了 AOP 的原理和核心概念后,咱们来做一个企业级实战案例—— 用 AOP 实现接口的权限校验,这是项目中非常非常非常常用的功能。我们分为详细版精简版实现,可以选择食用!!!

实战需求

  • 定义一个权限校验注解 @AuthCheck,可指定方法所需的角色(如 admin、user);
  • 用 AOP 环绕通知拦截所有标注了 @AuthCheck 的方法;
  • 校验逻辑:未登录 → 抛未授权异常;已登录但角色不匹配 → 抛无权限异常;角色匹配 → 执行目标方法。

1.详细版

1.1 创建自定义权限注解 @AuthCheck

注解用于标记需要进行权限校验的方法,指定方法所需的角色。

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 AuthCheck { /** * 方法执行所需的必选角色标识 * 示例:"admin" 表示需要管理员角色,"user" 表示需要普通用户角色 * 默认值为空字符串,表示无需特定角色(仅需登录即可) * @return 角色标识字符串 */ String mustRole() default ""; }

1.2 创建自定义异常类

定义未授权(未登录)和无权限(角色不匹配)的自定义异常,用于权限校验失败时抛出。

/** * 未授权异常(对应HTTP 401状态码) * 用于用户未登录时抛出 */ public class UnauthorizedException extends RuntimeException { public UnauthorizedException(String message) { super(message); } } /** * 禁止访问异常(对应HTTP 403状态码) * 用于用户已登录但角色不匹配时抛出 */ public class ForbiddenException extends RuntimeException { public ForbiddenException(String message) { super(message); } }

1.3 创建角色枚举和常量(可选)

为了规范角色标识,避免硬编码,可创建角色枚举或常量类。

/** * 角色枚举类 */ public enum UserRoleEnum { ADMIN("admin", "管理员"), USER("user", "普通用户"); private final String value; private final String desc; UserRoleEnum(String value, String desc) { this.value = value; this.desc = desc; } public String getValue() { return value; } public String getDesc() { return desc; } } /** * 角色常量类(也可直接使用枚举) */ public class UserConstant { public static final String ADMIN_ROLE = "admin"; public static final String USER_ROLE = "user"; }

1.4 实现 AOP 权限拦截器

创建切面类,使用环绕通知实现权限校验逻辑,核心流程:

  1. 从请求中获取当前登录用户;
  2. 校验用户是否已登录;
  3. 从 @AuthCheck 注解中获取所需角色;
  4. 校验用户角色是否匹配;
  5. 角色匹配则执行目标方法,不匹配则抛出异常。
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; /** * 权限校验AOP拦截器 * 拦截所有标注@AuthCheck注解的方法,执行角色权限校验 */ @Aspect // 标识该类为AOP切面类 @Component // 交给Spring容器管理,使切面生效 public class AuthInterceptor { /** * 注入用户服务,用于获取当前登录用户信息 * 实际项目中,UserService需实现从请求中解析登录用户(如通过Token解析) */ @Resource private UserService userService; /** * 环绕通知:拦截所有标注@AuthCheck注解的方法 * @param joinPoint 切入点对象,可获取目标方法信息、执行目标方法 * @param authCheck 目标方法上的@AuthCheck注解实例,用于获取所需角色 * @return 目标方法的执行结果 * @throws Throwable 目标方法执行过程中抛出的异常 */ @Around("@annotation(authCheck)") // 切入点表达式:拦截所有标注@AuthCheck注解的方法 public Object doIntercept(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable { // 1. 获取注解配置的必选角色 String mustRole = authCheck.mustRole(); // 2. 获取当前HTTP请求对象(从请求上下文获取) ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); HttpServletRequest request = requestAttributes.getRequest(); // 3. 从请求中获取当前登录用户(实际项目中需通过Token、Session等方式解析) User loginUser = userService.getLoginUser(request); // 4. 基础校验:未登录则抛出未授权异常 if (loginUser == null) { throw new UnauthorizedException("未登录,无法执行该操作"); } // 5. 无指定必选角色:仅需登录即可,直接执行目标方法 if ("".equals(mustRole)) { return joinPoint.proceed(); // 执行目标方法 } // 6. 管理员角色校验:如果注解指定角色为admin,需校验用户是否为管理员 if (UserRoleEnum.ADMIN.getValue().equals(mustRole)) { if (!isAdmin(loginUser)) { throw new ForbiddenException("无管理员权限,禁止执行该操作"); } return joinPoint.proceed(); // 权限通过,执行目标方法 } // 7. 普通角色校验:当前用户角色需与注解指定角色完全匹配 String userRole = loginUser.getUserRole(); if (!mustRole.equals(userRole)) { throw new ForbiddenException(String.format("无[%s]角色权限,禁止执行该操作", mustRole)); } // 8. 所有校验通过,执行目标方法并返回结果 return joinPoint.proceed(); } /** * 辅助方法:判断当前登录用户是否为管理员 * @param user 登录用户对象 * @return true-管理员,false-非管理员 */ private boolean isAdmin(User user) { return user != null && UserRoleEnum.ADMIN.getValue().equals(user.getUserRole()); } }

1.5 在业务方法中使用注解

在需要进行权限校验的业务方法上标注 @AuthCheck 注解,并指定所需角色即可。

import org.springframework.stereotype.Service; /** * 用户业务服务类 */ @Service public class UserService { /** * 新增用户(仅管理员可执行) * 标注@AuthCheck,指定必须有admin角色 */ @AuthCheck(mustRole = UserRoleEnum.ADMIN.getValue()) public void addUser(User user) { // 核心业务逻辑:新增用户到数据库 userMapper.insert(user); } /** * 更新用户信息(普通用户可执行) * 标注@AuthCheck,指定必须有user角色 */ @AuthCheck(mustRole = UserRoleEnum.USER.getValue()) public void updateUser(User user) { // 核心业务逻辑:更新用户信息 userMapper.updateById(user); } /** * 查询用户信息(仅需登录,无特定角色要求) * 标注@AuthCheck,不指定mustRole(默认空字符串) */ @AuthCheck public User getUserById(Long userId) { // 核心业务逻辑:查询用户信息 return userMapper.selectById(userId); } // 其他方法... }

2.精简版

2.1编写权限校验注解创建一个接口

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 AuthCheck { /** * 方法执行所需的必选角色标识 * 示例:"admin" 表示需要管理员角色,"user" 表示需要普通用户角色 * 默认值为空字符串,表示无需特定角色(仅需登录即可) * @return 角色标识字符串 */ String mustRole() default ""; }

2.2编写校验AOP,采取环绕通知。

@Aspect @Component public class AuthInterceptor { @Resource private UserService userService; /** * 执行拦截 * * @param joinPoint 切入点 * @param authCheck 权限校验注解 */ @Around("@annotation(authChek)") //@annotation(...) 表示 “拦截所有被括号中指定注解标记的方法”。 public Object doIntercept(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable { //逻辑校验,若校验失败则抛出异常 // //代码省略........... // return joinPoint.proceed(); } }

2.3在想要校验的方法上添加注解

@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)

5总结

Spring AOP是一种非常强大的编程思想,核心是通过代理将公共功能抽离切面,动态植入业务方法,实现解耦代码复用

核心要点回顾

  1. AOP 的核心思想:抽离公共代码,动态植入业务
  2. 底层实现:静态代理(AspectJ)和动态代理(JDK/CGLIB),Spring AOP默认使用动态代理
  3. 核心概念:切面、通知、切入点、连接点、目标对象、代理对象、织入
  4. 实战关键:通过自定义注解 + 环绕通知,可快速实现权限校验、日志记录等功能

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

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

相关文章

Qwen2.5-7B聊天机器人:个性化角色定制全攻略

Qwen2.5-7B聊天机器人:个性化角色定制全攻略 1. 背景与技术定位 1.1 Qwen2.5 系列的技术演进 Qwen2.5 是阿里云推出的最新一代大语言模型系列,覆盖从 0.5B 到 720B 参数的多个版本,涵盖基础预训练模型和指令调优模型。其中,Qwen…

环保实验室LIMS系统选型对比:中小环境检测单位的最优之选——硕晟LIMS

在环保行业快速发展的当下,实验室信息管理系统(LIMS)已成为中小环境检测单位提升工作效率、保障数据准确性和合规性的关键工具。为了帮助中小环境检测单位在众多LIMS供应商中做出明智选择,本文对广州白码、金现代、北京三维天地、…

从零开始部署Qwen2.5-7B|vLLM助力高效推理

从零开始部署Qwen2.5-7B|vLLM助力高效推理 一、引言:为何选择Qwen2.5-7B与vLLM组合? 在大模型落地实践中,推理效率和部署成本是决定项目能否规模化应用的核心因素。传统基于HuggingFace Transformers的推理方式虽然灵活&#xf…

图床软件 PicGo + Github

1、PicGo 下载:https://github.com/Molunerfinn/PicGo/releaseshttps://github.com/Molunerfinn/PicGo/releases 2、Github添加图床仓储 1.1 新建仓储 image-host 仓库名:czjnoe/image-host 1.2 创建Github Token https://github.com/settings/tokens…

SMBus协议数据字节传输机制通俗解释

SMBus协议数据字节传输机制通俗解释从“板级对话”说起:SMBus是怎么让设备互相听懂的?你有没有想过,一块服务器主板上成百上千个芯片,它们是怎么“交流”的?温度传感器怎么告诉系统它快“发烧”了?电池又是…

从零实现:基于image2lcd的图标数据生成流程

从一张PNG到MCU屏幕:手把手带你用image2lcd搞定嵌入式图标生成你有没有遇到过这种情况——UI设计师甩给你一组精美的PNG图标,而你的STM32板子却只能显示一块“马赛克”?或者好不容易把图片烧进Flash,结果发现加载慢得像卡顿的PPT&…

百度智能云的AI硬件实践:一块模组里的“工匠对话”

你好朋友,我叫“Dudu”一个专属你的心灵成长伴侣!“你看起来有点不开心?”三岁的乐乐正在摆弄手里的毛绒玩具,听到这句话时惊讶地抬起了头。这只名叫“Dudu”的玩具熊温柔地说。乐乐确实不开心——今天在幼儿园,他心爱…

Qwen2.5-7B成本优化:GPU资源高效利用指南

Qwen2.5-7B成本优化:GPU资源高效利用指南 1. 背景与挑战:大模型推理的算力瓶颈 随着大语言模型(LLM)在自然语言处理、代码生成、多轮对话等场景中的广泛应用,Qwen2.5-7B 作为阿里云最新发布的中等规模开源模型&#x…

多语言大模型部署新选择|Qwen2.5-7B镜像使用详解

多语言大模型部署新选择|Qwen2.5-7B镜像使用详解 随着大语言模型(LLM)在自然语言处理领域的广泛应用,如何高效、灵活地部署高性能模型成为开发者关注的核心问题。阿里云推出的 Qwen2.5-7B 模型,作为 Qwen 系列的最新迭…

Qwen2.5-7B知识库增强:专业领域问答系统搭建

Qwen2.5-7B知识库增强:专业领域问答系统搭建 1. 技术背景与问题提出 随着大语言模型(LLM)在自然语言理解与生成任务中的广泛应用,构建具备专业领域知识的智能问答系统已成为企业智能化服务的核心需求。通用大模型虽然具备广泛的…

Qwen2.5-7B容器化部署:Docker最佳实践

Qwen2.5-7B容器化部署:Docker最佳实践 1. 引言:为何选择Docker部署Qwen2.5-7B? 1.1 大模型落地的工程挑战 随着大语言模型(LLM)在自然语言理解、代码生成和多模态任务中的广泛应用,如何高效、稳定地将模型…

解析Multisim数据库管理机制:一文说清主库定位原理

Multisim主库为何“失踪”?一文讲透数据库定位机制与实战修复你有没有遇到过这样的场景:刚打开Multisim,准备画个电路图,却发现元件库一片空白——电阻、电容、三极管全都不见了。软件弹出一条提示:“无法加载主数据库…

Windows驱动开发必备:WinDbg Preview下载完整示例

从零搭建Windows驱动调试环境:WinDbg Preview实战全解析你有没有遇到过这样的场景?刚写完一个内核驱动,兴冲冲地安装到测试机上,结果一启动系统直接蓝屏——BUGCODE_NVBUS_DRIVER (0x133)。重启再试,又是一模一样的错误…

图解说明ES6的Iterator遍历器设计原理

深入理解 ES6 Iterator:从遍历机制到现代 JavaScript 的设计哲学你有没有遇到过这样的场景?用for...in遍历数组,结果莫名其妙多出几个“幽灵”属性;想把一个 DOM 节点列表(NodeList)展开成数组,…

SpringBoot+Vue 校园资料分享平台平台完整项目源码+SQL脚本+接口文档【Java Web毕设】

摘要 随着信息化时代的快速发展,校园内的学习资源共享需求日益增长,传统的资料分享方式如纸质传递或单一社交平台分享已无法满足学生的高效学习需求。校园资料分享平台旨在解决这一问题,通过数字化手段整合课程笔记、考试真题、实验报告等学习…

Qwen2.5-7B GPU配置指南:4090D四卡并行优化方案

Qwen2.5-7B GPU配置指南:4090D四卡并行优化方案 1. 背景与技术定位 1.1 Qwen2.5-7B 模型简介 Qwen2.5 是阿里云最新发布的大型语言模型系列,覆盖从 0.5B 到 720B 参数的多个版本。其中 Qwen2.5-7B 是一个在性能与资源消耗之间取得良好平衡的中等规模模…

大比表面积氧化铈:淡黄色粉末中的催化密码

在材料科学的微观世界里&#xff0c;一种淡黄色的粉末正在静默地展示着它的不凡——这就是氧化铈&#xff08;CeOn&#xff0c;1.5<n<2&#xff09;。它看似普通&#xff0c;却蕴含着强大的氧化还原能力&#xff0c;悄然推动着多个领域的技术进步。动态平衡的氧化还原核心…

基于Qwen2.5-7B的大模型LoRA微调全流程解析

基于Qwen2.5-7B的大模型LoRA微调全流程解析 随着大语言模型&#xff08;LLM&#xff09;在自然语言处理领域的广泛应用&#xff0c;如何高效地对百亿级参数模型进行个性化定制成为工程实践中的关键课题。阿里云推出的 Qwen2.5-7B-Instruct 模型凭借其强大的多语言支持、结构化输…

通过Multisim访问用户数据库优化课程管理

当仿真遇见数据&#xff1a;用Multisim打通课程管理的“任督二脉”你有没有遇到过这样的场景&#xff1f;学生交上来的实验报告写得头头是道&#xff0c;但当你问他&#xff1a;“你测到的截止频率到底是多少&#xff1f;”他支支吾吾答不上来&#xff1b;或者全班三十多人做完…

Modbus主从模式在RS485上的应用

Modbus主从通信如何在RS485上稳定运行&#xff1f;一文讲透工业现场的“数据高速公路”你有没有遇到过这样的场景&#xff1a;工厂里几十台传感器通过一根双绞线连到控制室&#xff0c;上位机却时不时收不到数据、报CRC错误&#xff0c;甚至整个总线“瘫痪”&#xff1f;排查半…