Spring 4 升级踩雷指南
点击上方“后端技术精选”,选择“置顶公众号”
技术文章第一时间送达!
作者:静默虚空
https://github.com/dunwu/spring-tutorial
前言
最近,一直在为公司老项目做核心库升级工作。本来只是想升级一下 JDK8 ,却因为兼容性问题而不得不升级一些其他的库,而其他库本身依赖的一些库可能也要同步升级。这是一系列连锁问题,你很难一一识别,往往只有在编译时、运行时才能发现问题。
总之,这是个费劲的活啊。
本文小结一下升级 Spring4 的连锁问题。
为什么升级 spring4
升级 Spring4 的原因是:Spring 4 以前的版本不兼容 JDK8。当你的项目同时使用 Spring3 和 JDK8,如果代码中有使用 JDK8 字节码或 Lambada 表达式,那么会出问题。
也许你会问,为什么不使用最新的 Spring 5 呢?因为作为企业软件,一般更倾向使用稳定的版本(bug 少),而不是最新的版本,尤其是一些核心库。
更多细节可以参考:
https://spring.io/blog/2013/05/21/spring-framework-4-0-m1-3-2-3-available/
spring 4 重要新特性
Spring 4 相比 Spring 3,引入许多新特性,这里列举几条较为重要的:
支持
JDK8
(这个是最主要的)。Groovy Bean Definition DSL
风格配置。支持 WebSocket、SockJS、STOMP 消息
移除 Deprecated 包和方法
一些功能加强,如:核心容器、Web、Test 等等,不一一列举。
更多 Spring 4 新特性可以参考:
https://docs.spring.io/spring/docs/4.3.14.BUILD-SNAPSHOT/spring-framework-reference/htmlsingle/#spring-whats-new
http://jinnianshilongnian.iteye.com/blog/1995111
升级 spring 4 步骤
了解了前面内容,我们知道了升级 Spring 4 带来的好处。现在开始真刀真枪的升级了。
不要以为升级一下 Spring 4,仅仅是改一下版本号,那么简单,细节处多着呢。
下面,结合我在公司项目升级 Spring4 时遇到的一系列坑,希望能帮助各位少走弯路。
注
下文内容基于假设你的项目是用 maven 管理这一前提。如果不满足这一前提,那么这篇文章对你没什么太大帮助。
修改 spring 版本
第一步,当然是修改 pom.xml 中的 spring 版本。
3.x.x.RELEASE
> 4.x.x.RELEASE
实例:升级 spring-core
其它 spring 库的升级也如此:
<properties><spring.version>4.3.13.RELEASE</spring.version>
</properties>
<dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version>
</dependency>
修改 spring xml 文件的 xsd
用过 spring 的都知道,spring 通常依赖于大量的 xml 配置。
spring 的 xml 解析器在解析 xml 时,需要读取 xml schema,schema 定义了 xml 的命名空间。它的好处在于可以避免命名冲突,有点像 Java 中的 package。
实例:一个 spring xml 的 schema
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
说明
xmlns="http://www.springframework.org/schema/beans"
声明 xml 文件默认的命名空间,表示未使用其他命名空间的所有标签的默认命名空间。xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
声明XML Schema 实例,声明后就可以使用 schemaLocation 属性了。xmlns:mvc="http://www.springframework.org/schema/mvc"
声明前缀为 mvc 的命名空间,后面的 URL 用于标示命名空间的地址不会被解析器用于查找信息。其惟一的作用是赋予命名空间一个惟一的名称。当命名空间被定义在元素的开始标签中时,所有带有相同前缀的子元素都会与同一个命名空间相关联。 其它的类似xmlns:context
、xmlns:jdbc
等等同样如此。
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
..."
这个从命名可以看出个大概,指定 schema 位置这个属性必须结合命名空间使用。这个属性有两个值,第一个值表示需要使用的命名空间。第二个值表示供命名空间使用的 xml schema 的位置。
上面示例中的 xsd 版本是 3.1.xsd
,表示 spring 的 xml 解析器会将其视为 3.1 版本的 xml 文件来处理。
现在,我们使用了 Spring 4,3.1.xsd
版本显然就不正确了,我们可以根据自己引入的 Spring 4 的子版本号将其改为 4.x.xsd
。
但是,还有一种更好的做法:把这个指定 xsd 版本的关键字干掉,类似这样:http://www.springframework.org/schema/tx/spring-tx.xsd
。
这么做的原因如下:
Spring 默认在启动时要加载 xsd 文件来验证 xml 文件。
如果没有提供
schemaLocation
,那么 spring 的 xml 解析器会从 namespace 的 uri 里加载 xsd 文件。schemaLocation
提供了一个 xml namespace 到对应的 xsd 文件的一个映射。如果不指定 spring xsd 的版本号,spring 取的就是当前本地 jar 里的 xsd 文件,减少了各种风险(比如 xsd 与实际 spring jar 版本不一致)。
更多详细内容可以参考这篇文章:
http://blog.csdn.net/hengyunabc/article/details/22295749)
修改 spring xml 文件
spring 4 对 xml 做了一些改动。这里说一个最常用的改动:
ref local
spring 不再支持 ref
元素的 local
属性,如果你的项目中使用了,需要改为 bean
。
spring 4 以前:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource"><ref local="dataSource" /></property>
</bean>
spring 4 以后:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource"><ref bean="dataSource" /></property>
</bean>
如果不改启动会报错:
Caused by: org.xml.sax.SAXParseException: cvc-complex-type.3.2.2: Attribute 'local' is not allowed to appear in element 'ref'.
当然,可能还有一些其他配置改动,这个只能说兵来将挡水来土掩,遇到了再去查官方文档吧。
加入 spring support
spring 3 中很多的扩展内容不需要引入support 。但是 spring 4 中分离的更彻底了,如果不分离,会有很多ClassNotFound
。
<dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>4.2.3.RELEASE</version>
</dependency>
更换 spring-mvc jackson
spring mvc 中如果返回结果为 json 需要依赖 jackson 的jar包,但是他升级到了2, 以前是 codehaus.jackson
,现在换成了 fasterxml.jackson
<dependency> <groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.7.0</version>
</dependency>
<dependency> <groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.7.0</version>
</dependency>
同时修改spring mvc的配置文件:
<beanclass="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"><property name="messageConverters"><list><ref bean="stringHttpMessageConverter" /> <beanclass="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean></list></property>
</bean><bean id="stringHttpMessageConverter"class="org.springframework.http.converter.StringHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/plain;charset=UTF-8</value></list></property>
</bean>
解决 ibatis 兼容问题
问题
如果你的项目中使用了 ibatis (mybatis 的前身)这个 orm 框架,当 spring3 升级 spring4 后,会出现兼容性问题,编译都不能通过。
这是因为 Spring4 官方已经不再支持 ibatis。
解决方案
添加兼容性 jar 包
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis-2-spring</artifactId><version>1.0.1</version>
</dependency>
更多内容可参考:
https://stackoverflow.com/questions/32353286/no-support-for-ibatis-in-spring4-2-0
升级 Dubbo
我们的项目中使用了 soa 框架 Dubbo 。由于 Dubbo 是老版本的,具体来说是(2013年的 2.4.10),而老版本中使用的 spirng 版本为2.x,有兼容性问题。
Dubbo 项目从今年开始恢复维护了,首先把一些落后的库升级到较新版本,比如 jdk8,spring4 等,并修复了一些 bug。所以,我们可以通过升级一下 Dubbo 版本来解决问题。
<dependency><groupId>com.alibaba</groupId><artifactId>dubbo</artifactId><version>2.5.8</version><exclusions><exclusion><groupId>org.springframework</groupId><artifactId>spring-context</artifactId></exclusion><exclusion><groupId>org.springframework</groupId><artifactId>spring-web</artifactId></exclusion><exclusion><groupId>org.javassist</groupId><artifactId>javassist</artifactId></exclusion></exclusions>
</dependency>
升级 Jedis
升级 Dubbo 为当前最新的 2.5.8 版本后,运行时报错:
JedisPoolConfig 配置错误
Caused by: java.lang.ClassNotFoundException: org.apache.commons.pool2.impl.GenericObjectPoolConfig
由于项目中使用了 redis,版本为 2.0.0 ,这个问题是由于 jedis 需要升级:
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.9.0</version>
</dependency>
jedis 2.4.1 以上版本的 JedisPoolConfig
已经没有了maxActive
和 maxWait
属性。
修改方法如下:
maxActive > maxTotal
maxWait > maxWaitMillis
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"><property name="maxTotal" value="200" /><property name="maxIdle" value="10" /><property name="maxWaitMillis" value="1000" /><property name="testOnBorrow" value="true" />
</bean>
JedisPool 配置错误
InvalidURIException: Cannot open Redis connection due invalid URI
原来的配置如下:
<bean id="jedisPool" class="redis.clients.jedis.JedisPool" destroy-method="destroy" depends-on="jedisPoolConfig"><constructor-arg ref="jedisPoolConfig" /><constructor-arg type="java.lang.String" value="${redis.host}" /><constructor-arg type="int" value="${redis.port}" />
</bean>
查看源码可以发现,初始化 JedisPool 时未指定结构方法参数的类型,导致 host 字符串值被视为 URI 类型,当然类型不匹配。
解决方法是修改上面的host 配置,为:<constructor-arg type="java.lang.String" value="${redis.host}" />
至此,spring 4 升级结束。后面如果遇到其他升级问题再补充。
资料
https://spring.io/blog/2013/05/21/spring-framework-4-0-m1-3-2-3-available/
推荐阅读(点击即可跳转阅读)
1.
2.
3.
4.
5.
Spring 4 升级踩雷指南相关推荐
- Spring Boot 中文参考指南
Spring Boot 版本 2.7.8 原文:https://docs.spring.io/spring-boot/docs/2.7.8/reference/htmlsingle/ - 笔者注: S ...
- Spring Cloud Alibaba迁移指南(二):零代码替换 Eureka
为什么80%的码农都做不了架构师?>>> 自 Spring Cloud 官方宣布 Spring Cloud Netflix 进入维护状态后,我们开始制作<Spring C ...
- 强烈推荐Spring Web Flow权威指南
关于Spring Web Flow权威指南 评论 读后感:这是Spring Web Flow创始人写的书.内容是基于1.0的.此书原版出版时其实2.0已经推出了,为什么老大并没有追新呢?我猜想,书中写 ...
- Spring Cloud Alibaba迁移指南(四):零代码兼容 Api-Gateway
自 Spring Cloud 官方宣布 Spring Cloud Netflix 进入维护状态后,我们开始制作<Spring Cloud Alibaba迁移指南>系列文章,向开发者提供更多 ...
- Spring Cloud 升级最新 Finchley 版本,踩了所有的坑
转载自 Spring Cloud 升级最新 Finchley 版本,踩了所有的坑 Spring Boot 2.x 已经发布了很久,现在 Spring Cloud 也发布了 基于 Spring Bo ...
- Spring Cloud Alibaba迁移指南(四):零代码兼容 Api-Gateway 1
自 Spring Cloud 官方宣布 Spring Cloud Netflix 进入维护状态后,我们开始制作<Spring Cloud Alibaba迁移指南>系列文章,向开发者提供更多 ...
- Spring Cloud Alibaba迁移指南(三):极简的 Config
自 Spring Cloud 官方宣布 Spring Cloud Netflix 进入维护状态后,我们开始制作<Spring Cloud Alibaba迁移指南>系列文章,向开发者提供更多 ...
- Spring Cloud Alibaba迁移指南(一):一行代码从 Hystrix 迁移到 Sentinel
自 Spring Cloud 官方宣布 Spring Cloud Netflix 进入维护状态后,我们开始制作<Spring Cloud Alibaba迁移指南>系列文章,向开发者提供更多 ...
- Spring Cloud Alibaba迁移指南(三):极简的 Config 1
自 Spring Cloud 官方宣布 Spring Cloud Netflix 进入维护状态后,我们开始制作<Spring Cloud Alibaba迁移指南>系列文章,向开发者提供更多 ...
最新文章
- Java并发编程-volatile
- python笔记之利用BeautifulSoup爬取糗事百科首页段子
- 为什么“极大似然估计表达式的极值”可以用来估计参数
- c语言构造报文,构造一个缓冲区溢出的C语言的例子
- f分布表完整图a=0.05_2019年05月16日,沪深A股股票分析
- 沃尔玛牵手Gatik推行自动驾驶试点项目 为客户配送订单
- docker入门2---docker的初体验
- char* char [] 区别[zz]
- android swf 播放器 源码,Android 9.0 flash播放器播放swf源码讲解
- 如何选择剑桥英语KET,PET课程和老师
- 玩转电脑常用的140个技巧
- 计算机考研面试有英语听力吗,考研复试前如何准备英语听力和口语
- 30万人追更,年度重磅Go图书出版,百万流量博主带你学习Go底层原理
- 【系统分析师之路】第七章 复盘系统设计(业务流程建模)
- 采用SAMKeychain钥匙串存储设备唯一标示与何种情况下同一个手机它存储的值会变化
- LeetCode 1344. 时钟指针的夹角
- Java——API(接口)
- Android 快速实现Parcelable接口
- 户籍不在本市并已申请基本养老保险或基本医疗保险关系转移手续销户提取业务办理指南(试行)...
- 图片无损放大软件哪个好?图片放大不失真这样做
热门文章
- couchdb android,CouchDB on android 入门
- 留学美国,我们是安全的吗?
- 微信小程序(七)通过chooseInvoiceTitle获取微信发票抬头
- 计算机网络中端到端与点到点的区别
- HTTPS生成数字证书
- “Provisioning profile “iOS Team Provisioning Profile“ doesn‘t include the currently selected device
- 博海拾贝--springcloud的组件及使用(3)服务网关 GateWay
- 3D和texture素材国外常用网站
- ADR01BRZ 精密电压基准IC 应用及介绍
- 我在传智播客当分校长生涯的总结:参演了一部精彩的电影