dubbo应用升级

前言

升级的应用为tomcat端应用。在升级过程中必须保证3者全部升级。

升级前版本 升级后版本
spring 2.5.6.SEC03 5.1.7.RELEASE
jdk 1.7 1.8
dubbo 2.5.3 2.7.2

为何三者都要升级?

2.5.6版本spring-context并不支持jdk1.8,2.5.3版本的dubbo强依赖2.5.6版本的spring。 所以,如果你的项目也是这三个版本组合,要升级任一时,都必须全部升级。

此处要注意,dubbo要选择2.7.2版本,2.7.0是有Bug的,当然如果你的系统中没有hessian协议的服务,也就可以无视这个Bug,不过还是建议2.7.2,毕竟相比2.7.0也删除调整了一些类。(这一点我很想吐槽,只是更新了2个小版本,甚至可以说是补丁也不为过,却涉及删除类。。。这操作感觉不符合阿里这种大厂该有的。删除类这种调整我认为起码得变更版本号中间的数字。)

建议: 请先升级消费端,再升级服务端

升级jdk

首先,先升级jdk,只需要更改pom.xml中的jdk版本即可。没有什么难度,这里就不展示代码了。

当然要对应的改动打包的jdk版本,还有运行的jdk版本。

升级Spring

引入最新版本的Spring jar包,如果有需要排除的包记得排除。如果你用的是idea,这里推荐maven helper插件可以很直观的看到jar包依赖关系。


<properties>
   <spring.version>5.1.7.RELEASEspring.version>
properties>
 
<dependency>
   <groupId>org.springframeworkgroupId>
   <artifactId>spring-webmvcartifactId>
   <version>${spring.version}version>
dependency>
<dependency>
   <groupId>org.springframeworkgroupId>
   <artifactId>spring-webartifactId>
   <version>${spring.version}version>
dependency>
<dependency>
   <groupId>org.springframeworkgroupId>
   <artifactId>spring-contextartifactId>
   <version>${spring.version}version>
dependency>
<dependency>
   <groupId>org.springframeworkgroupId>
   <artifactId>spring-context-supportartifactId>
   <version>${spring.version}version>
dependency>
<dependency>
   <groupId>org.springframeworkgroupId>
   <artifactId>spring-beansartifactId>
   <version>${spring.version}version>
dependency>
<dependency>
   <groupId>org.springframeworkgroupId>
   <artifactId>spring-coreartifactId>
   <version>${spring.version}version>
dependency>
<dependency>
   <groupId>org.springframeworkgroupId>
   <artifactId>spring-txartifactId>
   <version>${spring.version}version>
dependency>
<dependency>
   <groupId>org.springframeworkgroupId>
   <artifactId>spring-aopartifactId>
   <version>${spring.version}version>
dependency>
  • 调整spring xml配置

如果应用中的spring xml配置xsi:schemaLocation的dtd,xsd有设置版本,就要更改了,最好是删除版本号。例如:http://www.springframework.org/schema/beans/spring-beans.xsd

升级dubbo

引入新版本的dubbo,记得排掉旧版本的dubbo依赖

<dependency>
   <groupId>org.apache.dubbogroupId>
   <artifactId>dubboartifactId>
   <version>2.7.2version>
dependency>
<dependency>
   <groupId>org.apache.curatorgroupId>
   <artifactId>curator-frameworkartifactId>
   <version>4.2.0version>
dependency>
<dependency>
   <groupId>org.apache.curatorgroupId>
   <artifactId>curator-clientartifactId>
   <version>4.2.0version>
dependency>
<dependency>
   <groupId>org.apache.curatorgroupId>
   <artifactId>curator-recipesartifactId>
   <version>4.2.0version>
dependency>

调整xml配置

更改spring xml配置文件中xsi:schemaLocation引入的xsd,dtd等版本。(最好是删除后缀版本。如http://www.springframework.org/schema/beans/spring-beans.xsd)

全局搜索code.alibabatech.com更改为dubbo.apache.org

调整Spring扫描xml配置


<beans 
   xmlns="http://www.springframework.org/schema/beans" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
      http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

   <context:component-scan base-package="com.howbuy.trade.huodong.controller"/>
   <dubbo:annotation package="com.howbuy.trade.huodong.controller">dubbo:annotation>
beans>

调整配置

升级后,推荐使用注解方式,虽然xml也支持,不过dubbo明显对xml没有做很好的再扩展,很多新的配置在注解中可以很容易找到配置点,但在xml中却很难配置。比如hessian的方法重载配置。

调整配置(消费端)

以下是注解的配置方式,无论是controller还是service引入依赖的服务用@Reference注解来进行注入。
消费端无需关心服务本身是否是dubbo或者hessian,所以可以忽略protocol

@Reference(registry = "wechatRegistry", interfaceClass = WechatQueryService.class)
private WechatQueryService wechatQueryService;

@Reference(registry = "member", interfaceClass = MemberCustInfoService.class)
private MemberCustInfoService memberCustInfoService;

调整配置(服务端)

通过Service注解来实现服务的注册,注意这里的Service是org.apache.dubbo下的,并不是spring下的。

@Service
public class OperatorServiceImpl extends BaseServiceImpl implements OperatorService {
}

应用中可能会出现同名不同包的服务。
可以使用如下配置方式。(可不可以直接@Service("cms.operatorService")呢? 我主要在2.7.0上测试了,并且发现只能这样写,至于2.7.2我并没有再去测试。)

@org.springframework.stereotype.Service("cms.operatorService")
@Service
public class OperatorServiceImpl extends BaseServiceImpl implements OperatorService {
}

服务端hessian配置

@Service(protocol = "hessian", timeout = 3000,parameters = {Constants.HESSIAN_OVERLOAD_METHOD_KEY,"true"})
public class FileUploadServiceImpl implements IFileUploadService {
}

注意parameters参数,其中HESSIAN_OVERLOAD_METHOD_KEY配置就是为了解决hessian方法重载的问题,这也是2.7.0的bug点。
(这里我又要吐槽,在2.5.3时解决hessian的方法重载问题我是通过更改2.5.3的源码包实现的。在我升级时只有2.7.0版本,在我将消费端升级到2.7.0后,查看到源码有Constants.HESSIAN_OVERLOAD_METHOD_KEY的解析,相应的我认为2.7.0已经解决了hessian的方法重载问题。在之后升级服务端后发现,parameters会出现array转map异常。这里分析源码后发现,dubbo包下是有arrayToMap的解析器的,但是却并没有使用。这就会造成parameters参数根本没有任何用途。还好这时候已经有了2.7.2,通过分析2.7.2发现这个问题已经解决。)

高低dubbo版本兼容问题

升级过程中必然会出现部分应用是高版本dubbo,部分应用是低版本dubbo。

如果协议为dubbo在测试下来没发现兼容问题,还是在hessian处有问题。

拉取低版本dubbo的源码,找到ServiceConfig类,大约在285行左右doExportUrlsFor1Protocol方法中有个map(变量名就叫map),在方法内会看到会向map中填入很多参数,增加:

if(name.equals("hessian")){
    map.put("hessian.overload.method","true");
}

重新打包,并发布到自己maven库中,调整自己的dubbo应用依赖自己的dubbo即可。

补充(20190729):
在升级时,hessian协议会出现很多问题,建议查看后续我对hessian问题的补充。

升级过程中可能出现的问题汇总

1. RpcResult等找不到

引入org.apache.dubbo包下的RpcResult即可(毕竟2.7.0已经是spring了)

2.org/eclipse/jetty/util/log/Logger不存在?

<dependency>
   <groupId>org.eclipse.jettygroupId>
   <artifactId>jetty-servletartifactId>
   <version>9.4.19.v20190610version>
dependency>

3. javax.el.xxxx报错?

这个问题是因为tomcat版本的问题,请尽量使用tomcat8。如果不方便升级,可以将tomcat->lib下的el-api.jar更改为tomcat8中的jar

4. hessian问题

在升级过程中,上述的hessian.overload.method是为了解决hessian服务存在重载方法的兼容问题。

如果hessian接口的形参为一个对象,比如dto,如果子类的对象存在与父类对象同名的成员变量,会造成该变量值丢失。 解决方法: 1). 先拉去hessian的源码到本地。2). 更改HessianProxyFactorygetSerializerFactory()方法中new SerializerFactorynew BeanSerializerFactory

  /**
   * Gets the serializer factory.
   */
  public SerializerFactory getSerializerFactory()
  {
    if (_serializerFactory == null)
//      _serializerFactory = new SerializerFactory(_loader);
      _serializerFactory = new BeanSerializerFactory();

    return _serializerFactory;
  }

3). 重新定义hessian的版本为自定版本,并发布。
4). 更改消费端的hessian版本为自定版本。(这里可以不更新服务端的,当然如果对服务端有上线操作,还是建议升级一下)。
一下是我自己的测试结果,供参考:
4.0.7-fixed是原hessian版本,4.0.7.1是在4.0.7-fixed基础上修复了序列化问题的自定版本。

版本访问 结果
4.0.7.1 -> 4.0.7.1
4.0.7.1 -> 4.0.7-fixed
4.0.7-fixed -> 4.0.7.1 ×
4.0.7-fixed -> 4.0.7-fixed ×

补充(20190809):
将hessian的序列化方式改为BeanSerializerFactory后,虽然可以解决父子类包含相同成员变量名时参数丢失的问题,但是会出现返回值为List等反序列化失败的问题。
我尝试使用JavaSerializer、UnsafeSerializer后,这两个序列化虽然能保证所有的返回值都能反序列化,但是却无法保证父子类相同成员变量名的问题。
这就好像鱼和熊掌不可兼得。 最后我在Hessian2Input中查到相异之处。在readObject()中BeanSerializerFactory会进入case 119,其它序列化方式会进入case 111。而问题就出现在case 119this.findSerializerFactory().getListDeserializer(type,(Class)null)
那如果更改此处源码,直接用case 111来解析会如何?是不是就可以解决鱼和熊掌的问题?

你可能感兴趣的:(SpringMVC,Java,dubbo)