AOP 为啥没生效?花了 2 个钟才搞懂!

Posted Java技术栈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AOP 为啥没生效?花了 2 个钟才搞懂!相关的知识,希望对你有一定的参考价值。

点击关注公众号,Java干货及时送达

在技术群里看到一个老哥在问“怎么用切面来捕获自定义异常?” ( ̄▽ ̄)"

我当时想的是,捕获异常不是很常见的吗,平时经常用到这个全局异常捕获 ,于是就把自己 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 上,这里模仿了一个????

Spring Boot 基础教程和实战源码推荐:????

https://github.com/javastacks/javastack

通过异常通知来捕获

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

问题来了

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

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

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

spring:
 aop:
    auto: true

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

结果也没什么效果……

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

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

结果终于成功了!

问题剖析

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

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

  2. 没有使用这个 @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 ,我们直接指定并实例化这个配置类就可以了

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

总结

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

排查思路

知识脑图

那么,本期就分享到这啦,喜欢的小伙伴记得点点赞呀~



关注Java技术栈看更多干货

获取 Spring Boot 实战笔记!

以上是关于AOP 为啥没生效?花了 2 个钟才搞懂!的主要内容,如果未能解决你的问题,请参考以下文章

为啥在aop里面的事务不生效

花了快一天,才搞出来的一个client-go的demo

用Kotlin开发了一个Android应用,我只用了8小时

一文搞懂Spring AOP源码底层原理

windows 为啥设置了环境变量没生效

这一次搞懂Spring代理创建及AOP链式调用过程