spring 4 升级踩雷指南

前言

最近,一直在为公司老项目做核心库升级工作。本来只是想升级一下 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,引入许多新特性,这里列举几条较为重要的:

  1. 支持 JDK8 (这个是最主要的)。
  2. Groovy Bean Definition DSL 风格配置。
  3. 支持 WebSocket、SockJS、STOMP 消息
  4. 移除 Deprecated 包和方法
  5. 一些功能加强,如:核心容器、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.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
http://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:contextxmlns: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 版本不一致)。

更多详细内容可以参考这篇文章:为什么在Spring的配置里,最好不要配置xsd文件的版本号

修改 spring xml 文件

spring 4 对 xml 做了一些改动。这里说一个最常用的改动:

ref local

spring 不再支持 ref 元素的 local 属性,如果你的项目中使用了,需要改为 bean

shi

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的配置文件:

<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="stringHttpMessageConverter" />
<bean
class="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 已经没有了maxActivemaxWait 属性。

修改方法如下:

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 升级结束。后面如果遇到其他升级问题再补充。

资料

spring 4 升级踩雷指南的更多相关文章

  1. Spring Cloud 升级最新 Finchley 版本,踩坑指南!

    https://blog.csdn.net/youanyyou/article/details/81530240 Spring Cloud 升级最新 Finchley 版本,踩了所有的坑! 2018年 ...

  2. MySQL 升级方法指南大全

    原文:MySQL 升级方法指南大全 通常,从一个发布版本升级到另一个版本时,我们建议按照顺序来升级版本.例如,想要升级 MySQL 3.23 时,先升级到 MySQL 4.0,而不是直接升级到 MyS ...

  3. Spring WebSocket踩坑指南

    Spring WebSocket踩坑指南 本次公司项目中需要在后台与安卓App间建立一个长连接,这里采用了Spring的WebSocket,协议为Stomp. 关于Stomp协议这里就不多介绍了,网上 ...

  4. Spring:JdbcTemplate使用指南

    Spring:JdbcTemplate使用指南 Spring:JdbcTemplate使用指南 前言: 本文指在介绍Spring框架中的JdbcTemplate类的使用方法,涉及基本的Spring反转 ...

  5. Spring Cloud 升级最新 Greenwich 版本,舒服了~

    去年将 Spring Cloud 升级到了 Finchley 版本: Spring Cloud 升级最新 Finchley 版本,踩了所有的坑! 这个大版本栈长是踩了非常多的坑啊,帮助了不少小伙伴. ...

  6. Spring Cloud Alibaba迁移指南(二):零代码替换 Eureka

    自 Spring Cloud 官方宣布 Spring Cloud Netflix 进入维护状态后,我们开始制作<Spring Cloud Alibaba迁移指南>系列文章,向开发者提供更多 ...

  7. Spring Cloud Alibaba迁移指南(一):一行代码从 Hystrix 迁移到 Sentinel

    摘要: 本文对Hystrix.Resilience4j.Sentinel进行对比,并探讨如何使用一行代码这种极简的方式,将Hystrix迁移到Sentinel. Hystrix 自从前段时间 宣布停止 ...

  8. Spring Cloud 升级之路 - 2020.0.x - 1. 背景知识、需求描述与公共依赖

    1. 背景知识.需求描述与公共依赖 1.1. 背景知识 & 需求描述 Spring Cloud 官方文档说了,它是一个完整的微服务体系,用户可以通过使用 Spring Cloud 快速搭建一个 ...

  9. vue2升级vue3指南(二)—— 语法warning&error篇

    本文总结了vue2升级vue3可能会遇到的语法警告和错误,如果想知道怎样升级,可以查看我的上一篇文章:vue2升级vue3指南(一)-- 环境准备和构建篇 Warning 1.deep /deep/和 ...

随机推荐

  1. 《Web前端开发修炼之道》-读书笔记CSS部分

    如何组织CSS-分层 应用 css 的能力分两部分:一部分是css的API,重点是如何用css控制页面内元素的样式:另一部分是css框架,重点是如何对 css 进行组织.如何组织 css 可以有多种角 ...

  2. Element ui表格展示多张图片问题

    显示一张图片的方法: <el-table-column label="头像" width="100"> <template scope=&qu ...

  3. runtime--小白看过来

    目录 RunTime 概述 RunTime消息机制 RunTime交换方法 RunTime消息转发 RunTime关联对象 RunTime实现字典与模型互转 1.RunTime 概述 我们在面试的时候 ...

  4. RSA加密算法验证(C#实现)

    RSA算法简单原理介绍(节选于网络) 假设Alice想要通过一个不可靠的媒体接收Bob的一条私人讯息.她可以用以下的方式来产生一个公钥和一个私钥: 随意选择两个大的质数p和q,p不等于q,计算N=pq ...

  5. 用正则表达式(regex)匹配多项式(polynomial)

    因为作业的要求,我需要识别用户从命令行输入的多项式,并且要提取出其中的系数.指数以便用于后续计算. 曾经想过用一个数组把用户所有的输入全部存进来,然后在写逻辑判断.但想想那复杂的逻辑,头皮都发麻,这时 ...

  6. 详细解读-this-关键字在全局、函数、对象、jQuery等中的基础用法!

    一.前言 1. Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象.Javascript可以通过一定的设计模式来实现面向对象的编程,其 ...

  7. Java多线程Master-Worker模式

    Java多线程Master-Worker模式,多适用于需要大量重复工作的场景中. 例如:使用Master-Worker计算0到100所有数字的立方的和 1.Master接收到100个任务,每个任务需要 ...

  8. 淘宝轮播JS

    taobao首页轮播原生js面对对象封装版 Author:wyf 2012/2/25

  9. LNMP架构部署

    第1章 部署LNMP架构步骤 1.1 ①部署Linux系统(OK) 基本优化完成(ip地址设置 yum源更新 字符集设置) 安全优化完成(iptables关闭 selinux关闭 /tmp/ 1777 ...

  10. 如何部署Java_web项目到云服务器上

    步骤 1:购买 Linux 实例(略) 步骤2:安装JDK 本节介绍如何安装java jdk. 软件包中包含的软件及版本如下: Tomcat:1.8.0_121 说明:这是写文档时参考的软件版本.您下 ...