记一次因@Async引发的程序bug
事情的起因是微服务A通过feign调用微服务B的某个接口,报了形如下的异常
负责微服务A的工程师小张就找到负责提供该接口的工程师小李,问小李是不是改动了接口,小李一脸无辜说他最近没对这个接口做任何改动,不过小李还是说道他排查一下。
小李排查的过程如下,他先通过swagger查看他提供给A服务接口是否存在,他一查发现他在swagger上看不到他提供给A服务的接口。于是他怀疑是不是有人动了他的代码,他就去查找最近的git提交记录,发现没人动他的代码,因为项目还没发布,都在测试阶段,他就根据项目集成的git-commit-id-maven-plugin插件定位到测试目前发布具体是哪个版本。(ps:对
git-commit-id-maven-plugin感兴趣的朋友,可以查看之前的文章聊聊如何验证线上的版本是符合预期的版本)。然后他将该版本的代码下到本地进行调试,他发现代码中提供给A的接口还在,target下的class也有提供给A的接口class,但诡异的是swagger就是没显示他提供出去的接口,他一度以为是swagger出了问题,于是他用postman直接请求他提供A的接口,发现报了404。然后他就叫负责同个微服务B的同事小王,也帮忙试一下,发现结果就是404。后面没招,小李就去求助他们项目资深同事小林。
小林的排查思路如下,他先走查一下小李的接口代码,发现他提供的接口实现层的方法上加了一个@Async,示例形如下
小林凭多年的经验直觉告诉小李说,应该是@Async引起。小李很斩钉截铁的说不可能啊,他@Async很早就加了,之前接口都可以访问的,小林一看小李说得那么肯定,他也不好打击小李。于是他接下来做了如下操作,先在项目中yml配置如下参数,开启springweb日志
然后在项目中加了形如下代码,来跟踪接口bean的类型
启动控制台,看日志形如下
发现确实没打印出相关requestMapping映射信息,这可以说明一点就是小李那个接口没有绑定到springmvc映射,也就是出现404的原因。接着观察控制台打印的bean,内容形如下
这很明显这个接口bean已经被jdk动态代理给替换。小李看到控制台打印的信息,若有所思,然后说,我把@Async去掉试下。小李把@Async去掉后,再观察下控制台
通过控制台可以发现,此时接口已经绑定到springmvc映射,而且打印出bean类型是真实对象bean。小李看到这个现象,也百思不得其解,他说道他之前确实是加了@Async,接口也能正常访问。于是小林就问一句,你确定你加了@Async,异步生效了吗,小李说开启spring异步,不都是加@Async吗。小林又问了一句,你在项目中开启异步,除了加@Async,还有做什么处理吗,小李说没了,他之前在项目使用异步就都是加了@Async,也能用了好好的,小林一听,基本上知道为什么小李之前@Async,接口还能正常访问了,小林为了验证想法,就问同负责该项目的小王,说你最近有加什么异步操作吗,小王说有,小林进一步问,你是怎么做的,小王说,他先加@EnabledAsyn,开启异步,然后在业务逻辑层上的方法上加@Async注解。小李一听,说原来使用@Async还要配合@EnabledAsyn啊,他之前都不知道
接着小李说 那在controller是不是就不能使用@Async注解了? ,小林说最好是把加@Async的逻辑挪到service层去处理,不过也不是controller就不能使用@Async注解了,接着小林为了验证这个想法,他把原来实现的接口类去掉,形如下
启动后,查看控制台
此时bean的类型如下
访问接口,打印内容如下
从控制台可以发现,都是http-nio-8080-exec-1线程触发,说明异步没生效,即@Async失效。后面对controller做了如下改造
访问接口,打印内容如下
这说明在controller其实也是可以用@Async,只是要额外做处理。所以建议是把@Async从controller中抽离出去,在新类中进行处理,示例如下
访问接口,打印内容
说明异步生效
从mvc日志
我们可以知道,controller映射处理是在RequestMappingHandlerMapping 这个类中,但具体是哪个方法进行处理呢,我们可以通过日志打印的信息,进行倒推,也可以基于spring的特性加断点调试,比如通过afterPropertiesSet这一启动扩展点调试起,就会发现RequestMappingHandlerMapping的映射处理是在
进行处理,具体是通过processCandidateBean进行处理
最终是通过detectHandlerMethods进行处理
这个里面就是做了实际注册。而执行detectHandlerMethods的前提是
即只有加了@Controller或者@RequestMapping的类会进行处理,而@RestController为啥也处理,点击
@RestController发现
他本质就是@Controller。但我们通过反射查找注解,正常只会查找一层,比如
他找到@RestController这一层,而不会找继续再找@RestController里面的@Controller,而AnnotatedElementUtils.hasAnnotation,这个注解方法就不一样,他是可以找到合并注解,即使是使用
@RestController,他还会继续找到里面的@Controller。因此这个方法对于找复合型注解很有用
当我们使用jdk动态代理时,因为父类上没加@Controller或者@RequestMapping,因此他不会被mvc进行映射处理,导致404。而使用cglib时,因为他是作为子类继承了目标类,因此他会继承目标类上的注解,因此当为cglib代理时,他会正常被mvc进行映射处理
这是因为加了@Async后,controller变成代理了,而当要异步处理方法,用this时,他使用的是目标对象,而非代理对象。这跟现在面试事务为啥事务失效的八股文基本是一个套路
本文主要讲@Async导致controller 404,同时也使@Async失效的原因。解决的推荐方法就是将@Async抽离出controller,新建一个service类进行处理。
出于研究的目的制作了木马程序
D或者C吧制作木马本来就不是正当行为但出发点是好的D应该是吧
打败你的从来都不是人工智能,对此你有什么态度?
并不是每一个每日在高速收费站收费的人下岗以后,做任何事情都不容易,也不是每一个在对话框办业务流程的人下岗以后也没有生活。
实际上 ,击败她们的,几乎都并不是人工智能技术。
在早期没有人工智能技术的时期,是我们饿殍遍野的老祖先时期,那一个时期,大家还只穿了一条裤头,手里边拿着石块和树技做的武器装备捕猎。此刻部落里来了2个新手,一个叫小王,一个叫小李。
由于它们是新手,部落联机出门捕猎的情况下,她们两个人只有做一些解决猎食实体线、运送猎食的协助工作中。小李在做完这件事情以后,也学着部落里边捕猎最厉害的老赵的技巧悄悄的私底下训练。小王做完了以后呢,和部落里好多个没事的人聊大天。
两年以后,发生了一群野兽,围攻了这一部落。在这次围攻中,部落里的人死的死,伤的伤,仅有具有战斗力的几个人,欣然的活了出来,再次存活,这当中就会有小李。而小王呢,在这次围攻中第一个被吞掉了。部落的老赵人老以后,小李担起了旗帜,变成这一部落里边捕猎最厉害的人,领着着部落再次存活。
N很多年以后,小王和小李转世投胎赶到了当代。变成一所985名牌大学的当期大学毕业生,她们与此同时被某公司的同一单位录用。她们的大领导是一位在领域十分杰出、在企业闯荡了十几年的刘总。
有一次,刘总公出,走以前给他与此同时安排了一项很重要的信息搜集和梳理工作中。规定她们尽量多地收集有关信息,2日内把规整好的信息文档发至他的微信上。
小王和小李全是刚来公司上班没多久,对这一领域、对企业的认识并不深。刘总没有告知她们信息收集的主要规定、方式、方式。小王有点儿不开心了,私底下跟小李说:刘总真的是得,走以前都不把此项工作中交代清晰。我们是刚大学毕业,刚来企业,只身一人的,上哪去搜集信息啊?小李淡淡笑道,说:今夜大家都回来想想办法吧。
之后,小王第二天百度了一下,把百度搜索前好几页上寻找的有关信息拷贝、黏贴了一份word文本文档,立即在微信上发送给了刘总。
小李呢,没有像小王那般心急。他找到以前在刘总单位工作中过,如今早已晋升做另一个部门负责人的马主管。询问他有关刘总分配此项工作中的观点,及其有关此项工作中的信息收集方式。马主管比较忙,一开始并不愿意理睬小李。之后小李数次拜会,乃至下午不想吃饭在马主管的公司办公室外边等他。
马主管感觉小李这一新手很积极主动,也很谦虚又很好学,有些像当初的自身,就细心地告知了小李应当找的人,最终,马主管跟小李说:我将这几个人的电话让你,我一会也会跟她们打招呼。你就说是根据我寻找它们的,她们会帮你搞到一些信息。
因此,小李逐一给他通电话联系,搜集到许多很重要的里面信息和重要信息。小李把这种信息收集好后,多花了一点时间把内容编写变成“微信公众平台”上的文图信息,消息推送给了刘总。
往后面的日巷子里,几回别的的工作计划,小王和小李都不断着相似的版式设计风格。
1年之后,刘总就把所有关键的管理性工作中交到了小李,把这些无关紧要的事务性工作都交到了小王。3年之后,小李被刘总破格提拔为这一机构的主管,变成高管,而小王仍在那边做一些相同的事情工作。5年之后,企业上新的系统软件,全部原先这些线下推广的事务性工作所有能够线上上进行。小王,因而被公司辞退员工了。而小李,由于刘总的升职,他做好了原先刘总的部位,挑动了集团公司的主梁,独当一面。
小李在电脑上设计了一个有理数运算程序:输入a,加*键,再输入b,得到运算a*b=a^2-b^2-[2(a^3-1)-1/b]/(a-
1.解:因为a*b=a^2-b^2-[2(a^3-1)-1/b]/(a-b),
所以(-2)*(1/2)
=(-2)^2-(1/2)^2-{2×[(-2)^3-1]-1/(1/2)}/[-2-(1/2)]
=11/3-8
=-(13/3)
2.解:因为a^2-b^2-[2(a^3-1)-1/b]/(a-b)无法执行,
所以a=b或b=0
电脑开机时一直重复启动,进不了系统页面。
电脑重复自动重启会因以下几种原因引起:
一、软件方面
1.病毒
“冲击波”病毒发作时还会提示系统将在60秒后自动启动。
木马程序从远程控制你计算机的一切活动,包括让你的计算机重新启动。
清除病毒,木马,或重装系统。
2.系统文件损坏
系统文件被破坏,如Win2K下的KERNEL32.DLL,Win98 FONTS目录下面的字体等系统运行时基本的文件被破坏,系统在启动时会因此无法完成初始化而强迫重新启动。
解决方法:覆盖安装或重新安装。
3.定时软件或计划任务软件起作用
如果你在“计划任务栏”里设置了重新启动或加载某些工作程序时,当定时时刻到来时,计算机也会再次启动。对于这种情况,我们可以打开“启动”项,检查里面有没有自己不熟悉的执行文件或其他定时工作程序,将其屏蔽后再开机检查。当然,我们也可以在“运行”里面直接输入“Msconfig”命令选择启动项。
二、硬件方面
1.机箱电源功率不足、直流输出不纯、动态反应迟钝。
用户或装机商往往不重视电源,采用价格便宜的电源,因此是引起系统自动重启的最大嫌疑之一。
①电源输出功率不足,当运行大型的3D游戏等占用CPU资源较大的软件时,CPU需要大功率供电时,电源功率不够而超载引起电源保护,停止输出。电源停止输出后,负载减轻,此时电源再次启动。由于保护/恢复的时间很短,所以给我们的表现就是主机自动重启。
②电源直流输出不纯,数字电路要求纯直流供电,当电源的直流输出中谐波含量过大,就会导致数字电路工作出错,表现是经常性的死机或重启。
③CPU的工作负载是动态的,对电流的要求也是动态的,而且要求动态反应速度迅速。有些品质差的电源动态反应时间长,也会导致经常性的死机或重启。
④更新设备(高端显卡/大硬盘/视频卡),增加设备(刻录机/硬盘)后,功率超出原配电源的额定输出功率,就会导致经常性的死机或重启。
解决方法:现换高质量大功率计算机电源。
2.内存热稳定性不良、芯片损坏或者设置错误
内存出现问题导致系统重启致系统重启的几率相对较大。
①内存热稳定性不良,开机可以正常工作,当内存温度升高到一定温度,就不能正常工作,导致死机或重启。
②内存芯片轻微损坏时,开机可以通过自检(设置快速启动不全面检测内存),也可以进入正常的桌面进行正常操作,当运行一些I/O吞吐量大的软件(媒体播放、游戏、平面/3D绘图)时就会重启或死机。
解决办法:更换内存。
③把内存的CAS值设置得太小也会导致内存不稳定,造成系统自动重启。一般最好采用BIOS的缺省设置,不要自己改动。
3.CPU的温度过高或者缓存损坏
①CPU温度过高常常会引起保护性自动重启。温度过高的原因基本是由于机箱、CPU散热不良,CPU散热不良的原因有:散热器的材质导热率低,散热器与CPU接触面之间有异物(多为质保帖),风扇转速低,风扇和散热器积尘太多等等。还有P2/P3主板CPU下面的测温探头损坏或P4 CPU内部的测温电路损坏,主板上的BIOS有BUG在某一特殊条件下测温不准,CMOS中设置的CPU保护温度过低等等也会引起保护性重启。
②CPU内部的一、二级缓存损坏是CPU常见的故障。损坏程度轻的,还是可以启动,可以进入正常的桌面进行正常操作,当运行一些I/O吞吐量大的软件(媒体播放、游戏、平面/3D绘图)时就会重启或死机。
解决办法:在CMOS中屏蔽二级缓存(L2)或一级缓存(L1),或更换CPU排除。
4.AGP显卡、PCI卡(网卡、猫)引起的自动重启
①外接卡做工不标准或品质不良,引发AGP/PCI总线的RESET信号误动作导致系统重启。
②还有显卡、网卡松动引起系统重启的事例。
5. 并口、串口、USB接口接入有故障或不兼容的外部设备时自动重启
①外设有故障或不兼容,比如打印机的并口损坏,某一脚对地短路,USB设备损坏对地短路,针脚定义、信号电平不兼容等等。
②热插拔外部设备时,抖动过大,引起信号或电源瞬间短路。
6.光驱内部电路或芯片损坏
光驱损坏,大部分表现是不能读盘/刻盘。也有因为内部电路或芯片损坏导致主机在工作过程中突然重启。光驱本身的设计不良,FireWare有Bug。也会在读取光盘时引起重启。
7.机箱前面板RESET开关问题
机箱前面板RESET键实际是一个常开开关,主板上的RESET信号是+5V电平信号,连接到RESET开关。当开关闭合的瞬间,+5V电平对地导通,信号电平降为0V,触发系统复位重启,RESET开关回到常开位置,此时RESET信号恢复到+5V电平。如果RESET键损坏,开关始终处于闭合位置,RESET信号一直是0V,系统就无法加电自检。当RESET开关弹性减弱,按钮按下去不易弹起时,就会出现开关稍有振动就易于闭合。从而导致系统复位重启。
解决办法:更换RESET开关。
还有机箱内的RESET开关引线短路,导致主机自动重启。
8. 主板故障
主板导致自动重启的事例很少见。一般是与RESET相关的电路有故障;插座、插槽有虚焊,接触不良;个别芯片、电容等元件损害。
三、其他原因
1.市电电压不稳
①计算机的开关电源工作电压范围一般为170V-240V,当市电电压低于170V时,计算机就会自动重启或关机。
解决方法:加稳压器(不是UPS)或130-260V的宽幅开关电源。
②电脑和空调、冰箱等大功耗电器共用一个插线板的话,在这些电器启动的时候,供给电脑的电压就会受到很大的影响,往往就表现为系统重启。
解决办法就是把他们的供电线路分开。
2.强磁干扰
不要小看电磁干扰,许多时候我们的电脑死机和重启也是因为干扰造成的,这些干扰既有来自机箱内部CPU风扇、机箱风扇、显卡风扇、显卡、主板、硬盘的干扰,也有来自外部的动力线,变频空调甚至汽车等大型设备的干扰。如果我们主机的搞干扰性能差或屏蔽不良,就会出现主机意外重启或频繁死机的现象。
3、交流供电线路接错
有的用户把供电线的零线直接接地(不走电度表的零线),导致自动重启,原因是从地线引入干扰信号。
4.插排或电源插座的质量差,接触不良。
电源插座在使用一段时间后,簧片的弹性慢慢丧失,导致插头和簧片之间接触不良、电阻不断变化,电流随之起伏,系统自然会很不稳定,一旦电流达不到系统运行的最低要求,电脑就重启了。解决办法,购买质量过关的好插座。
5. 积尘太多导致主板RESET线路短路引起自动重启。
四、部分实例
1. CPU二级缓存坏的实例
一台几年前配置的兼容机:K6-2 200MHzCPU,采用VX-Pro+芯片组的主板,两根16MB 72线EDO内存,
Windows 98操作系统。在出现蓝天白云画面后自动重启,安全模式同样无法进入,只能进入MS-DOS模式。笔者猜想由于内存条质量问题导致电脑重启的可能性较大,所以首先更换同型号内存条测试,故障依旧。再更换电源仍无法解决问题。排除到最后只剩下主板、CPU和显卡,试过显卡没有问题后,苦于找不到能安装K6-2 200MHzCPU的旧主板只能作罢。
当时也怀疑过BIOS设置可能有误,试过恢复到缺省值,也未能解决问题。过了几天,再次摆弄电脑时,无意进入BIOS并将CPU Internal Cache一项设为Disable,保存退出后重启,系统竟然可以启动了!由此估计应当是CPU的缓存有问题,于是再将缓存设置为打开状态并启动电脑,果然系统又不能正常启动了。由于将缓存关闭后大幅度降低了CPU的性能,所以Windows 98在启动和运行程序时比以往慢了许多,最后换了一块CPU才算解决问题
2. 电源故障的实例
笔者上班的地方计算机每天都要开着(因为上网的人多),十天半月不关机是常事。在如此高的工作强度下,硬件设备的故障率也很高。
故障现象:两台兼容机,一台CPU为Athlon XP 1700+,一台CPU为P4 1.7GHz,主机电源均为世纪之星电源。当计算机处于满负荷状态运行一段时间后(此时CPU使用率保持在100%,硬盘也在大量读写数据),经常性地自动重启。其中一台在挂接一块60GB硬盘和一块80GB硬盘时,出现供电不足的现象。
故障分析处理:由于这两台计算机平时用于文档编辑、上网等一般工作时正常,只有进行大量计算时才出问题。开始怀疑是CPU温度过高所致,但检测表明温度正常。检查硬盘发现,其中一块硬盘出现了坏道,但是在更换硬盘重装系统后故障依旧,看来硬盘出现坏道很可能是计算机经常非正常重启导致的。在更换新电源后,故障消失。
拆开两个旧电源,发现其中一个电源的两个相同型号的电解电容(3300μF/10V)顶端有黄褐色的颗粒状凝结物,另一个电源的两个不同型号的电解电容(1000μF/16V,3300μF/16V)顶端也有黄褐色的颗粒状凝结物,这是电容被击穿漏液所导致的。在电子市场花钱购买了相同型号的电容更换后,经测试均恢复正常。这里提醒一下,千万别把电容正负极接反了!事后分析发现,笔者单位电网常因检修或用电不当突然停电,导致配件上的电容被击穿,一块主板也曾经在一次突然停电后罢工,检查发现几个大电解电容被击穿漏液,更换电容后恢复正常。
3. 显卡接触不良的实例
故障现象:朋友电脑配置为明基BenQ 77G的显示器、技嘉8IRX的主板、P4 1.6G CPU、80G硬盘、小影霸速配3000显卡、全向极云飞瀑内猫、主板自带AC97的声卡。因装修房子,要挪动电脑,就把电脑后的连线都拆了。后来自己接好线后,电脑却怎么也启动不起来了。电脑自检正常,闪过主板LOGO后,出现WINDOWS 98启动画面,接着光标闪动,一切很正常,可是约摸着快要进入系统的时候,电脑突然“嘀”的一声重启动了,重新启动几次都是这样。
故障分析:笔者的这位朋友是个纯纯的“菜鸟”,初步判断可能是一般性的接线问题,很有可能是鼠标和键盘接反导致的。先是检查了一遍电脑接线,没有问题,会不会是接线松动呢?重新把所有电脑连线接了一遍
故障依旧。启动时选安全模式能进入系统,运行也正常,重启后进入BIOS里查看CPU温度,在正常范围内,排除因CPU过热导致的重启。朋友也没安装新的硬件,故排除电源供电不足导致重启现象。引起故障的原因可能有以
下四个方面:一是软件冲突;二是显示分辨率或刷新率设置高于额定的值;三是显卡和其它硬件冲突、或驱动程序问题导致;四是显卡故障。
故障排除:问朋友发生故障前对机器进行了哪些操作?朋友说拆机前一直都用的很好,没有安装过新软件。没有蛛丝马迹,只有从上面的四个可能的故障原因里排查。重启后,进入安全模式,运行msconfig命令,把启动项里不是操作系统所必需的项都去掉,重启后,故障依旧。看来不是软件安装导致的。接下来看看是不是分辨率和刷新率过高,在安全模式下,将监视器删除,重启动,故障依旧。最后问题都集中在显卡身上了。再次进入安全模式,删除显卡驱动程序,重启动后,跳过显卡驱动安装,能进入正常启动模式,看来故障是驱动程序的问题或显卡与其它硬件冲突引起的了。下载一个新的驱动看能不能解决这个问题呢?拨号上网,机器突然又重启了,难道猫也坏了吗?这可怎么办,真的山穷水复了吗?这台电脑是因为拆了以后就启不起来了,显卡和猫总不会因搬一下机器就坏了吧?想到搬运机器,是不是因为拆装电脑时把显卡碰松导致接触不良而引起的故障呢?抱着最后试一试的心理,打开机箱,将显卡和猫拔出重新插紧安好,装好显卡驱动,重启,竟然看到美丽的桌面了,试着拨号,也没问题了,故障排除了。原来故障是显卡接触不良的导致。
小结:以上显卡接触不良导致电脑不能进入系统故障,现象有点类似显卡故障的症状,如果不从细小问题入手,还真难一时半会解决,甚至会怀疑是硬件故障,而大费周折。
0条大神的评论