在排查依赖间影响的时候,最常使用的还是mvn命令。
如果要查看当前的依赖树,可以使用以下命令。
mvn dependency:tree
如果要查看maven如何解决包冲突,即查看重复的、被忽略的依赖,可以使用以下命令:
使用上述命令后,会看到有些依赖上会有额外的信息。他们的含义分别是:
大型项目中,由于依赖众多,当使用上述命令后,查看的信息会特别多。因此可以使用以下命令,在查看依赖情况时指定要查看或过滤的包。
指定查看的包:
mvn dependency:tree -Dverbose -Dincludes=org.springframework:spring-tx
指定排除的包:
mvn dependency:tree -Dverbose -Dexcludes=com.google.guava:guava
过滤串使用groupId:artifactId:version的方式进行过滤,可以不写全。
查看公有包可以访问 MvnRepository ,当你需要升级依赖的时候,可以在这个网站上查看想升级版本的包的最新版本信息。
依赖版本升级可能会遇到以下几种问题,假设我们有A/B/C/D等包。
假设在A包中有一个类ClassA,被B包引用。由于升级,ClassA改了路径或名称、或者由别的类代替。那么B包也需要升级,以匹配A包升级。同样的,如果B包中的类被C包依赖,C包也需要升级。在这个过程中,如果B包的版本中没有适配A包最新版本的话,可以尝试在代码中重写一个旧的ClassA,让B包能够用上。如果改动是在太大,那么建议还是别把A的版本升的太高。
假设在A包中,原先有依赖google-guava包,然后我们自然而然地用了guava包中的类。在A包升级后,它去掉了对google-guava的依赖,那我们的项目可能就会报错了。这里建议凡是在业务代码中用到的第三方包,都在pom中指明依赖。
不知道大家有没有遇到过包版本混乱的情况?我遇到过,在 2018-01
版本中,某些接口可以使用,在 2018-02
版本中又不可以。你以为他的包版本规则是按照日期产出的,结果又出来一个 1.2.10
版本。总之,包的开发者对包的管理存在一定的问题,这个时候,最好和包管理者进行沟通,确认可用版本。
所省级包中的某些类在升级后,入参、属性发生变化,从而导致代码或配置报错。
在springboot1x升级2x时,有很多在application.properties中的配置key也会发生变化。一般情况下,根据idea的提示修改即可。
在springboot1x升级2x时,HttpMessageConverters从web模块迁移至了http模块,如果有使用 HttpMessageConverters
这个类,就需要做一下调整。WebMvcConfigurer的跨域配置,原先只需要调用addMapping方法即可,升级后就需要指定allowCredentials了。
假设A是一个框架包,某个接口允许有一个实现。结果在升级B/C包后,B/C包都实现了这个接口。在编译时,没有任何问题,但运行时,A框架发现有两个实现,所以会报错。 此时,需要查看B,C包在升级后,是否还同时需要,如果不同时需要,则只要去掉其中一个依赖即可。如果同时需要,则需要联系包管理者进一步解决冲突。
在升级完包依赖后,需要我们进一步观察升级对生产造成的影响。一般来说,可能会有以下这些问题。
在我们的代码中,玩的6的人总喜欢用一些奇奇怪怪的高级方法,例如反射取一下私有属性等等。但随着依赖包的升级,有些私有属性消失了或bug被修复了,我们代码中的一些高级用法就会失效,严重者甚至会引起线上问题。
大家都用过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,该语句就可能引发了一些业务错误。
大家也都用过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变成可写的。
以上两个case,第一个是误写,第二个是不了解接口说明。在我们的平常开发中,尽量避免这两种问题吧。
虽然在常识中,包越升级越好。但也有可能升级后的包存在某些bug,导致对生产环境产生影响。因此对于重要应用,在升级完包后,最好预发环境做好充足验证,在发布上线前,也要做好beta验证。