SpringBoot 1.X到2.X 升级的一些思考总结
1. 为什么要升级
- 支持最新的Java9(虽然目前的项目还没有用到Java9,但未来升级到Java9的可能性会很高)。
- 基于Spring5构建,Spring5的各种新特性均可以在这里使用。
- 为各种组件的响应式变成提供自动化配置(虽然我们没有用到,但使用这些组件的人用起来会更顺畅)。
- 支持SpringMVC的非阻塞式替代方案WebFlux以及嵌入式NettyServer。
- 最重要的还是目前的项目依赖还比较简单。如果现在不升级,随着依赖数的增加、版本跨度增加,再升级依赖就会更加困难。
2. 升级用到的工具
2.1 mvn命令
在排查依赖间影响的时候,最常使用的还是mvn命令。
2.1.1 mvn基本命令
如果要查看当前的依赖树,可以使用以下命令。
mvn dependency:tree
2.1.2 mvn查看重复忽略的依赖
如果要查看maven如何解决包冲突,即查看重复的、被忽略的依赖,可以使用以下命令:
使用上述命令后,会看到有些依赖上会有额外的信息。他们的含义分别是:
- 最后写着compile的就是编译成功的。
- 最后写着omitted for duplicate的就是有jar包被重复依赖了,但是jar包的版本是一样的,该行依赖被忽略。
- 最后写着omitted for conflict with xxxx的,说明和别的jar包版本冲突了,而该行的jar包不会被引入。
- 最后写着version managed from xxx ;omitted for duplicate ,表示虽然pom依赖中写明是依赖xxx,但当前项目明确指定使用该行前面的版本,最终由于版本重复当前行被忽略。
- 最后写着version managed from 1.16.8 ;表示虽然pom依赖中写明是依赖xxx,但当前项目明确指定使用该行前面的版本。
2.1.3 mvn指定或排查特定依赖
大型项目中,由于依赖众多,当使用上述命令后,查看的信息会特别多。因此可以使用以下命令,在查看依赖情况时指定要查看或过滤的包。
指定查看的包:
mvn dependency:tree -Dverbose -Dincludes=org.springframework:spring-tx
指定排除的包:
mvn dependency:tree -Dverbose -Dexcludes=com.google.guava:guava
过滤串使用groupId:artifactId:version的方式进行过滤,可以不写全。
2.2 maven仓库
查看公有包可以访问 MvnRepository ,当你需要升级依赖的时候,可以在这个网站上查看想升级版本的包的最新版本信息。
3. 升级中可能遇到的问题
依赖版本升级可能会遇到以下几种问题,假设我们有A/B/C/D等包。
3.1 多个依赖连续升级
假设在A包中有一个类ClassA,被B包引用。由于升级,ClassA改了路径或名称、或者由别的类代替。那么B包也需要升级,以匹配A包升级。同样的,如果B包中的类被C包依赖,C包也需要升级。在这个过程中,如果B包的版本中没有适配A包最新版本的话,可以尝试在代码中重写一个旧的ClassA,让B包能够用上。如果改动是在太大,那么建议还是别把A的版本升的太高。
3.2 新版本依赖项减少
假设在A包中,原先有依赖google-guava包,然后我们自然而然地用了guava包中的类。在A包升级后,它去掉了对google-guava的依赖,那我们的项目可能就会报错了。这里建议凡是在业务代码中用到的第三方包,都在pom中指明依赖。
3.3 所升级包管理混乱
不知道大家有没有遇到过包版本混乱的情况?我遇到过,在
2018-01
版本中,某些接口可以使用,在
2018-02
版本中又不可以。你以为他的包版本规则是按照日期产出的,结果又出来一个
1.2.10
版本。总之,包的开发者对包的管理存在一定的问题,这个时候,最好和包管理者进行沟通,确认可用版本。
3.4 升级后配置发生改变
所省级包中的某些类在升级后,入参、属性发生变化,从而导致代码或配置报错。
在springboot1x升级2x时,有很多在application.properties中的配置key也会发生变化。一般情况下,根据idea的提示修改即可。
在springboot1x升级2x时,HttpMessageConverters从web模块迁移至了http模块,如果有使用
HttpMessageConverters
这个类,就需要做一下调整。WebMvcConfigurer的跨域配置,原先只需要调用addMapping方法即可,升级后就需要指定allowCredentials了。
3.5 升级后的框架代码逻辑冲突
假设A是一个框架包,某个接口允许有一个实现。结果在升级B/C包后,B/C包都实现了这个接口。在编译时,没有任何问题,但运行时,A框架发现有两个实现,所以会报错。 此时,需要查看B,C包在升级后,是否还同时需要,如果不同时需要,则只要去掉其中一个依赖即可。如果同时需要,则需要联系包管理者进一步解决冲突。
4. 升级后可能遇到的问题
在升级完包依赖后,需要我们进一步观察升级对生产造成的影响。一般来说,可能会有以下这些问题。
4.1 bug修复引发的bug
在我们的代码中,玩的6的人总喜欢用一些奇奇怪怪的高级方法,例如反射取一下私有属性等等。但随着依赖包的升级,有些私有属性消失了或bug被修复了,我们代码中的一些高级用法就会失效,严重者甚至会引起线上问题。
4.1.1 mybatis升级带来的问题
大家都用过mybatis吧,在if的test中写入这种语句
for_test == null or for_test='' or for_test == -1
。在特定版本之前,由于ognl的bug,等同于
for_test == null or for_test=='' or for_test == -1
,该语句可以按正常逻辑走通,但由于升级了mybatis,ognl修复了该bug,该语句就可能引发了一些业务错误。
4.1.2 tomcat升级带来的问题
大家也都用过tomcat吧, ParameterMap (Tomcat API Documentation) 是request中的一个属性。我们为了在进入业务控制器前覆盖/修改前端传入的参数,可以向这个map传入一些值。
虽然官方文档告诉我们,该map只能读不能写。但实际上,在tomcat特定版本前,在filter中使用RequestDispatcher的forward进行请求转发,tomcat会使用ApplicationHTTPRequest对原始的request进行包装,而在ApplicationHTTPRequest的getParameterMap方法中,返回的是普通的HashMap。
该问题的具体修复版本是:7.0.68和8.0.14。在升级到这些版本后,这个特性就不能使用了,从而会导致业务错误。我当时的临时解法是判断getParameterMap方法得到的是不是可写的map,如果不是,就利用反射,将该map变成可写的。
4.1.3 小结
以上两个case,第一个是误写,第二个是不了解接口说明。在我们的平常开发中,尽量避免这两种问题吧。
4.2 性能上的影响
虽然在常识中,包越升级越好。但也有可能升级后的包存在某些bug,导致对生产环境产生影响。因此对于重要应用,在升级完包后,最好预发环境做好充足验证,在发布上线前,也要做好beta验证。
原始发表:2020-01-05, 如有侵权请联系 cloudcommunity@tencent.com 删除
社区
活动
资源
关于
腾讯云开发者
扫码关注腾讯云开发者
领取腾讯云代金券
热门产品
热门推荐
更多推荐
Copyright © 2013 - 2023 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号: 粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287