@Around踩坑记录

news/2024/4/20 16:22:49/

@Around踩坑记录

先上结论:

如果你在定义切面的时候打算使用环绕通知➕定义注解的方式,那么在进行*@Around*("(@annotation(costTrace))") 类似这样的定义的时候,”costTrace“一定要与你定义切面中入参的参数名字一致,而不是参数类型(你定义的注解名字)一致.

1. 背景

在完善自己暑期实习项目的过程中,发现自己在业务逻辑中花了大量的篇幅去打一些和方法耗时计算相关的日志,于是在优化的过程中,第一步便是利用切面编程的思想将这些计算耗时的日志代码通过切面的方式,悄无声息的侵入,把代码篇幅都留给业务逻辑,而不是这些千篇一律的日志打印。

在这里,我通过传统的 (自定义注解 ➕ spring AOP 切面)的方式进行,以下是我的初始版本⬇️

1.1 引入依赖与定义配置


<dependency> <groupId>org.aspectj</groupId>  <artifactId>aspectjrt</artifactId> 
</dependency>  
<dependency> <groupId>org.aspectj</groupId>  <artifactId>aspectjweaver</artifactId> 
</dependency>

spring的xml配置文件中定义:

<aop:config proxy-target-class="true"/>
<aop:aspectj-autoproxy/>

1.2 自定义注解

/*** @author kaihua* @describe : 被该注解标记,将被进行代价计算与日志打印* @date 2023/7/4*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD })
public @interface CostTrace {String value() default "";}

1.3 定义切面

/*** @author kaihua* @describe* @date 2023/7/4*/
@Aspect
@Component
public class CostTraceAspect {/*** CostTrace 切面* @param joinPoint : 切点* @param costTrace : 方法注解* @return : 返回值*/@Around("(@annotation(CostTrace))")public Object handleJoinPoint(ProceedingJoinPoint joinPoint, CostTrace costTrace) {//1. 获取切入点方法信息MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();String className = methodSignature.getDeclaringType().getName();String methodName = methodSignature.getName();String costTraceInformation = costTrace.value();Object[] args = joinPoint.getArgs();String requestStr = JSON.toJSONString(args);//2. 定义方法开始时间long begin = System.currentTimeMillis();Object result = null;try {//3. 执行方法result = joinPoint.proceed(args);//4.1 方法执行完毕之后打印日志LoggerManager.info(String.format("the method %s of class %s execution successful, the input parameters are %s, the total time consumption is %dms, the other information: %s", methodName, className, requestStr, System.currentTimeMillis() - begin, costTraceInformation),"","100");} catch (Throwable e) {e.printStackTrace();//4.2 方法若执行失败打印日志LoggerManager.error(String.format("the method %s of class %s execution error, the input parameters are %s, the other information: %s", methodName, className, requestStr, costTraceInformation),"",e);}return result;}
}

2. 问题的出现

在预发环境部署的过程中出现了如下报错

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dependencyTypeHolder' defined in URL [jar:file:/home/admin/taefileserver/target/taefileserver.war/WEB-INF/lib/ateye-client-2.3.8.jar!/ateye-scene.xml]: BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.config.internalTransactionAdvisor': Cannot resolve reference to bean 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0' while setting bean property 'transactionAttributeSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0': BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0': Cannot resolve reference to bean 'cursitor-pointcut' while setting bean property 'pointcut'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cursitor-pointcut' defined in class path resource [spring-cursitor.xml]: BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#1': Cannot resolve reference to bean 'jmonitor-pointcut' while setting bean property 'pointcut'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jmonitor-pointcut' defined in class path resource [jmonitor-spring.xml]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 formal unbound in pointcut

报错非常长,但是通过控制变量法(通过部署前后的日志变化比较,不推荐,,最笨的方法)以及读取日志内容(推荐,但是有时候难以排查问题)发现,日志中pointcut的字眼,并且报错的本质原因是bean容器初始化失败,那必定是某个bean的定义出现了问题。

结合自己新添加的代码,发现只有自己定义的切面被标注了@Component,便把问题锁定在切面中了,但是这段代码乍一看,并没有什么错误,就是一个非常简单的环绕通知定义。

3. 问题的排查

通过复制日志报错搜索解决方案显然不太可行,后面专门去搜索了@Around配合注解如何去进行定义,终于在廖雪峰老师的网站看到了答案.

👉 https://www.liaoxuefeng.com/wiki/1252599548343744/1310052317134882

请添加图片描述

我又重新尝试修改了自己定义的切面的代码,进行部署,终于成功了!!

但是我这里还是不明白,为什么不能够使用注解类型,非要去使用对应的注解参数名字呢?

在一番搜索和chatGpt battle大战之后,大概搞清楚了原因:

**“在使用 @annotation 拦截注解时,需要获取到该注解的属性值,而注解的属性值是在注解对象中定义的,而不是在注解类型中定义的。因此,在 @annotation 中传入注解对象,可以获取到注解的属性值。”**

4. 解决方法的证实

我将切面的@Around定义分别换为了两个版本,结果都可以部署成功,基本可以证明了这个做法的正确性。

// version 1
@Around("(@annotation(costTrace))")
public Object handleJoinPoint(ProceedingJoinPoint joinPoint, CostTrace costTrace)// version 2
@Around("(@annotation(cos))")
public Object handleJoinPoint(ProceedingJoinPoint joinPoint, CostTrace cos)

5. 小结

虽然这个只是一个非常非常非常小的排查问题案例,但是还是不由得产生非常多的感悟:

“作为一个臭写代码的程序员,我们所谓的学习,只是在学习其他人定义的规则,最典型的就是开发过程中的各种框架,我们在不断的学习别人定下来的规则。虽然这个现实是绝望的,但是我们也要从中有所收获,我们今天了解了这个规则,并不应该仅仅停留于学习到了这个规则,更可贵的是要去尝试去思考规则制定者在制定规则时候的思考”


http://www.ppmy.cn/news/797144.html

相关文章

羊驼再度进化,“长颈鹿版”LongLLaMA 来啦,上下文长度冲向 100K ,性能不减

文 | 小戏、ZenMoore 要说当下制约大模型释放更大规模潜力的桎梏&#xff0c;除了机器幻觉&#xff0c;肯定当属受限的上下文长度&#xff0c;前两天微软的 LongNet 正将 Transformer 的上下文长度扩展到夸张的 10 亿量级&#xff0c;这两天撑起了开源大模型一片天的 LLaMA 家族…

spring10-配置数据元

他的作用是提高我们程序性能的&#xff1a;我们怎么用呢&#xff01;先创建我们数据源对象&#xff1a;创建初始化对象之后&#xff0c;创建数据源对象之后&#xff0c;会给我们一些初始化资源。 使用完后还给他 &#xff0c;这是一种环保的思想。 常见的数据源&#xff1a;底…

爬虫反反爬

目录 为什么要反爬&#xff1f; 经常被反爬的主要人群 常见的反爬策略 通过headers字段来反爬 通过headers中的User-Agent字段来反爬 通过referer字段或者是其他字段来反爬 通过cookie来反爬 通过请求参数来反爬 通过从html静态文件中获取请求数据(github登录数据) 通…

能打开共享打印机但是无法连接

已经打开了共享&#xff0c;看到方电脑共享的打印机&#xff0c;但是无法连接 有说要去除更新的&#xff0c;有说改注册表&#xff0c;重启打印服务的&#xff0c;都试了还是不行 后来发现还是要在windows 管理凭据里面将凭据进行添加进去&#xff0c;或者一开始打开共享的时候…

Windows打印机共享相关问题

1.存在多个副本删除不了&#xff0c;或者打印机有黄色感叹号 可删除此文件夹下的内容 解决方法&#xff1a;删除打印机后&#xff0c;选中一个设备&#xff0c;选择打印机属性&#xff0c;删除副本打印机对应的驱动程序和系统安装包。 2.打印机驱动下载 解决方法&#…

Win10系统更新后共享打印机无法打印

如果共享打印机突然不打印或者连不上 试试把这些win10的补丁卸载重启 卸不掉就更新补丁再卸&#xff0c;多试几次 再不行试试用cmd卸或者注册表改值 网上的办法我都试个遍&#xff0c;终于整好了 最后记得禁止系统更新&#xff08;我上次就忘了&#xff09;!

WIN10系统无法连接共享打印机,0x000000400错误完美解决方法;0x00000709错误完美解决方法

win10&#xff0c;win11强行推送更新的补丁将会导致同一个局域网内共享打印机无法正常使用&#xff0c;添加打印机会报错0x00000040或者0x00000709的问题&#xff0c;有些版本的系统是可以在更新补丁里面卸载&#xff0c;重启一下就可以了。但是有些windows版本没办法卸载更新补…

win10、11共享打印机报错无法连接到打印机

大多数是windows更新补丁导致的&#xff0c;只需运行相应版本的的bat文件就可以解决。 使用方法&#xff1a;将下载好的压缩包解压&#xff0c;并运行bat文件。只要打了2021年10月补丁的电脑都需要运行&#xff0c;不管是服务端还是客户端。比如服务端是xp&#xff08;xp不存在…

【云原生】安装AWS NLB Load Balancer Controller1.8

AWS 的ALB不支持规则重写&#xff0c;所以需要使用nginx ingress绑定AWS的NLB来实现 NLB的优势&#xff1a; 所有命名空间可以共用一个NLB 1、安装 参考官网地址&#xff1a;https://kubernetes.github.io/ingress-nginx/deploy/#aws 2、注释说明 1&#xff09;入口卸载S…

连接共享打印机提示没有权限使用网络资源

连接共享打印机提示没有权限使用网络资源 我们在做桌面运维的过程中经常会遇到这样的情况&#xff0c;局域网内连接共享打印机提示没有权限使用网络资源&#xff0c;这应该如何解决呢&#xff1f;经过以下几步设置&#xff0c;基本能解决所有连接不上共享打印机的问题&#xff…

geotools读取shp数据

读取shp pom依赖 <dependency><groupId>org.geotools</groupId><artifactId>gt-main</artifactId><version>${geotools.version}</version></dependency><dependency><groupId>org.geotools</groupId><…

程序包不存在 单独引那个包

哪个模块的依赖导不进去 单独右键服务 找到maven reload 在IDEA中使用Jedis操作redis出现 build运行报错&#xff0c;出现“程序包不存在&#xff0c;找不到符号”问题 原因分析&#xff1a; idea自身的原因 解决方案&#xff1a; 在terminal中执行这个命令mvn idea:idea

神舟微型计算机 mini pcs-b 更换系统

mini pcs-b 更换系统 朋友拿来一台奇怪的电脑主机让我维修&#xff0c;如图&#xff1a; 只有巴掌大小&#xff0c;真是开眼了&#xff0c;再上几张图欣赏一下&#xff1a; 这是放固态硬盘的地方&#xff0c;但是没见到硬盘 打开顶盖&#xff0c;主板&#xff0c;硬盘&…

Windows10神州网信版的远程桌面开启

在XP和Windows7中&#xff0c;开启远程桌面并不复杂&#xff0c;到了Windows10略有不同&#xff0c;对于Windows10的神州网信版来说&#xff0c;就复杂了。 默认情况下&#xff0c;远程桌面是不开启的。 要开启神州网信版的Windows10远程桌面 &#xff0c;需要下列步骤&#xf…

Nodejs之Buffer和path使用说明

Buffer&#xff08;缓冲器&#xff09; 1.概念 Buffer是一个类似于数组的对象&#xff0c;用于表示固定长度的字节序列 Buffer本质是一段内存空间&#xff0c;专门用来处理二进制数据。 2.特点 Buffer大小固定且无法调整Buffer性能较好&#xff0c;可以直接对计算机内存进…

正则表达式 | 组合

组合是一对小括号里包含子表达式组成一个整体类似于数学意义上的一对小括号。 0x00 语法 (子表达式) 0x01 例子 (1)对字符串abcabcabc只匹配abc字符串两次&#xff1a; 表达式(abc){2}结果&#xff1a;abcabc (2)对下列字符串匹配类似于IP格式的字符串: abc.abc.abc 192.…

数字电路反相器符号_数字电路知识总结

数字电路知识总结 一、数制与码制... 2 1、 二进制、八进制、十进制、十六进制转换... 2 2、 原码、反码、补码... 2 3、BCD码(8421码)、余三码、格雷码(循环)... 2 二、逻辑代数... 2 1.基本运算:与或非... 2 2.基本定理:代入,反演,对偶... 2 3.化简方法:真值表,公式法,卡…

【数字信号处理】数字信号处理简介 ( 数字信号处理技术 | 傅里叶变换 )

文章目录 一、数字信号处理技术二、傅里叶变换 ( 时域转频域 ) 一、数字信号处理技术 数字信号处理 ( DSP , Digital Signal Processing ) 是 信息学科 和 计算机学科 结合产生的一门新的学科 , 核心是 使用 数值计算的方法 , 完成对信号的处理 ; DSP 有两种理解 : Digital S…

有意思的数字运算组合

该篇文章是我于2009年6月10日通过自己编写的工具&#xff0c;批量从位于在博客园的博客站点(http://chenxizhang.cnblogs.com)同步而来。文章中的图片地址仍然是链接到博客园的。特此说明&#xff01; 陈希章 原文地址&#xff1a;http://www.cnblogs.com/chenxizhang/archive/…

python 用print输出字符串和数字的组合_Python字符串拼接(包含字符串拼接数字)...

我们见过书写字符串的一种特殊方式,即直接将两个字符串紧挨着写在一起,这样的话 Python 就会自动拼接它们,比如说:s1 = "Hello,"Charlie print(s1) 上面代码将会输出:Hello,Charlie 其实,这种写法只是书写字符串的一种特殊方法,并不能算是真正意义上的拼接字符…