△Hollis, 一个对Coding有着独特追求的人△

这是Hollis的第 333 篇原创分享

作者 l Hollis

来源 l Hollis(ID:hollischuang)

先交代一下背景,在很久之前,我曾经封装过一个分库分表的扫表工具——Full Table Scanner,主要实现方式是通过使用TDDL Hint + 网格任务 + Mybatis Stream Query 提升性能,降低使用成本。

为了方便使用,我把他封装成了一个SpringBoot Starter,因为他提供了很好的快速扫表能力,所以被很多应用使用,并且一直都跑的好好的。

但是前两天,突然有人在钉钉上找我,说是他们应用做了改造,启动的时候报错,报错内容和我的这个工具有关。

因为一个空格

于是我开始帮忙排查这个问题,首先查看现场。主要报错信息如下:

java.lang.reflect.InvocationTargetExceptionat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at com.taobao.pandora.boot.loader.MainMethodRunner.run(MainMethodRunner.java:54)at com.taobao.pandora.boot.loader.Launcher.launch(Launcher.java:87)at com.taobao.pandora.boot.loader.Launcher.launch(Launcher.java:50)at com.taobao.pandora.boot.loader.SarLauncher.main(SarLauncher.java:171)Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [com.alibaba.fin.xxx.test.CreditXXXStartUp]; nested exception is java.lang.IllegalStateException: Unable to read meta-data for class  com.alibaba.fin.table.scanner.autoconfiguration.TDDLTableTopologyBuilderAutoConfigurationat org.springframework.context.annotation.ConfigurationClassParser.processDeferredImportSelectors(ConfigurationClassParser.java:556)at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:185)at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:308)at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:228)at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:272)at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:92)at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687)at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525)at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:134)at com.alibaba.fin.xxx.start.CreditpayXXXBootStartUp.main(CreditpayMercuryApplicationBootStartUp.java:88)... 8 moreCaused by: java.lang.IllegalStateException: Unable to read meta-data for class  com.alibaba.fin.table.scanner.autoconfiguration.TDDLTableTopologyBuilderAutoConfigurationat org.springframework.boot.autoconfigure.AutoConfigurationSorter$AutoConfigurationClass.getAnnotationMetadata(AutoConfigurationSorter.java:217)at org.springframework.boot.autoconfigure.AutoConfigurationSorter$AutoConfigurationClass.getAnnotationValue(AutoConfigurationSorter.java:198)at org.springframework.boot.autoconfigure.AutoConfigurationSorter$AutoConfigurationClass.readBefore(AutoConfigurationSorter.java:186)at org.springframework.boot.autoconfigure.AutoConfigurationSorter$AutoConfigurationClass.<init>(AutoConfigurationSorter.java:158)at org.springframework.boot.autoconfigure.AutoConfigurationSorter$AutoConfigurationClasses.<init>(AutoConfigurationSorter.java:115)at org.springframework.boot.autoconfigure.AutoConfigurationSorter.getInPriorityOrder(AutoConfigurationSorter.java:57)at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.sort(AutoConfigurationImportSelector.java:241)at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.selectImports(AutoConfigurationImportSelector.java:98)at org.springframework.context.annotation.ConfigurationClassParser.processDeferredImportSelectors(ConfigurationClassParser.java:547)... 20 moreCaused by: java.io.FileNotFoundException: class path resource [ com/alibaba/fin/table/scanner/autoconfiguration/TDDLTableTopologyBuilderAutoConfiguration.class] cannot be opened because it does not existat org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:172)at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:50)at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:98)at org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataReaderFactory.createMetadataReader(ConcurrentReferenceCachingMetadataReaderFactory.java:89)at org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataReaderFactory.getMetadataReader(ConcurrentReferenceCachingMetadataReaderFactory.java:76)at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:93)at org.springframework.boot.autoconfigure.AutoConfigurationSorter$AutoConfigurationClass.getAnnotationMetadata(AutoConfigurationSorter.java:213)... 28 more

于是我开始帮忙排查,错误信息很长,其中最关键的信息就是这句:

Caused by: java.io.FileNotFoundException:
class path resource [ com/alibaba/fin/table/scanner/autoconfiguration/TDDLTableTopologyBuilderAutoConfiguration.class] cannot be opened because it does not exist

看到这个报错,最开始的反应以为是jar包冲突了。

开始进行maven的依赖分析,发现并没有什么冲突的。

为了定位问题到底和这个Starter是否有关,我们先把关于这个工具的依赖排除掉了,之后就可以正常启动了。

基本确定一定是和这个工具的引入有关。于是开始排查这个包到底做了什么会导致应用启动失败。

排查的细节就不多说了,最终经过多方排查,我们最终发现这个问题竟然和一个空格有关。

仔细看上面的报错信息,提示找不到

[ com/alibaba/fin/table/scanner/autoconfiguration/TDDLTableTopologyBuilderAutoConfiguration.class]

有没有发现,在类前面多了个空格?

后来发现,错误信息中下面这句也更为关键:

Caused by: java.lang.IllegalStateException:
Unable to read meta-data for class  com.alibaba.fin.table.scanner.autoconfiguration.TDDLTableTopologyBuilderAutoConfiguration

仔细观察发现,这里的报错提示中TDDLTableTopologyBuilderAutoConfiguration类前面也多了个空格?

大家都知道,应用在启动的时候,会扫描classpath下面的所有spring.factories文件,并加载其中的自动配置信息。如果在加载初始化的时候遇到什么特殊的情况,应用就会启动失败。

而上面报错的TDDLTableTopologyBuilderAutoConfiguration正是我的starter的自动配置文件。

于是打开我的spring.factories,发现在TDDLTableTopologyBuilderAutoConfiguration 的配置前面,真的就多了一个空格

为了快速定位是不是这个问题,我先把这个空格删除,然后很快帮同事打了一个SNAPSHOT的包。

同事引入了我的新包之后,重启应用,发现问题解决了。

到这个地方,基本定位到了问题,就是因为我的spring.factories文件中多了一个空格,导致应用启动失败了。

但是,为什么这个问题之前没有发现呢?这次这位同事又是改了什么东西导致问题出现了呢?

问题原因分析

根据报错内容的堆栈,我们先定位到org.springframework.core.io.ClassPathResource 这个类在读取文件的时候失败了。

这个类是Spring中的一个文件读取的相关类。首先第一个想到是不是和Spring的版本有关。

于是我们快速到启动失败的应用的日常环境和线上环境分别看了一下打包之后的Spring的版本。

日常启动失败的机器中,打包后引用的Spring版本为:

$ls|grep spring-core
spring-core-4.3.13.RELEASE.jar

线上正常运行的机器中,打包后引用的Spring版本为:

$ls|grep spring-core
spring-core-4.3.22.RELEASE.jar

果然,这货是因为Spring的版本不同,和这位同学沟通后,得知他是改动了应用里面的一个包的依赖关系,那肯定是因为这个,导致了他的Spring版本仲裁关系发生了改变,从4.3.22.RELEASE降到了4.3.13.RELEASE。

先让这位同学去排查他的Spring仲裁的问题了,我继续分析,因为Spring版本不同,并且高版本没有这个问题,说明可能是一个Spring的bug,于是我尝试求助Google。

在这之前,同事的电脑浏览器默认是百度,我先用百度查询过,但是没查到,于是改用Google。

使用关键词:"spring.factories space trim"(这几个关键词很关键,spring.factories space是问题的根源,而且我觉得这一定是个被修复的bug,而且修复方式是用了trim)

很快就找到了一个相关内容,早在2018年有网友反馈过这个问题:

在这个ISSUE中,有官方人员给出了回复,这个问题在SPR-17413(https://jira.spring.io/browse/SPR-17413?redirect=false )中被修复:

其中提到,在4.3.21, 5.0.11, 5.1.2等版本中被修复,而我们的现象也确实是,线上正常运营的版本使用的是4.3.22。

顺藤摸瓜,查看一下Spring关于本次Bug修复的提交记录:

-w999

并且在他们的测试使用的spring-factories中也增加了空格,用于测试。

上面只是截图了一部分,其实这次bug修复,官方共提交了3次,涉及到43行代码的改动。他们在多处相关操作的地方,做了trim。

总结

本次问题的发生主要是因为在旧版本的Spring中,如果引入的starter中的spring.factories中配置内容中包含空格,会导致解析失败,进而导致应用启动失败。

这是一个已经被报告出来,并且也被解决了的bug。在SPR-17413中已经被修复,在高于4.3.21的版本中被修复。

其实,这篇文章的内容并不复杂,只是介绍了一个Bug,本来只是记录一下,并没什么可讲的。

但是,这个问题的排查过程还是值得学习的,有这样几个关键点:

  • 1、从报错信息本身入手。

  • 2、仔细看报错内容,不要忽略任何一个细节,哪怕是一个空格。

  • 3、学会问题猜测,猜测后再验证。

  • 4、请用Google!

参考资料:

https://github.com/spring-projects/spring-framework/issues/21946

https://github.com/spring-projects/spring-boot/issues/14903

https://jira.spring.io/browse/SPR-17413?redirect=false

往期推荐
别瞎学了,这几门语言要被淘汰了!
中国编程第一人,一人抵一城!
再见 Win10系统!下一代操作系统要来了!!直面Java第343期:为什么TOMCAT要破坏双亲委派深入并发第013期:拓展synchronized——锁优化如果你喜欢本文,请长按二维码,关注 Hollis.转发至朋友圈,是对我最大的支持。点个 在看
喜欢是一种感觉
在看是一种支持
↘↘↘

同事说他的应用起不来了,因为我的代码里面多了一个空格!相关推荐

  1. 表格对决CSS--一场生死之战

    表格对决CSS--一场生死之战 作者:阿捷 2004-7-19 21:00:54 原文作者:Sergio Villarreal 作者简介:墨西哥网页设计师,1993年接触网络,个人主页为Overcaf ...

  2. 表格对决CSS--一场生死之战 (转自“清清月儿”)

    表格对决CSS--一场生死之战 作者:阿捷 2004-7-19 21:00:54 原文作者:Sergio Villarreal 作者简介:墨西哥网页设计师,1993年接触网络,个人主页为Overcaf ...

  3. (1) 表格对决CSS--一场生死之战

    原文作者:Sergio Villarreal  作者简介:墨西哥网页设计师,1993年接触网络,个人主页为Overcaffeinated.net  原文出处:sitepoint.com  原文发表时间 ...

  4. 大佬教你怎样防止同事用 QQ 邮箱提交公司代码?

    事情是这样的,最近组里新建了一个代码仓库来开发一个新的产品,再加上今天北京下大雨很多同事选择在家工作,于是我就选择用自己的个人电脑来工作. 但我的个人电脑里面的 Git 信息是用的我自己的个人邮箱: ...

  5. 热传的职场异性相处PPT!网友评:你倒是给我分配个女同事啊!

    近日,某宇宙行内部流转的一份异性员工相处的提议书,引起了网友的轩然大波,究竟是怎么一回事呢? 提议书中提了十个平时员工相处之间需要注意的场景: 同时文中还有详细解说: 从上图中,我们可以清晰地看到,有 ...

  6. 程序猿:喜欢与聪明的同事们在一起搞软件开发

    上周我从三个哈尔姆斯塔德大学的学生那里收到一封电子邮件是关于他们做了一个三个月的项目名字叫程序员想要什么,以及企业如何吸引有才华的程序员. 这里是我自己按照重要性对于问题的几条答案.很明显,人有不同的 ...

  7. lombok依赖_公司来了个新同事不会用 Lombok,还说我代码有问题

    新来的同事不会用 Lombok,所以会引发本文! 背景 最近公司新来一个搞 Java 的同事,搞了半天项目还没有跑起来,后来叫我过去帮他看一下,然后指着红色的编译错误和我说是不是代码有问题.. 我顿时 ...

  8. 因代码不规范,码农枪击4名同事,一人情况危急

    作者 | 鱼哥 本文经授权转自鱼哥来说事 据外媒报道,来自美国的一名程序员因同事不写注释,不遵循驼峰命名,括号换行,最主要还天天git push -f 等因素枪击了4名同事,导致一人情况危急. 现在凶 ...

  9. 如何写出让同事膜拜的漂亮代码?

    "代码千万行,注释第一行:编程不规范,同事两行泪":"道路千万条,安全第一条.代码不规范,亲人两行泪."在技术圈广为盛传,可见代码不规范让程序员们是多么的头痛. ...

最新文章

  1. PyTorch中的C++扩展
  2. 【408预推免复习】计算机组成原理之CPU的结构和功能
  3. webchart= php 解码,Web Pages - Chart 帮助器
  4. svm 支持向量机 回归 预测_机器学习:简单理解支持向量机SVM
  5. pureftpd 如何修改管理员密码
  6. 未给员工足额缴纳公积金!董明珠曾豪言:每人一套房不需要公积金
  7. AI学习笔记(十一)CNN之图像识别(上)
  8. autobuddy in mfc导致的错误
  9. 在Linux中smbfs文件系统的挂载
  10. 杨校老师课堂之Hadoop环境搭建(一)
  11. 各种学习资料库,非常好的收藏汇总!!!!!
  12. php怎么解析xml,php解析xml方法实例详解
  13. 怎么把PDF转换成jpg图片?这两种方法快来get
  14. 前端页面缓存系列之localStorage
  15. android 12以上改变应用最大32进程限制方法
  16. Pandas之skew,求偏度
  17. FPGA开发——图像处理(包括MT9V034等摄像头学习笔记)
  18. html5制作奥运五环,第一讲:使用html5——canvas绘制奥运五环
  19. 一图说明什么是 java 中 pojo类
  20. BugkuCTF之web题之细心

热门文章

  1. TCP客户端服务器(Python)
  2. java.lang.math.abs_java.lang.StrictMath.abs(int a)方法实例
  3. linux查看编译器的大小端,Linux系统大小端判断
  4. Linux系统编程40:多线程之基于环形队列的生产者与消费者模型
  5. Windows下编译配置Caffe的GPU版本
  6. 1313. 解压缩编码列表
  7. USACO-Section1.3 Transformations (矩阵旋转匹配问题)
  8. Shell 判断文件或文件夹是否存在(不存在则创建)
  9. Python 获取当前时间或当前时间戳,通过时间戳获取hash
  10. Linux下的用户、组和权限的详细解释