SpringBoot突报java.lang.NoSuchFieldError分析
SpringBoot项目,引了一个内部的工具包,竟然导致启动失败,报找不到freemarker Configuration类的一个属性,网上的解法都大同小异,最终用了自己的办法解决,花点时间记录下来,希望能帮助到别人。
关键词:SpringBoot,AutoConfiguration,freemarker,NoSuchFiledError
问题背景
最近在开发过程中由于要用到公司内部的一个工具类,所以添加了common-util.jar到工程的maven依赖中,功能开发完了,打算本地调试一下,但悲剧的是应用启动失败了。查看堆栈信息,并没有我新添加的代码,是Spring初始化失败了,堆栈信息如下:
初步分析
对照着堆栈来看,错误很明确,就是在运行时缺少freemarker.template.Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS 这个field导致,但是怎么解决呢?度娘上基本都是下面这两种解决办法:
图片来源于https://www.cnblogs.com/geekdc/p/9243069.html
我并没有采用这两种办法,因为这并不是一个新搭建的工程,而且我这次也没有做过任何版本升级,唯一的可能就是引入的新jar包有问题。
再看异常堆栈
从堆栈来看是缺少了一个Field导致,那什么情况下会造成这种情况呢,我第一时间猜测应该是jar包冲突了,因为之前遇到过一次,有兴趣的可以看这里,我查看了新引入jar包内部的pom文件,确实是依赖了freemarker(2.3.16)的jar包,而且scope是compile,就这样,这个低版本的freemarker被传递依赖进来了,至于最终使用哪个,就由maven的仲裁机制决定了,很明显我这个工程最终用了老版本,所以导致运行时找不到Field,解决方案很简单,使用exclusion将老版本的freemarker排除就好了。一般故事到这儿就结束了,但是我这个人手贱,偏要看看项目以前依赖的freemarker是什么版本的,结果看完又不能按时睡觉了(题外话:白天老是这事那事,晚上才有时间写代码)。
意外收获
我使用mvn dependency:tree将所有依赖都输出到文本文件里,然后搜索freemarker,结果意外的发现居然没有依赖freemarker,这是什么情况,刚刚不是还j说ar包冲突了吗,难道是自我冲突了?
一时间没有了头绪,想百度都不知道关键字写什么。一般这个时候我会点根烟开始复盘,从头到尾反复看案发现场,总能发现蛛丝马迹。终于灵光一下,我脑子里闪过这么一段话“之前没有freemarker.jar的时候不报错,现在有了也应该不报错才对,除非SpringBoot具有自动发现功能,可以实现组件可插拔”,就这样,我尝试搜索“SpringBoot自动发现”,看看百度给我的结果:
我很自然的过滤了第二条搜索内容,因为我知道那不是我想要的,我内心想表述的其实是“自动转配、自动配置”。
根因分析
了解了自动装配的大概原理后,我梳理出了这次启动失败的根本原因,如下:
- SpringBoot启动的时候触发自动配置;
- spring-boot-autoconfigure-1.5.11.RELEASE.jar\META-INF\spring.factories里面是需要自动配置的Bean,里面就有FreeMarkerAutoConfiguration;
- 自动配置一般会有一些约束条件,满足条件才会自动配置,条件通过@Condition***这类注解来声明;
- FreeMarkerAutoConfiguration的自动配置约束条件为@ConditionalOnClass({freemarker.template.Configuration.class, FreeMarkerConfigurationFactory.class}),意味着只有freemarker.template.Configuration.class, FreeMarkerConfigurationFactory.class这两个类都存在的时候才会自动配置;
- 如果第四步满足条件,最终会触发FreeMarkerConfigurationFactory.newConfiguration这个方法,这个方法内部用到了Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS这个Field,它来源于freemarker.jar,就是堆栈中报NoSuchFiledError的主角;
- 如果第四步不满足条件,就不触发FreeMarkerAutoConfiguration的自动配置,进而不会用到Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS这个Field;
FreeMarkerConfigurationFactory来源于spring-context-support-4.3.15.RELEASE.jar,这个jar包之前就依赖了,而Configuration来源于freemarker.jar,是common-util.jar传递依赖进来的,所以正好满足了上面的第四步,进而触发了第五步,最终导致SpringBoot启动失败。
汇总解决办法
通过上面的一些分析,我认为这个问题一共有以下几种办法:
- 如果你的项目中没有用到freemarker的话可以禁用freemarker的自动配置,像初步分析那里提到的;
- 升级freemarker到高版本;
- 像我遇到的问题一样,确实不需要freemarker功能,可以将freemarker.jar排除;
总结
虽然是个很小的问题,但是解决过程确实让我收获不少,之前对于SpringBoot只停留在简单使用阶段,通过这次排查过程,也算是了解了SpringBoot自动配置的大体思想,这种可插拔的设计真的是非常巧妙。
如果觉得有用,请您点个推荐。
参考资料:
https://www.cnblogs.com/nijunyang/p/12051770.html
https://blog.csdn.net/ZYC88888/article/details/84245127
最新文章
- KnockoutJS 3.X API 第八章 映射(mapping)插件
- eclipse 导入工程报错Unable to execute dex: Multiple dex files define Landroid/annotation/SuppressLint
- jsp前三章小测试:错题
- 解决WordPress中无法将上传的文件移动至wp-content/uploads
- EXCEL VBA入门篇之代码应用基础
- Java基础之创建窗口——使窗口在屏幕居中(TryWindow2/TryWindow3)
- 初始化ArrayList的两种方法
- hbase日常操作及维护
- proxy server 代理服务器
- POJ 2251 三维BFS(基础题)
- jQuery中的常用内容总结(二)
- ProgressDialog的使用及逻辑处理
- iOS开发点滴-添加阴影效果
- ArcGIS API for JavaScript 4.x 本地部署之Apache(含Apache官方下载方法)
- linux下安装nodejs及npm
- Graphics Class
- mvc开发网站打开慢总结
- DOM操作 JS事件 节点增删改查
- Pandas分组统计函数:groupby、pivot_table及crosstab
- Keras之inception_v3使用
热门文章
- 未来科技城 x 奇点云打造「企业数据大脑」,助力1.3万家企业服务
- RxJava操作符实践:8_算术和聚合操作之3_min
- 吴裕雄--天生自然HTML学习笔记:HTML 属性
- 吴裕雄--天生自然 R语言开发学习:时间序列(续三)
- java MVC 自定义类型转换器(Formatter、AnnotationFormatterFactory)
- python标准库-calendar 模块
- 吴裕雄--天生自然KITTEN编程:滂沱大雨
- Java 关于线程的面试题及答案
- TCP大文件发送案例以及UDP介绍
- Swift 进阶 第 4 课 集合类型协议