zoukankan      html  css  js  c++  java
  • spring 4 升级踩雷指南

    目录

    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: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 版本不一致)。

    更多详细内容可以参考这篇文章:为什么在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 已经没有了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 升级结束。后面如果遇到其他升级问题再补充。

    资料

  • 相关阅读:
    了解 NoSQL 的必读资料
    关于什么时候用assert(断言)的思考
    这次见到了一些大侠
    NetBeans 时事通讯(刊号 # 87 Jan 12, 2010)
    动态链接库dll,静态链接库lib, 导入库lib
    新女性十得 写得了代码,查得出异常
    记录系统乱谈
    新女性十得 写得了代码,查得出异常
    fullpage.js禁止滚动
    RunningMapReduceExampleTFIDF hadoopclusternet This document describes how to run the TFIDF MapReduce example against ascii books. This project is for those who wants to experiment hadoop as a skunkworks in a small cluster (110 nodes) Google Pro
  • 原文地址:https://www.cnblogs.com/aimei/p/12201363.html
Copyright © 2011-2022 走看看