使用注解方式构建dubbo服务
前言
Dubbo是阿里巴巴开源的一个高性能优秀的服务框架,通过使用RPC实现服务调用。在业界尤其国内使用广泛。下面就从头开始构建dubbo的简单demo,配置使用注释方式完成,以zookeeper为注册中心。
构建项目
以 IntelliJ IDEA 为例,创建一个多模块的项目,项目结构如下图所示。
其中,dubbo-demo是父项目,其下有3个子项目,分别是:
- dubbo-server 服务提供者,提供服务接口具体实现,对外提供服务。
- dubbo-client 服务调用者,充当客户端角色,调用服务。
- dubbo-api 定义接口,为以上两者充当桥梁作用,目的解耦。
需要注意的是,dubbo-demo作为父项目,它的依赖可用以子项目,且其packaging
的值为pom
。
其他3个项目即为普通的maven项目,打包方式为jar(packaging),dubbo-server及dubbo-client均依赖dubbo-api。
以dubbo-server为例,其pom.xml(部分)为
标注第一个框指明其继承的父项目,第二个框表示依赖了dubbo-api。
dubbo-client与此相似。
前期准备
本文使用zookeeper作为服务注册中心,首先要保证zookeeper服务可以正常运行。这里使用本地zookeeper为例。
进入ZOOKEEPER_HOME/bin 目录,执行
sudo ./zkServer.sh start
命令即可。默认zookeeper端口为2181,不必修改。
定义接口
为解耦以及架构清晰,于是有了dubbo-api子项目。当然这个项目不是必须的,接口的定义也可以放在dubbo-server(即服务提供方),但为以后扩展方便,对外接口统一由dubbo-api定义。
package com.wthfeng.dubboapi.service;
/**
* @author wangtonghe
* @since 2018/9/6 09:57
*/
public interface HelloService {
String sayHello(String name);
}
很简单,定义一个需要实现的接口即可。
提供服务
dubbo-server负责暴露并提供服务。
1. 首先,编写一个定义dubbo配置类。
@Configuration
public class DubboConfig {
@Resource
private DubboProperties dubboProperties;
/**
* 应用名配置,等同于 <dubbo:application name="xxx" />
*
* @return ApplicationConfig
*/
@Bean
public ApplicationConfig applicationConfig() {
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName(dubboProperties.getName());
return applicationConfig;
}
/**
* 注册中心配置,等同于 <dubbo:registry address="url" />
*
* @return RegistryConfig
*/
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress(dubboProperties.getAddress());
registryConfig.setClient(dubboProperties.getClient());
return registryConfig;
}
/**
* 协议配置,等同于 <dubbo:protocol name="dubbo" port="20880" />
*
* @return ProtocolConfig
*/
@Bean
public ProtocolConfig protocolConfig() {
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setName(dubboProperties.getProtocolName());
protocolConfig.setPort(dubboProperties.getProtocolPort());
return protocolConfig;
}
注释写的很清楚了,DubboProperties 是加载的一个配置类,内容如下:
application.dubbo.demo.server.name=dubbo-server
application.dubbo.demo.server.address=zookeeper://127.0.0.1:2181
application.dubbo.demo.server.client=zkclient
application.dubbo.demo.server.protocolName=dubbo
application.dubbo.demo.server.protocolPort=20880
从配置类可以看出,注册中心使用的是zookeeper,这个稍后再说,先这样写着。下面看看暴露服务的设置。
2. 编写一个实现类实现要暴露的接口。
package com.wthfeng.dubboserver.service;
import com.alibaba.dubbo.config.annotation.Service;
import com.wthfeng.dubboapi.service.HelloService;
/**
* @author wangtonghe
* @since 2018/9/5 17:46
*/
@Service(timeout = 5000, version = "1.0", group = "demo-dubbo")
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
String value = "Hello " + name + " !";
return value;
}
}
注意:@Service 这个注解是dubbo的用于暴露服务的注解。而不是spring的那个注解!其中timeout为调用该服务的超时时间,version为版本号,group为分组。interface这里指HelloService,
interface、group、version三者确定一个服务。
3. 最后,需要在spring boot 启动类中配置dubbo的暴露服务的包的扫描路径,即将HelloServiceImpl这样的类放于一个包中使其能扫描到。
@SpringBootApplication
@DubboComponentScan(value = "com.wthfeng.dubboserver.service")
public class DemoServerApplication {
public static void main(String[] args) {
SpringApplication.run(DemoServerApplication.class, args);
}
}
至此,服务提供者的配置就完成了。下面看看服务消费者的配置。
消费服务
1. 设置配置文件
配置文件和服务提供者的类似,直接贴出了。
@Configuration
public class DubboClientConfig {
@Resource
private DubboProperties dubboProperties;
/**
* 应用名配置,等同于 <dubbo:application name="xxx" />
*
* @return ApplicationConfig
*/
@Bean
public ApplicationConfig applicationConfig() {
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName(dubboProperties.getName());
return applicationConfig;
}
/**
* 注册中心配置,等同于 <dubbo:registry address="url" />
*
* @return RegistryConfig
*/
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress(dubboProperties.getAddress());
registryConfig.setClient(dubboProperties.getClient());
return registryConfig;
}
/**
* 协议配置,等同于 <dubbo:protocol name="dubbo" port="20880" />
*
* @return ProtocolConfig
*/
@Bean
public ProtocolConfig protocolConfig() {
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setName(dubboProperties.getProtocolName());
protocolConfig.setPort(dubboProperties.getProtocolPort());
return protocolConfig;
}
}
2. 引用服务
@Component
public class BusinessService {
/**
* 引用服务,与 <dubbo:reference/> 等同。注意这里的version和group要和暴露服务的一致
*/
@Reference(version = "1.0", group = "demo-dubbo")
private HelloService helloService;
public void testHello(String name) {
String str = helloService.sayHello(name);
System.out.println("调用结果:" + str);
}
}
@Reference 注解为dubbo服务调用的注解,和dubbo中@Service 注解对应,尤其是version和group以及interface字段两者一定要一致。
3. 设置扫描包地址
@SpringBootApplication
@DubboComponentScan(value = "com.wthfeng.democlient.service")
public class DemoClientApplication {
public static void main(String[] args) {
SpringApplication.run(DemoClientApplication.class, args);
}
}
在dubbo-client项目启动类中,添加dubbo包扫描地址。
项目启动
据此,dubbo项目构建完毕。为测试方便,在dubbo-client的测试包下添加一个测试类,如下
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoClientApplicationTests {
@Resource
private BusinessService businessService;
@Test
public void contextLoads() {
businessService.testHello("dubbo");
}
}
在zookeeper正常运行的前提下,先启动dubbo-server,再运行此测试用例。输出:
调用结果:Hello dubbo !
表示构建成功。
项目架构
目前,我们可以把上述项目及组件整理分类一下。可分为服务调用房,服务提供者,注册中心,(dubbo-api为系统解耦,不作为系统部分)。
根据dubbo文档及资料描述,流程如下:
- 启动zookeeper及服务提供方(Provider)
- Provider 向注册中心注册服务(告诉zookeeper我都有什么服务)
- Consumer(消费方)订阅需要的服务(告诉zookeeper我需要什么服务)
- 注册中心告知消费者服务所在地址(zookeeper告知消费者其需要服务的地址列表)
- 消费者调用服务
流程图如下(来自官网):
其他补充
- 图中5表示,消费者和提供服务者,需要定时向监控中心发送调用次数等的数据,便于监控中心统计,此处不是服务所必须的
- 注册中心还需时刻保持与服务提供者的联系(通过心跳包),以确定提供者在线,若其下线,需及时告知消费者。
- 图中3也表示,当服务列表变化时,向消费者推送变更通知。