当前位置: 首页 > news >正文

Spring Aop失效的情況及解决办法

文章目录

    • 第一种(要增强的类或方法没被spring管理)
    • 第二种(要被增强的类或方法同时被spring和springMVC扫描)
    • 第三种(要增强的方法被同类的方法调用)
      • AopContext原理
    • 第四种(用的注解方式没有开启注解支持)
    • 总结

第一种(要增强的类或方法没被spring管理)

对于传统的web项目来说,通常使用spring和springmvc,因此对于这种项目来讲,他是有两个容器的,一个是spring容器,一般我们会把Service层的东西注入到spring容器中,另一个是springmvc的容器,通常这个容器里注入的是Controller层的东西,这里我们认为spring容器是父容器,springmvc是子容器的概念,然后我们大家都知道通过父子继承关系可知,子容器是可以读取到父容器中的东西,但是父容器是无法读到子容器中的内容,因此基于这个场景,有的同学,把Aop的实现类注入到了spring容器中,并且将Aop的切点表达式配置<aop:config> <aop:pointcut的execution也配到了spring容器的xml,而巧了这位同学要切的类方法,正好是Controller,也就是springmvc容器中的东西,那么这时候问题就来了,aop在初始化时会在自己的容器中寻找能够匹配的类方法,然后给他套上一层代理,此时他在自己能够访问到的spring容器中根本找不到与之匹配的类和方法,因为这些类和方法是在springmvc容器中管理的,因此就没有代理成功
解决那么对于上述问题要怎么修改呢?只需要确保你要Aop切的类和方法与你Aop配置切点aop:config<aop:pointcut的execution表达式声明是在同一个容器中即可,此时只需要将这个配置移到springmvc容器的xml中即可

第二种(要被增强的类或方法同时被spring和springMVC扫描)

第二种情况与第一种情况有些许的类似,但并不相同,是关于重复扫描的,比如你在spring容器中配置了一个Aop,并且把他托管给spring容器管理,而且execution表达式切的也是spring容器中管理的类和方法,理论上这个时候是好用的,这批execution切到的类都被加了代理,但是巧了,springmvc容器中由于配置的是包路径扫描,恰好把execution表达式切的这一批对象又扫了一遍,又都托管给了springmvc容器,而此时扫到的这批对象,是重新new出来交给springmvc管理的,因此并没有被aop代理,所以在使用时,注入进来的可能是springmvc容器管理的这批对象,因此使用时发现Aop代理失效了
解决:这个问题的解决方案,就是避免两个容器重复扫描。

第三种(要增强的方法被同类的方法调用)

第三个问题就比较简单了,他的现象是有些方法被Aop代理成功了,但有个别方法没有代理成功,当同一个类中的方法A直接调用方法B(被注解标记)时,其本质是 this.methodB()。这里的this 指向的是原始对象本身,而不是Spring生成的代理对象,故被调用的方法没有被Aop代理,无法织入横切逻辑。
解决:举个栗子,比如A.a(),A.b()是被代理的类和方法,那么当我调用A.a()时,此时a被代理了,成功执行代理类的内容,但还没有完,a()方法中调用了自身的方法b(),此时我们以为b也会被代理类代理,但实际上并没有,因为他是自身方法调用了并不是通过代理类A调用的,在a方法中可以通过((A) AopContext.currentProxy()).b()调用,不过前提是配置上<aop:config expose-proxy="true">expose-proxy="true"是重点

AopContext原理

AopContext.currentProxy() 是 Spring AOP(面向切面编程)框架中的一个工具方法,它允许你在一个由 Spring AOP 创建的代理类中获取对当前代理对象的引用。这对于在代理对象内部需要调用其他被增强(或说被代理)的方法时特别有用,因为直接通过 this 引用调用方法可能会绕过 Spring AOP 的增强逻辑。

以下是 AopContext.currentProxy() 获取当前代理对象的原理概述:

  1. 代理对象的创建:当 Spring 容器启动并发现某个 bean 需要被 AOP 增强时,它会为这个 bean 创建一个代理对象。这个代理对象是一个实现了与原始 bean 相同接口的类,并且它会在调用方法时执行额外的 AOP 逻辑(如前置通知、后置通知、环绕通知等)。
  2. ThreadLocal 存储:在创建代理对象的过程中,Spring AOP 会将当前创建的代理对象存储在 ThreadLocal 变量中。ThreadLocal 是一个特殊的变量,它使得每个线程都有自己的一个独立的变量副本。在 AOP 的场景中,这是非常有用的,因为不同的线程可能会调用同一个代理对象的方法,而 ThreadLocal 可以确保每个线程都能够访问到自己的代理对象副本。
  3. AopContext.currentProxy():当你在代理对象内部调用 AopContext.currentProxy() 时,这个方法会检查当前线程的 ThreadLocal 变量,并返回存储在该变量中的代理对象。这样,你就可以在代理对象内部通过 AopContext.currentProxy() 获取到对自身的引用,从而调用其他被增强的方法而不绕过 AOP 的增强逻辑。

需要注意的是,AopContext.currentProxy()只在由 Spring AOP 创建的代理对象内部有效,如如果由外部调用了被AOP注解的方法就会是代理对象。如果你在一个非代理对象或者由其他方式创建的代理对象内部调用这个方法,它可能会返回 null 或者不可预期的结果。

另外,为了使用 AopContext.currentProxy(),你需要在 Spring 的配置中启用对 AopContext 的支持。这通常是通过在启动类上添加 @EnableAspectJAutoProxy(exposeProxy = true) 注解来实现的。这个注解会告诉 Spring AOP 在创建代理对象时也将代理对象存储在 ThreadLocal 中,以便 AopContext.currentProxy() 能够访问到它

第四种(用的注解方式没有开启注解支持)

这种就更好理解了,只需要开启注解支持就行了。
xml方式开启在spring配置文件添加上<aop:aspectj-autoproxy/>即可
注解方式开启在启动类上添加@EnableAspectJAutoProxy即可

总结

第一种和第二种是因为MVC分层没有用好,接收数据和业务逻辑要分开,
第三种是因为代理模式限制
第四种就是使用不当了

参考: https://blog.csdn.net/sun5769675/article/details/95187532

http://www.cnnetsun.cn/news/1308786.html

相关文章:

  • java毕业设计——基于JSP+sqlserver的网上超市设计与实现(毕业论文+程序源码)——网上超市
  • GD32E232的Modbus串口编程入门
  • PlayGround AI —— 使用图片生图器轻而易举
  • CN_GreenLumaGUI 项目常见问题解决方案
  • 如何使用 Boost.Python 实现 C++ 与 Python 的无缝桥接:完整指南
  • 10倍提升Laravel应用性能:图像优化完全指南(2025最新版)
  • 终极Grafana Dash Gen问题解决方案:从入门到精通的完整指南
  • 【开源】基于51单片机的简易智能楼道照明设计
  • 贡献者必读:如何为Its Hover图标库提交新的动画图标
  • 解决Meta Llama模型转换中的符号链接错误:3种方案让模型部署提速90%
  • Docker-Android环境变量终极指南:解锁容器化Android的全部潜能
  • RequireJS终极指南:如何构建高性能前端模块加载系统
  • YAPF性能优化终极指南:让大型Python项目格式化速度提升300%
  • Druid数据本地化终极指南:10个存储访问优化技巧
  • 终极指南:掌握dio指数退避策略,让网络请求永不失败
  • Sorcar实时更新功能详解:参数调整即时反馈的秘密
  • 掌握Hasura Backend Plus存储规则:自定义S3访问权限的实用技巧
  • blender_mmd_tools终极指南:轻松导入MikuMikuDance模型与动作
  • AICore游戏AI开发库:从零构建智能游戏角色的终极指南
  • SpringBoot 脚手架搭建指南:从零构建企业级开发框架
  • Awesome Go:终极Go语言资源宝库
  • Ostrakon-VL-8B入门必看:零售数字化转型中首个可私有部署的领域MLLM
  • Alpamayo-R1-10B作品集:不同天气条件(晴/雨/夜)下视觉鲁棒性对比
  • Qwen3-0.6B-FP8效果展示:复杂逻辑题的CoT分步推理折叠演示
  • HybridPageKit vs 传统方案:为什么它能成为新闻类App的首选框架?
  • Zed‘s community论坛功能深度探索:高效交流与问题解决的终极技巧
  • Home Assistant Glow快速上手:3步完成固件安装与Home Assistant集成
  • 原生开发的利与弊:Vanilla-Todo项目经验与最佳实践总结
  • IPED命令行帮助文档生成:自动生成帮助文档的例子
  • RAG Search API性能优化技巧:提升检索速度与结果质量的10个实用方法