花了2个钟才搞懂这AOP为啥没生效,水友却睡着了……

简介: Springboot中AOP失效的原因今天 4ye 来和小伙伴们分享一个小实战啦 ,冲冲冲~ (。・∀・)ノ实战回顾(我居然拖到现在才写了这文章…… 😵)主要是在一个周日(2020.6.6)在技术群里看到一个老哥在问“怎么用切面来捕获自定义异常?” ( ̄▽ ̄)"我当时想的是,捕获异常不是很常见的吗,平时经常用到这个全局异常捕获 ,于是就把自己 GitHub 上的小例子发给他(主要是这个 ControllerAdvice 注解),如图 👇结果老哥过了一段时候就加了我,还问我有没有空帮忙看下,还

网络异常,图片无法展示
|



SpringbootAOP失效的原因


今天 4ye 来和小伙伴们分享一个小实战啦 ,冲冲冲~ (。・∀・)ノ


网络异常,图片无法展示
|


实战回顾


(我居然拖到现在才写了这文章…… 😵)


主要是在一个周日(2020.6.6)在技术群里看到一个老哥在问


“怎么用切面来捕获自定义异常?” ( ̄▽ ̄)"


我当时想的是,捕获异常不是很常见的吗,平时经常用到这个全局异常捕获 ,于是就把自己 GitHub 上的小例子发给他(主要是这个 ControllerAdvice 注解),如图 👇


网络异常,图片无法展示
|


结果老哥过了一段时候就加了我,还问我有没有空帮忙看下,还想打电话问我,我当时的内心是


这么急的吗(瑟瑟发抖……)


网络异常,图片无法展示
|


不过刚好在外面没时间,就婉拒了,后来晚上回来,愣是花了两个钟,才看懂 为啥这个AOP 没有生效?为啥没能捕获到异常?

网络异常,图片无法展示
|


下面进入主题👉(项目整体介绍


maven项目结构图


在该项目中,maven项目采用多模块构建父子结构,由 父maven 来统一管理这些公共包,以及项目的整体版本属性配置等


里面有两个模块,starter 模块和 core 模块,其中 starter 模块依赖core 模块,整体如下图👇


网络异常,图片无法展示
|


子模块介绍


不知道小伙伴们看到上面的 starter 有没有嗅到什么 ?


一开始我以为是常见的 自定义starter ,但是里面的内容却和我想的有点出入,居然只有一个 spring.factories 文件, 很明显这里使用到了 Springboot 的 SPI 机制

这个在我们之前的 👉 Springboot自动装配原理探索 一文中有介绍到,小伙伴们可以前去了解看看~😄


对两个模块中的核心部分进行展开,结构如下👇


网络异常,图片无法展示
|


core项目描述非web项目里面只有 service ,没有启动类等


👉 由于 core 模块 不是web项目!!,所以这个 ControllerAdvice 是肯定不能用的,毕竟它是在 web 包中的,一般我们在 web项目中配合这个@ExceptionHandler(Exception.class) 实现全局异常捕获,然后进行统一处理的。


👉 从 Springboot 的 SPI 机制 中我们可以得知,Springboot 项目启动时,会去扫描各个项目中的 META-INF/spring.factories 文件(包括各个jar包),然后将其中的配置信息读取到内存中,而自动配置时会根据一定的条件对这些类进行筛选,最后创建符合的类,完成这个自动装配。


很明显,这里就是通过自动配置,来实现相关 bean 的注入。


配置类说明


那么,在了解了这些基本信息后,我们可以把目光移到这个 xxxConfig 上,这里模仿了一个👇


网络异常,图片无法展示
|


紧接着就是项目中的切面配置了,例如以前写的小例子:👇


代码在我的 GitHub


github.com/RyzeYang/sp…


通过异常通知来捕获


网络异常,图片无法展示
|


除了上面这两个之外,项目中没有用到其他配置了!


问题来了


这个时候问题就来了,在定义了切面之后,发现根本没有在项目中起作用!而其他都可以正常运行!


网络异常,图片无法展示
|


于是我一直在想,这是为啥呀,明明切面已经定义好了呀……


网络异常,图片无法展示
|


终于,我开始了尝试,在 yaml 配置文件中添加这个参数


spring:
  aop:
    auto: true
复制代码


因为在印象中,这个默认是 true ,会默认使用这个 @EnableAspectJAutoProxy , 不用我们手动去添加这个 @EnableAspectJAutoProxy 注解(之前一直没有手动添加这个注解)🐖


网络异常,图片无法展示
|


结果也没什么效果……


于是乎,我决定手动添加到刚刚那个 xxxConfig 配置类上,结果也没有什么作用……


网络异常,图片无法展示
|


终于,我才想起那个 切面配置 没有被加载到这个 Spring 中 ,于是我又在那个配置类 xxxConfig 上添加了这个包扫描注解 @ComponentScan(basePackages = "com.xxx.xxx")


结果终于成功了!


于是我赶在 23:59 将修改后的文件发给那位老哥后,却发现他居然睡着了 哈哈哈


网络异常,图片无法展示
|


网络异常,图片无法展示
|

问题剖析


解决问题后,我们可以发现这个问题就下面两点👇


  1. 没有将切面注册到 SpringIOC 容器中


  1. 没有使用这个 @EnableAspectJAutoProxy


第一步的解决也很简单,就是没有配置这个包扫描 @ComponentScan(basePackages = "com.xxx.xxx")


第二步的解决嘛,就有点一头雾水了当时,毕竟之前也不需要我手动去添加的,而且从配置的描述信息中可以发现,即使我们没有配置,他也是默认开启的,会自动使用这个注解的~


那么小伙伴们知道第二步问题的所在吗😄


网络异常,图片无法展示
|


嘿嘿,答案就出在这个自动配置 身上,可以发现我们上面都没有使用到这个 @EnableAutoConfiguration 注解,而在我们的 SpringBootApplication 组合注解中,最重要的就是它了! 通过它去开启了我们的这个自动装配


这个时候又得把这文章搬出来了 👉 Springboot自动装配原理探索 哈哈

那么我们再来看看这个 AOP自动装配的配置类


AOP自动装配的配置类


AopAutoConfiguration 源码如下👇


网络异常,图片无法展示
|


开头有这么一个条件注解


@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
复制代码


havingValue = "true" 的意思是:值为 true 时才有效


matchIfMissing = true 的意思是:没有配置这个属性时也能加载


接着让我们把目光移到第一个静态内部类: AspectJAutoProxyingConfiguration

如图👉:


网络异常,图片无法展示
|


这个我们也比较熟悉啦, proxyTargetClasstrue 时表示使用 cglibfalse 使用 JDK动态代理


接着看最后的静态内部类: ClassProxyingConfiguration


网络异常,图片无法展示
|


可以发现它这里的条件是和 AspectJAutoProxyingConfiguration 相反的,当没有这个 Advice 类时,帮我们去注册这个代理到 IOC


看完该AOP自动装配类后, 我们可以发现当我们使用 @EnableAutoConfiguration 自动装配注解时并引入 AOP 的包时,它会自动帮我们装配这个


AopAutoConfiguration ,而它里面就使用到了 @EnableAspectJAutoProxy ,所以我们一般不用手动添加该注解。


网络异常,图片无法展示
|


怎么测试


嘿嘿,再出一个小问题考考小伙伴😝


有没有细心的小伙伴发现上面的 core 模块是没有用到这个


SpringBootApplication 的,而且我们也没有用到这个


@EnableAutoConfiguration ,那么没有自动装配,这个 SPI 显然也没啥作用 ,那么,我们在项目中要怎么测试呢~


网络异常,图片无法展示
|


答案就在 单元测试的注解身上 @SpringBootTest(classes = xxxConfiguration.class)


通过这个 classes ,我们直接指定并实例化这个配置类就可以了


我也是报错了才知道 哈哈😝


网络异常,图片无法展示
|


总结


嘿嘿,老规矩,画个图总结下啦👇


排查思路


网络异常,图片无法展示
|


知识脑图


网络异常,图片无法展示
|


那么,本期就分享到这啦,喜欢的小伙伴记得点点赞呀~ 下期看看情况分享下下面某一个叭😝


  • Springboot自定义starter


  • 利用AOP实现插件


  • Spring源码


目录
相关文章
|
2月前
|
Java 程序员 容器
十分钟搞懂依赖注入
依赖注入(DI)是软件开发中的关键技术,它将类的依赖关系转移至外部管理,提升了代码的模块化和可测试性。如同炒菜时调料不由厨师直接添加,而是由调料师准备并递送,程序员只需声明所需依赖,外部机制如DI容器会负责实例化并注入这些依赖。这样,类变得更灵活且易于测试,同时也促进了代码的模块化。例如,在Java中,可以通过构造函数注入Logger接口的不同实现(如ConsoleLogger和FileLogger),使Application类与其具体实现解耦。
|
4月前
|
设计模式 黑灰产治理
三分钟带您搞懂代理模式
三分钟带您搞懂代理模式
|
5月前
|
设计模式 Java 开发者
一目了然!谁能想到Java多线程设计模式竟然被图解,看完不服不行
多线程设计模式在Java编程中起着至关重要的作用,它能够有效提高程序的执行效率,使得程序在处理大量数据和复杂任务时更加高效。然而,对于初学者来说,理解和应用多线程设计模式可能是一项相当具有挑战性的任务。为了让读者更加轻松地掌握这一复杂主题,我们带着一种全新的图解方式,深入剖析Java多线程设计模式的精髓。
|
5月前
|
XML Java 数据格式
🚀今天,我们来详细的聊一聊SpringBoot自动配置原理,学了这么久,你学废了吗?
🚀今天,我们来详细的聊一聊SpringBoot自动配置原理,学了这么久,你学废了吗?
102 0
|
12月前
|
设计模式 存储 安全
Java的第十三篇文章——JAVA多线程(后期再学一遍)
Java的第十三篇文章——JAVA多线程(后期再学一遍)
|
Java 关系型数据库 数据库连接
太难了!面试官让我结合案例讲讲自己对Spring事务传播行为的理解
Spring 在 TransactionDefinition 接口中规定了 7 种类型的事务传播行为。事务传播行为是 Spring 框架独有的事务增强特性,他不属于的事务实际提供方数据库行为。这是 Spring 为我们提供的强大的工具箱,使用事务传播行可以为我们的开发工作提供许多便利。但是人们对他的误解也颇多,你一定也听过“service 方法事务最好不要嵌套”的传言。要想正确的使用工具首先需要了解工具。本文对七种事务传播行为做详细介绍,内容主要代码示例的方式呈现。
|
缓存 监控 Java
十.Spring源码剖析-拜托面试官别再问我AOP原理了
IOC/DI , AOP 是Spring最重要的两个特性 ,也是面试高频被问到的部分,前面我们已经分析了Spring的IOC相关源码以及DI依赖注入相关源码,从本篇文章开始我们着手分析Spring的AOP源码 。 开始之前,你需要对AOP 原理,JDK动态代理,CGLIB动态代理有一定的理解。这里先上一个图,后面源码分析的时候可以看着图来
|
设计模式 运维 架构师
我懵了!架构描述是个啥玩意?
我懵了!架构描述是个啥玩意?
86 0
|
XML Java 数据格式
面试问到IOC我该如何回答呢?
相信在面试中,只要问到Spring,基本都会抛出一个问题,说说你对Spring IOC理解吧?虽然在日常的开发经常会使用到,但是要回答起来,并不简单。大脑经过简单的头脑风暴后,蹦出了控制反转、依赖注入这样的词语。显然这些并不是面试官想听的。
|
消息中间件 存储 缓存
国庆假期,整整七天,我用76张图把Spring AOP给画明白了!
国庆假期,整整七天,我用76张图把Spring AOP给画明白了!