在springboot中使用dubbo,本来是件挺简单的事情,但现实的世界就是如此的复杂,今天我用一个亲身经历的跳坑和填坑的事来讲在spring boot中使用高版本dubbo(当当的魔改版)的三重境界。

1、看山是山,使用官方starter

简单的使用dubbo starter集成进spring boot还是非常简单的。

在springboot2的pom.xml中引入dubbo的starter

    <dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>

在启动类里面加上注解@EnableDubboConfiguration

@EnableDubboConfiguration
@SpringBootApplication
public class DubbodemoApplication { public static void main(String[] args) {
SpringApplication.run(DubbodemoApplication.class, args);
} }

在application.properties里面写dubbo的相关配置

spring.dubbo.application.name=mydubbostarterdemo
spring.dubbo.server=true
spring.dubbo.protocol.name=dubbo
spring.dubbo.registry.address=zookeeper://127.0.0.1:2181

作为服务的提供者,我们发布一个服务

public interface IHelloService {
public String hello(String str);
}
import com.alibaba.dubbo.config.annotation.Service;
//这个service的注解是dubbo的service,不是spring的service注解
@Service(interfaceClass = IHelloService.class)
@Component
public class HelloServiceImpl implements IHelloService { @Override
public String hello(String str) {
String returnStr = "Hello "+str;
return returnStr;
} }

然后运行DubbodemoApplication就能发布这个服务了。

同样的,在消费者那边,我们直接用@Reference注解来引用这个服务即可

    @Reference
private IHelloService helloService;
@GetMapping("/hello/{name}")
public String hello(@PathVariable("name") String name) {
String str = helloService.hello(name);
System.out.println(str);
return str;
}

记得在消费者的工程里面要加上IHelloService的接口类。

这样就能愉快的调用了

是不是很简单,是不是很容易。但是这个世界是复杂的,我们看下pom文件可以看到,里面引用的dubbo版本是2.6.0

但现在很多地方用的并不是dubbo,而是当当改过的dubbo,最新的版本已经到了2.8.4,如果服务提供者用这个版本,那么消费者还用这种方法调用,就会报错

2019-12-05 11:51:28.094 ERROR 17808 --- [nio-8088-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method hello in the service com.skyblue.dubbodemo.service.IHelloService. Tried 3 times of the providers [192.168.1.103:20880] (1/1) from the registry 115.29.199.6:2181 on the consumer 192.168.1.103 using the dubbo version 2.6.0. Last error is: Failed to invoke remote method: hello, provider: dubbo://192.168.1.103:20880/com.skyblue.dubbodemo.service.IHelloService?anyhost=true&application=mydubbostarterdemo&check=false&dubbo=2.8.4a&generic=false&interface=com.skyblue.dubbodemo.service.IHelloService&methods=hello&pid=17808&register.ip=192.168.1.103&remote.timestamp=1575517827193&side=consumer&timestamp=1575517879746, cause: Fail to decode request due to: RpcInvocation [methodName=hello, parameterTypes=null, arguments=null, attachments={path=com.skyblue.dubbodemo.service.IHelloService, input=223, dubbo=2.6.0, version=0.0.0}]] with root cause

com.alibaba.dubbo.remoting.RemotingException: Fail to decode request due to: RpcInvocation [methodName=hello, parameterTypes=null, arguments=null, attachments={path=com.skyblue.dubbodemo.service.IHelloService, input=223, dubbo=2.6.0, version=0.0.0}]
at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.returnFromResponse(DefaultFuture.java:218) ~[dubbo-2.6.0.jar:2.6.0]
at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:137) ~[dubbo-2.6.0.jar:2.6.0]
at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:111) ~[dubbo-2.6.0.jar:2.6.0]
at com.alibaba.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke(DubboInvoker.java:95) ~[dubbo-2.6.0.jar:2.6.0]
at com.alibaba.dubbo.rpc.protocol.AbstractInvoker.invoke(AbstractInvoker.java:142) ~[dubbo-2.6.0.jar:2.6.0]
......

同样,提供服务端也是报错

2019-12-05 12:00:55.144  WARN 7412 --- [w I/O worker #7] c.a.d.r.p.dubbo.DecodeableRpcInvocation  :  [DUBBO] Decode rpc invocation failed: expected integer at 0x12 java.lang.String (Ljava/lang/String;), dubbo version: 2.8.4a, current host: 192.168.1.103

com.alibaba.com.caucho.hessian.io.HessianProtocolException: expected integer at 0x12 java.lang.String (Ljava/lang/String;)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.error(Hessian2Input.java:2720) ~[dubbo-2.8.4a.jar:2.8.4a]
at com.alibaba.com.caucho.hessian.io.Hessian2Input.expect(Hessian2Input.java:2691) ~[dubbo-2.8.4a.jar:2.8.4a]
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readInt(Hessian2Input.java:773) ~[dubbo-2.8.4a.jar:2.8.4a]
at com.alibaba.dubbo.common.serialize.support.hessian.Hessian2ObjectInput.readInt(Hessian2ObjectInput.java:58) ~[dubbo-2.8.4a.jar:2.8.4a]
at com.alibaba.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:106) ~[dubbo-2.8.4a.jar:2.8.4a]

显然,因为版本差异造成了向下兼容有问题,那怎么办呢,我首先想到的是把消费端的dubbo starter也升级到2.8.4,但这个版本不是阿里做的,所以阿里官方的starter还是稳稳的停留在2.0.0的最新版本,只支持dubbo 2.6.0的版本,那怎么办呢?

2、看山不是山,回归传统,不用starter

我其实首先尝试的是starter直接强行引用2.8.4的版本

       <dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.0</version>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.8.4</version>
</dependency>

可惜可耻的失败了,启动消费端的时候就报错了

12:12:01.733 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
java.lang.NoClassDefFoundError: com/alibaba/dubbo/qos/server/DubboLogo
at com.alibaba.dubbo.spring.boot.context.event.DubboBannerApplicationListener.buildBannerText(DubboBannerApplicationListener.java:49)
at com.alibaba.dubbo.spring.boot.context.event.DubboBannerApplicationListener.onApplicationEvent(DubboBannerApplicationListener.java:39)
at com.alibaba.dubbo.spring.boot.context.event.DubboBannerApplicationListener.onApplicationEvent(DubboBannerApplicationListener.java:23)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:76)
at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:53)
at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:345)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
at com.skyblue.dubbodemo.DubbodemoClientApplication.main(DubbodemoClientApplication.java:13)

这里有一个DubboLogo的报错,后面我们会讲到。显然,starter里面用到的dubbo2.6.0的代码在dubbo2.8.4里面做了改动,已经调不了了,怎么办,只能抛弃starter,使用传统的dubbo调用方法了。

        //不使用starter
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.8.4</version>
</dependency>

在resources/spring目录下添加一个dubbo-consumer.xml文件

<?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:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <dubbo:application name="mydubbodemo"/> <!-- 注册中心配置,使用zookeeper注册中心暴露服务地址 -->
<dubbo:registry id="registry1" address="zookeeper://127.0.0.1:2181" timeout="60000" /> <dubbo:consumer timeout="120000" retries="0" check="false"/>
<dubbo:reference interface="com.skyblue.dubbodemo.service.IHelloService" registry="registry1" id="helloService"/>
</beans>

然后在消费端的启动文件里面加上这个xml文件

@SpringBootApplication
@ImportResource("classpath:spring/dubbo-consumer.xml")
class DubbodemoClientApplication{ public static void main(String[] args) {
SpringApplication.run(DubbodemoClientApplication.class, args);
} }

调用服务的类改成传统的引入方式

   @Autowired
private IHelloService helloService;

这样就能使用2.8.4版本的dubbo了。

但是,这种方法需要在xml里面显式的申明我需要调用的服务,和直接用注解@Reference就调用服务比方便性差太多了,虽然现在可以使用了,但我还是深深的想念starter...

3、看山还是山,就要用starter

看过我之前文章的朋友应该清楚,其实starter是一个很简单的规范,可以让开发人员来自定义自己的starter,既然官方不支持,那我们就自己改一个starter不就行了,我就是拿2.0.0版本的官方dubbo starter改的。先clone一份官方的版本,这里

首先要改的就是把pom.xml的dubbo版本升级到2.8.4,但改完后就会看到有报错。报错就是这个类DubboBannerApplicationListener

bannerTextBuilder.append(DubboSpringBootStarterConstants.LINE_SEPARATOR).append(DubboLogo.dubbo)
.append(" :: Dubbo :: (v").append(Version.getVersion()).append(")")
.append(DubboSpringBootStarterConstants.LINE_SEPARATOR);

里面的DubboLogo这个类在dubbo后面版本里面被去掉了,所以报错,但这个其实是在后台的console 出现一个dubbo的标志,不要也无所谓,去掉就好了。上面我们在消费端强行升级dubbo版本,启动时报的其实也是这个错。

然后我们再次改pom.xml文件,把spring boot和jdk的版本也升一下

<properties>
...
<java.version>1.8</java.version>
<spring-boot.version>2.2.1.RELEASE</spring-boot.version>
<dubbo.version>2.8.4a</dubbo.version>
...
</properties>

这样,一个可以在2.8.4a版本下使用的dubbo starter就改造完成了。

4、用起来

虽然改完了,但怎么用却还是一个问题,第一种方法是直接用mvn package生成dubbo-spring-boot-starter-2.8.4a.jar,然后copy到项目中去。但这种方法在现在的软件开发中已经不常用了,大部分用的方法是发布到maven的nexus私服。首先要把pom.xml改一下

<distributionManagement>
<snapshotRepository>
<id>snapshots</id>
<url>http://私服ip:port/nexus/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>releases</id>
<url>http://私服ip:port/nexus/content/repositories/releases</url>
</repository>
</distributionManagement>

另外本地maven软件的setting.xml文件也要配置一下:

<servers>
<server>
<id>releases</id>
<username>账号</username>
<password>密码</password>
</server>
<server>
<id>snapshots</id>
<username>admin</username>
<password>admin123</password>
</server>
</servers>

然后执行 mvn deploy就能发布到私服上去了。如果deploy有报这个错

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-gpg-plugin:1.6:sign (sign-artifacts) on project dubbo-spring-boot-starter: Unable to execute gpg command: Error while executing process. Cannot run program "gpg.exe": CreateProcess error=2, 系统找不到指定的文件。 -> [Help 1]

是因为deploy的时候调用了gpg的签名,我们私服不见得需要,我直接把它从pom.xml里面去掉了

<plugin>
<artifactId>maven-gpg-plugin</artifactId>
<version>${maven-gpg-plugin.version}</version>
<configuration>
<skip>false</skip>
</configuration>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>

就是这段,去掉后,发布成功就能够直接在项目的pom.xml中引用了。

修改后的starter源代码

springboot2中使用dubbo的三重境界的更多相关文章

  1. PHP解耦的三重境界(浅谈服务容器)

    阅读本文之前你需要掌握:PHP语法,面向对象 在完成整个软件项目开发的过程中,有时需要多人合作,有时也可以自己独立完成,不管是哪一种,随着代码量上升,写着写着就"失控"了,渐渐&q ...

  2. SpringBoot2中,怎么生成静态文档

    SpringBoot2中,怎么生成静态文档 在实际开发过程中,我们通过swagger就可以生成我们的接口文档,这个文档就可以提供给前端人员开发使用的.但是,有时候,我们需要把我们的接口文档,提供给第三 ...

  3. Spring Boot中使用Dubbo

    高并发下Redis会出现的问题: 缓存穿透 缓存雪崩 热点缓存 一.定义commons工程11-dubboCommons (1) 创建工程 创建Maven的Java工程,并命名为11-dubboCom ...

  4. SpringBoot2.0 整合 Dubbo框架 ,实现RPC服务远程调用

    一.Dubbo框架简介 1.框架依赖 图例说明: 1)图中小方块 Protocol, Cluster, Proxy, Service, Container, Registry, Monitor 代表层 ...

  5. dubbo 2.7.0 中缺乏 <dubbo:annotation /> 的解决方案

    一.背景  从 dubbo 2.6.5 升级到 2.7.0,突然发现好多地方不能用了,dubbo:annotation 直接报红,原先的 @Service 和 @Reference 中直接报了过时,源 ...

  6. SpringBoot2中配置文件的调整,升级SpringBoot2时候注意的坑

    原来使用SpringBoot1.5最近写个demo后发现原来的配置文件不能用了. 最后上网查询了一下资料,springboot2.0和spring1.x还是存在不少问题的. 1.问题一:Java版本要 ...

  7. springcloud中使用dubbo开发rpc服务及调用

    spring cloud中基于springboot开发的微服务,是基于http的rest接口,也可以开发基于dubbo的rpc接口. 一,创建goodsService模块 1, 在创建的goodsSe ...

  8. 如何在 Istio 中支持 Dubbo、Thrift、Redis 以及任何七层协议?

    赵化冰,腾讯云高级工程师,Istio Member,ServiceMesher管理委员,Istio 项目贡献者, Aerika 项目创建者 ,热衷于开源.网络和云计算.目前主要从事服务网格的开源和研发 ...

  9. JMeter中添加dubbo相关插件异常问题解决

    从网上下载了一个dubbo的插件,然后放到JMeter的/lib/ext目录下: 然后启动直接异常 发现启动不了,然后下载了一个全新的JMeter3.2将dubbo插件放到同样的目录,启动,没有问题: ...

随机推荐

  1. Mycat分布式数据库架构解决方案--Linux安装运行Mycat

    echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! Myc ...

  2. 学习笔记01HTML

    1.五大浏览器:IE,FireFox,Chrome,Opera,Safari(Apple)所有浏览器都是这五大浏览器中作为核心引擎的.Trident(引擎):就是IE浏览器的WebBrowser控制. ...

  3. NOIP模拟 11

    差点迟到没赶上开题 开题后看了T1,好像一道原题,没分析复杂度直接敲了个NC线段树,敲了个暴力,敲了个对拍,就1h了.. 对拍还对出错了,发现标记下传有点问题,改了以后对拍通过,就把T1扔掉看T2 觉 ...

  4. 如何在 Spring/Spring Boot 中做参数校验?你需要了解的都在这里!

    本文为作者原创,如需转载请在文首著名地址,公众号转载请申请开白. springboot-guide : 适合新手入门以及有经验的开发人员查阅的 Spring Boot 教程(业余时间维护中,欢迎一起维 ...

  5. 如何实现一个MVVM

    说一说我对于mvvm模型的理解吧 我第一次接触mvvm也是在学习vue的时候,在我看来vue和react都是数据驱动视图,但是vue属于标准的mvvm模型,react是从组件化演变而来 不多废话,直接 ...

  6. js中函数的原型

    js中每一个构造函数都有一个prototype的属性,prototype指向一个对象,而这个对象的属性和方法都会被构造函数的实例所继承,因此,需要一些共享的属性和方法可以写在构造函数的原型中 1  用 ...

  7. 深入理解计算机系统 第三章 程序的机器级表示 part2

    这周由于时间和精力有限,只读一小节:3.4.4  压入和弹出栈数据 栈是一种特殊的数据结构,遵循“后进先出”的原则,可以用数组实现,总是从数组的一端插入和删除元素,这一端被称为栈顶. 栈有两个常用指令 ...

  8. [LC]219题 Contains Duplicate II (存在重复元素 II )

    ①英文题目: Given an array of integers and an integer k, find out whether there are two distinct indices ...

  9. 用大写字母输入 Linux 命令,实现以 sudo 用户权限运行

    我们知道,一些 Linux 命令是要通过 sudo 权限才能运行的,这需要我们每次使用这些命令时在前面加一个 sudo ,十分繁琐.今天给大家介绍一个好用的工具 SUDO ,它只需要我们用大写字母键入 ...

  10. 并发编程-硬件加持的CAS操作够快么?

    Talk is cheap CAS(Compare And Swap),即比较并交换.是解决多线程并行情况下使用锁造成性能损耗的一种机制,CAS操作包含三个操作数--内存位置(V).预期原值(A)和新 ...