springboot2中使用dubbo的三重境界
在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®ister.ip=192.168.1.103&remote.timestamp=1575517827193&side=consumer×tamp=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的三重境界的更多相关文章
- PHP解耦的三重境界(浅谈服务容器)
阅读本文之前你需要掌握:PHP语法,面向对象 在完成整个软件项目开发的过程中,有时需要多人合作,有时也可以自己独立完成,不管是哪一种,随着代码量上升,写着写着就"失控"了,渐渐&q ...
- SpringBoot2中,怎么生成静态文档
SpringBoot2中,怎么生成静态文档 在实际开发过程中,我们通过swagger就可以生成我们的接口文档,这个文档就可以提供给前端人员开发使用的.但是,有时候,我们需要把我们的接口文档,提供给第三 ...
- Spring Boot中使用Dubbo
高并发下Redis会出现的问题: 缓存穿透 缓存雪崩 热点缓存 一.定义commons工程11-dubboCommons (1) 创建工程 创建Maven的Java工程,并命名为11-dubboCom ...
- SpringBoot2.0 整合 Dubbo框架 ,实现RPC服务远程调用
一.Dubbo框架简介 1.框架依赖 图例说明: 1)图中小方块 Protocol, Cluster, Proxy, Service, Container, Registry, Monitor 代表层 ...
- dubbo 2.7.0 中缺乏 <dubbo:annotation /> 的解决方案
一.背景 从 dubbo 2.6.5 升级到 2.7.0,突然发现好多地方不能用了,dubbo:annotation 直接报红,原先的 @Service 和 @Reference 中直接报了过时,源 ...
- SpringBoot2中配置文件的调整,升级SpringBoot2时候注意的坑
原来使用SpringBoot1.5最近写个demo后发现原来的配置文件不能用了. 最后上网查询了一下资料,springboot2.0和spring1.x还是存在不少问题的. 1.问题一:Java版本要 ...
- springcloud中使用dubbo开发rpc服务及调用
spring cloud中基于springboot开发的微服务,是基于http的rest接口,也可以开发基于dubbo的rpc接口. 一,创建goodsService模块 1, 在创建的goodsSe ...
- 如何在 Istio 中支持 Dubbo、Thrift、Redis 以及任何七层协议?
赵化冰,腾讯云高级工程师,Istio Member,ServiceMesher管理委员,Istio 项目贡献者, Aerika 项目创建者 ,热衷于开源.网络和云计算.目前主要从事服务网格的开源和研发 ...
- JMeter中添加dubbo相关插件异常问题解决
从网上下载了一个dubbo的插件,然后放到JMeter的/lib/ext目录下: 然后启动直接异常 发现启动不了,然后下载了一个全新的JMeter3.2将dubbo插件放到同样的目录,启动,没有问题: ...
随机推荐
- Python能做什么,自学Python效果怎么样?
短时间掌握一门技能是现代社会的需求.生活节奏越来越快,现在不是大鱼吃小鱼,而是快鱼吃慢鱼的时代,人的时间比机器的时间更值钱.Python作为一种轻量级编程语言,语言简洁开发快,没那么多技巧,受到众多追 ...
- Java对象"后事处理"那点事儿——垃圾回收(一)
1.Dead Or Alive 我们都知道对象死亡的时候需要进行垃圾回收来回收这些对象从而释放空间,那么什么样的对象算是死亡呢,有哪些方法可以找出内存中的死亡对象呢?一般来说,我们可以这样认为:如果内 ...
- python(可迭代对象,迭代器,生成器及send方法详解)
一.可迭代对象 对象必须提供一个__iter__()方法,如果有,那么就是可迭代对象, 像列表,元祖,字典等都是可迭代对象可使用isinstance(obj,Iterable)方法判断 from co ...
- (大模拟紫题) Luogu P1953 易语言
原题链接:P1953 易语言 (我最近怎么总在做大模拟大搜索题) 分别处理两种情况. 如果只有一个1或0 直接设一个cnt为这个值,每次输入一个新名字之后把数字替换成cnt,最后cnt++即可. 注意 ...
- CSP2019游记
第一轮 Day 0 今天正好学校开运动会,就从开幕式开始翘,申请来机房训练. 早上六点多到了机房. 然后果不其然,运动会又下雨了(祈雨大会).机房冷的一批. 今天中午没有午休时间,去食堂吃个饭就直接来 ...
- 【 格式化时间(SimpleDateFormat)用法】
将特定字符串转换成Date格式 可以通过 new 一个 SimpleDateFormat 对象,通过对象调用parse方法实现 示例代码: String time = "2019-11-09 ...
- NOIP模拟 34
次芝麻,喝喝喝,长寿花! 什么鬼畜题面...一看就不是什么正经出题人 skyh双双双AK了..太巨了... T1 次芝麻 稍稍手玩就能发现分界点以一个优美的方式跳动 然后就愉快地帮次货们次掉了这个题- ...
- 大数据之路week01--自学之集合_2(Iterator迭代器)
选代器:是遍历集合的一种方式.迭代器是依赖于集合而存在的.我有一个集合: Collection c = new ArrayList();我们给集合中添加元素: c. add("hello' ...
- SSM整合案例--用户登录
实现用户登录案例,并进行非法拦截 实现当用户未登录时,无法跳转到出登录页面以外的任何页面,拦截用户仍在登陆页面:当用户登录成功即可跳转到其他页面 (1)导入依赖 <!-- https://mvn ...
- Windows下编译最新版ChezScheme
据说ChezScheme是最快的神级编译器,一秒钟几百万行,王垠说的2秒内编译自身绝不是夸张(看这里<揭秘Chez Scheme>,Scheme中文社区).ChezScheme由美国印第安 ...