news 2026/10/3 13:55:11

初步理解 AOP

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
初步理解 AOP

初步理解 AOP

AOP(Aspect-Oriented Programming,面向切面编程)是对 OOP(面向对象编程)的补充。它要解决的核心问题是:把那些散落在各个业务方法中的重复逻辑(如日志、事务、权限、缓存)抽取出来,集中管理,让业务代码只关注业务本身。

一、为什么需要 AOP

假设你写了一个用户注册方法:

publicvoidregister(Useruser){log.info("开始注册用户:"+user.getName());// 日志longstart=System.currentTimeMillis();// 性能监控if(!currentUser.hasPermission("user:add")){// 权限校验thrownewPermissionDeniedException();}userDao.save(user);// 真正的业务longcost=System.currentTimeMillis()-start;// 性能监控log.info("注册完成,耗时:"+cost+"ms");// 日志}

真正的业务只有userDao.save(user)一行,其他都是“横切关注点”。如果每个方法都这样写,代码会变得臃肿、重复、难以维护。AOP 就是把这些横切逻辑从业务方法中抽离出去,统一放到“切面”里。

二、AOP 的核心概念

概念说明类比
切面(Aspect)横切关注点的模块化,包含切点和通知一个日志处理类
连接点(Join Point)程序执行中可以插入切面的点,通常是方法调用每个可以被拦截的方法
切点(Pointcut)匹配连接点的表达式,定义“在哪里”织入execution(* com.example.service.*.*(..))
通知(Advice)在切点上执行的具体动作,定义“做什么”log.info("方法执行")
织入(Weaving)把切面应用到目标对象并创建代理的过程Spring 运行时生成代理对象
目标对象(Target)被切面增强的原始业务对象UserServiceImpl实例
代理(Proxy)织入后生成的代理对象,包含增强逻辑$Proxy12或 CGLIB 子类

一句话:切点定义在哪里拦截,通知定义拦截后做什么,切面把它们组合在一起,通过代理织入到目标对象。

三、五种通知类型

通知注解执行时机
前置通知@Before目标方法执行前
后置通知@After目标方法执行后(无论是否异常)
返回通知@AfterReturning目标方法正常返回后
异常通知@AfterThrowing目标方法抛出异常后
环绕通知@Around目标方法执行前后,最强大
@Aspect@ComponentpublicclassLogAspect{@Before("execution(* com.example.service.*.*(..))")publicvoidbefore(JoinPointjp){System.out.println("执行前:"+jp.getSignature().getName());}@AfterReturning(pointcut="execution(* com.example.service.*.*(..))",returning="result")publicvoidafterReturning(JoinPointjp,Objectresult){System.out.println("返回结果:"+result);}@Around("execution(* com.example.service.*.*(..))")publicObjectaround(ProceedingJoinPointpjp)throwsThrowable{longstart=System.currentTimeMillis();Objectresult=pjp.proceed();// 执行目标方法longcost=System.currentTimeMillis()-start;System.out.println("耗时:"+cost+"ms");returnresult;}}

四、AOP 的实现方式

Spring AOP 底层使用动态代理:

  • 目标类实现了接口 → 默认使用 JDK 动态代理。
  • 目标类没有接口 → 使用 CGLIB 动态代理。
  • Spring Boot 默认强制使用 CGLIB。

代理对象在运行时生成,拦截目标方法调用,在调用前后插入通知逻辑。

// 伪代码:代理对象内部publicclassUserServiceProxyimplementsUserService{privateUserServicetarget;publicvoidregister(Useruser){// 前置通知log.info("开始注册");// 调用目标方法target.register(user);// 后置通知log.info("注册完成");}}

五、AOP 能做什么

场景说明
日志记录统一记录方法调用日志
事务管理@Transactional自动开启/提交/回滚事务
权限校验方法执行前检查用户权限
性能监控统计方法执行耗时
缓存@Cacheable先查缓存,未命中才执行方法
异常处理统一捕获异常并记录

六、快速上手示例

1. 引入依赖(Spring Boot)

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>

2. 定义切面

@Aspect@ComponentpublicclassTimeAspect{@Around("execution(* com.example.service.*.*(..))")publicObjectmeasureTime(ProceedingJoinPointpjp)throwsThrowable{longstart=System.currentTimeMillis();Objectresult=pjp.proceed();longcost=System.currentTimeMillis()-start;System.out.println(pjp.getSignature().getName()+" 耗时:"+cost+"ms");returnresult;}}

3. 调用 Service 方法

@ServicepublicclassUserService{publicvoidregister(Useruser){System.out.println("注册用户:"+user.getName());}}

执行userService.register(user)时,控制台会输出:

注册用户:张三 register 耗时:0ms

业务代码中没有任何日志或监控代码,增强逻辑完全由切面处理。

七、注意事项

内部调用失效:同一个类中方法 A 调用方法 B,B 的增强不会生效。因为内部调用走的是原始对象,不是代理对象。

@ServicepublicclassUserService{publicvoidmethodA(){methodB();// 不经过代理,增强失效}@TransactionalpublicvoidmethodB(){}}

切点表达式要准确:execution(* com.example.service.*.*(..))只匹配service包下的类。写错包名或方法签名会导致增强不生效。

不要滥用 AOP:AOP 适合处理横切关注点,不适合替代正常的业务逻辑。过度使用会让代码难以追踪。

八、总结

AOP 的核心思想是把横切关注点从业务代码中分离出来,通过代理在运行时织入。它让业务方法保持纯净,同时获得日志、事务、权限等通用能力。

关键点说明
解决的问题横切逻辑重复、耦合高
核心概念切面、切点、通知、连接点、织入、代理
通知类型@Before、@After、@AfterReturning、@AfterThrowing、@Around
底层实现JDK 动态代理 / CGLIB
典型应用日志、事务、权限、缓存、监控
注意事项内部调用失效、切点表达式准确

理解 AOP,就理解了 Spring 为什么能在不修改业务代码的情况下,为方法添加事务、缓存、日志等能力。这是 Spring 框架最核心的设计思想之一。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 13:55:02

Flex-π——比Fast-WAM更快的多流世界-动作模型:可按需融合RGB和“从RGB中获取的3D pointmap和DINO语义”,联合生成潜在的未来视觉特征和动作

前言 过去一年&#xff0c;具身智能领域在模型架构上展开激烈范式之争 一派坚守 VLA&#xff08;视觉-语言-动作模型&#xff09;&#xff0c;认为端到端直接从图像映射到机械臂动作&#xff0c;结构精炼、推理极快&#xff0c;是高频实时闭环控制的唯一可行方案&#xff1b;…

作者头像 李华
网站建设 2026/10/3 13:52:12

开源项目可视化--一键生成架构图丨Github项目分享

开源仓库转交互式的系统架构图Diagram网页版&#xff1a; GitDiagram - Visualize Any GitHub Repository 开源仓库转换成一个结构化的、易于 AI 理解的文本&#xff0c;将代码库的原始内容完整地呈现给LLM&#xff1a; https://gitingest.com/ 开源仓库打包Repomix&#x…

作者头像 李华
网站建设 2026/10/3 13:52:11

docker-compose方式部署kafka集群(Kraft方式)——筑梦之路

# # Kafka Docker Compose 部署变量模板 # 用法&#xff1a;cp docker-compose.env.example .env 然后按需修改&#xff08;三个 compose 文件共用本文件&#xff09; # 注意&#xff1a;.env 与 compose 文件必须放在同一个目录下 # # 镜像&#xff08;Apache 官方 JVM 镜像…

作者头像 李华
网站建设 2026/10/3 13:51:19

GPT-2 训练成本从 4.3 万美元降到 48 美元?我试了一下 nanochat

2019 年训练一个 GPT-2 级别的模型 reportedly 花了 4.3 万美元&#xff1b;现在 nanochat 的 README 上写着&#xff1a;用 8 块 H100 跑大概 1 个半小时&#xff0c;成本 48 美元左右&#xff0c;就能训出一个 GPT-2 水平、还能对话的模型。spot 实例甚至可以压到 15 美元。 …

作者头像 李华