前言
上一篇:SpringBoot与Dubbo的集成、配置与部署(1)准备工作
在上一篇的内容中,我们已经完成了基本的准备工作:下载、部署并启动了ZooKeeper,并安装部署了Dubbo Admin控制台。在这篇日志中,主要将记录如何在SpringBoot项目中集成、配置并构筑Dubbo服务提供者。
虽然Dubbo对于web分布式架构的支撑最终还是会回到http网络协议上来,但是与Eureka有所不同的是,Dubbo在默认情况下对http协议进行了更多的封装,使开发人员在编写代码的时候,更难以察觉到运行在其背后的http网络通信协议。而Eureka则是将http协议暴露在外,开发人员在编写代码调用远程服务的时候,很容易感受到其http的本质。
我们可以通过以下的示意代码片段简单查看一下两者在调用远程服务时的区别:
Eureka消费者
//...
//注入RestTemplate
@Autowired
RestTemplate restTemplate;
//...
//封装Http头部信息,指明请求数据的格式
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
HttpEntity httpEntity = new HttpEntity(requestParameter,headers);
//使用RestTemplate发起远程调用
ResponseEntity<String> response = this.restTemplate.postForEntity( url, httpEntity , String.class );
Dubbo消费者
//指认dubbo服务者所提供的接口
@Reference
private DemoDubboManager demoDubboManager;
//...
//调用远程服务
this.demoDubboManager.helloDubbo();
造成两者之间区别的主要原因在于,消费者在调用Dubbo服务者所提供的远程接口时,需要先将服务者所暴露的接口以jar包的方式添加到自身的classpath中,如此即能在代码中直接调用jar包中的接口,而Dubbo会接管该jar包中的接口,并以网络通讯协议去连接服务者之所在。
依赖
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>2.7.7</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j2</artifactId>
</exclusion>
</exclusions>
</dependency>
依赖非常简单,值得注意的是,由于需要与SpringBoot架构进行整合,而开发人员往往在SpringBoot架构的配置中会自行单独配置日志log4j2,因此在引入dubbo资源的时候,可能需要排除其中自带的log4j2资源包。
配置
#spring服务名
spring.application.name=dubboProvider1
#dubbo服务名,可以不配置,缺省使用springboot服务名
#dubbo.application.name=dubboProvider1
#ZooKeeper地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
#指定dubbo使用的协议、端口
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
#指定注册到zookeeper上超时时间,单位是毫秒。如果在连接zookeeper时报出超时错误,可以尝试将该参数值增大
dubbo.registry.timeout=10000
#指定提供dubbo服务的包。该包中存放的可以是接口类。
dubbo.scan.base-packages=com.freezingxu.service.dubbo
配置项也比较简单。唯一需要注意的地方在于上述配置中的最后一项,该项指向的是我们自己的工程Service层接口代码所在的包路径。
接口代码
在上述配置文件所指向的包名下,根据实际的业务需求,创建service接口:
package com.freezingxu.service.dubbo;
import java.lang.reflect.InvocationTargetException;
public interface KcCateManager {
public String showKcCateListWithJson(String requestStr);
}
可以看到,这是一个标准的Java接口类,其中包含了一个接口定义。该接口接收一个字符串形式的入参,并返回一个字符串结果。
接下来对该接口可以有两种不同的处理方式:
方式一:
由于这是一个标准Java接口,并且不带有任何第三方要素,因此可以直接将该接口定义所在的工程单独打包为jar包。在真正的Dubbo服务提供者工程中,引入该jar包,并另编写类实现该接口。
这一方式的好处在于能够事先将需要暴露在分布式环境中的接口先定义好,与真正的实现类相互独立拆分,形成类似于API一样的概念。而Dubbo消费者仅需在自己的classpath中引入该接口jar包即可,无需引入接口的真正实现。
方式二:
在接口类所在的工程中,直接编写类实现该接口,并根据实际的业务需求编写其中的代码逻辑。然后将整个工程代码一起打包成jar资源,引入消费者工程的classpath中。
我在这儿偷了一个懒,我使用了方式二进行代码的编写,将接口及实现类放置在同一个项目工程中,但是在打包jar时,只单独选择了接口类进行打包。
实现类代码
实现类的代码非常简单,如下所示:
//...
import org.apache.dubbo.config.annotation.Service;
//...
@Service //使用dubbo包名下的Service注解,以支持Dubbo架构
public class KcCateManagerImpl implements KcCateManager{
//...
//dubbo 接口的实现
public String showKcCateListWithXml(String requestStr){
//...
}
}
要注意的地方是,在类头部注解中出现的“@Service”,并不是普通的Spring注解,而是Dubbo相关包中的注解。其完整的包路径为:
org.apache.dubbo.config.annotation.Service
发布dubbo服务者
好了,实现类中具体的业务逻辑需要视各个项目的不同而定,在此就不再多做赘述。完成了dubbo服务提供者的编码后,就可以打包发布到Tomcat中了。
具体打包和发布的过程不再多做赘述,我们只是看一下发布的结果。需要注意的是,必须要实现启动ZooKeeper服务。
在启动日志信息中,可以看到出现了大量与 dubbo和zookeeper相关的信息,提示我们服务已经启动,并且连接到了ZooKeeper服务。
此时,我们可以通过Dubbo Admin面板来查看服务是否被正常发布:
在面板中,能够看到已经注册到了ZooKeeper中的服务,其名称以接口类的形式出现,并且目前显示“没有消费者”。
至此,Dubbo服务发布者的配置和部署已经完成。