Dubbo 是一款微服务框架,提供高性能 RPC 通信,服务发现,流量管理等服务治理能力,提供构建大规模微服务集群所需的整套解决方案。
本文讲述如何利用 Dubbo 快速构建一个完整的服务端 - 客户端程序,包括基于 XML,注解和 API 的方式实现一个 Dubbo 的 demo。
配置开发环境 本文使用 IntelliJ IDEA 作为 Dubbo 应用程序开发的 IDE。
安装 ZooKeeper Dubbo 推荐使用 ZooKeeper (下文简称为 zk)作用注册中心,为简单起见,本文搭建一个单机版的 zk 以供 Dubbo 应用程序使用。有关 zk 集群的搭建步骤,可参考 ZooKeeper的安装与部署 。
在 zk 官网下载最新版本的 zk 二进制安装包,解压,将 conf
目录下 zoo_sample.cfg
文件复制为 zoo.cfg
,然后在 zk 主目录执行命令,将 zk 启动起来。此时 zk 会监听默认的 2181 端口。
下载源代码 本文的 Dubbo 入门应用程序很简单,服务端接收到客户端请求,然后直接将消息返回给客户端。应用程序可以通过 XML、注解和 API 三种方式编写。
本文示例应用程序在 https://github.com/zonghaishang/dubbo-samples 可以下载。
下载后,使用 IDEA 打开,导入 pom.xml
所需的依赖后显示如下:
基于 XML 实现 Echo 服务端 定义服务端接口 EchoService
,暴露出来以供客户端使用:
1 2 3 4 5 6 7 package com.alibaba.dubbo.samples.echo.api;public interface EchoService { String echo (String message) ; }
接下来是接口的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.alibaba.dubbo.samples.echo.impl;import com.alibaba.dubbo.rpc.RpcContext;import com.alibaba.dubbo.samples.echo.api.EchoService;import java.text.SimpleDateFormat;import java.util.Date;public class EchoServiceImpl implements EchoService { public String echo (String message) { String now = new SimpleDateFormat ("HH:mm:ss" ).format(new Date ()); System.out.println("[" + now + "] Hello " + message + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); return message; } }
为了让 EchoService
对外正常提供服务,还需要一些额外的配置,通过 spring 配置声明以暴露服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <beans xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo ="http://dubbo.apache.org/schema/dubbo" xmlns ="http://www.springframework.org/schema/beans" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd" > <dubbo:application name ="echo-provider" /> <dubbo:registry address ="zookeeper://127.0.0.1:2181" /> <dubbo:protocol name ="dubbo" port ="20880" /> <bean id ="echoService" class ="com.alibaba.dubbo.samples.echo.impl.EchoServiceImpl" /> <dubbo:service interface ="com.alibaba.dubbo.samples.echo.api.EchoService" ref ="echoService" /> </beans >
最后是编写代码加载 spring 配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.alibaba.dubbo.samples.echo;import org.springframework.context.support.ClassPathXmlApplicationContext;public class EchoProvider { public static void main (String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext (new String []{"spring/echo-provider.xml" }); context.start(); System.in.read(); } }
Echo 服务端示例代码,以及各代码所在目录位置如下图所示:
启动 EchoProvider
,控制台输出:
[08/11/20 09:50:38:038 CST] main INFO zookeeper.ZookeeperRegistry: [DUBBO] Notify urls for subscribe url provider://192.168.3.3:20880/com.alibaba.dubbo.samples.echo.api.EchoService
打开一个新的终端,输入命令连接服务端:
然后输入执行接口调用命令:
1 dubbo>invoke com.alibaba.dubbo.samples.echo.api.EchoService.echo ("leehao.me" )
输出:
“leehao.me” elapsed: 0 ms.
说明已正常调用了服务端口的接口。
Echo 客户端 上面我们使用 telnet
命令调用服务端接口,现在我们编写 Dubbo 客户端来调用服务端接口。
客户端通过 spring 配置引用服务端接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <beans xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo ="http://dubbo.apache.org/schema/dubbo" xmlns ="http://www.springframework.org/schema/beans" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd" > <dubbo:application name ="echo-consumer" /> <dubbo:registry address ="zookeeper://127.0.0.1:2181" /> <dubbo:reference id ="echoService" check ="false" interface ="com.alibaba.dubbo.samples.echo.api.EchoService" /> </beans >
主要配置包括,使用 zk 作为注册中心,需要消费的服务接口,等。
然后,编写代码,加载 spring 配置,调用远程接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.alibaba.dubbo.samples.echo;import com.alibaba.dubbo.samples.echo.api.EchoService;import org.springframework.context.support.ClassPathXmlApplicationContext;public class EchoConsumer { public static void main (String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext (new String []{"spring/echo-consumer.xml" }); context.start(); EchoService echoService = (EchoService) context.getBean("echoService" ); String status = echoService.echo("Hello leehao!" ); System.out.println("echo result: " + status); } }
启动 EchoConsumer
,控制台输出:
echo result: Hello leehao!
基于注解实现 Dubbo 支持使用注解的方式来暴露服务接口。
Echo 服务端 在服务接口添加 @Service
注解,即可以暴露服务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.alibaba.dubbo.samples.echo.impl;import com.alibaba.dubbo.config.annotation.Service;import com.alibaba.dubbo.rpc.RpcContext;import com.alibaba.dubbo.samples.echo.api.EchoService;import java.text.SimpleDateFormat;import java.util.Date;@Service public class EchoServiceImpl implements EchoService { public String echo (String message) { String now = new SimpleDateFormat ("HH:mm:ss" ).format(new Date ()); System.out.println("[" + now + "] Hello " + message + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); return message; } }
然后,由 dubbo 将这个服务接口提升为 spring 容器的 bean,并负责配置的初始化和服务暴露:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 import com.alibaba.dubbo.config.ProtocolConfig;import com.alibaba.dubbo.config.ApplicationConfig;import com.alibaba.dubbo.config.ProviderConfig;import com.alibaba.dubbo.config.RegistryConfig;import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;public class AnnotationProvider { public static void main (String[] args) throws Exception { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext (ProviderConfiguration.class); context.start(); System.in.read(); } @Configuration @EnableDubbo(scanBasePackages = "com.alibaba.dubbo.samples.echo") static class ProviderConfiguration { @Bean public ProviderConfig providerConfig () { return new ProviderConfig (); } @Bean public ApplicationConfig applicationConfig () { ApplicationConfig applicationConfig = new ApplicationConfig (); applicationConfig.setName("echo-annotation-provider" ); return applicationConfig; } @Bean public RegistryConfig registryConfig () { RegistryConfig registryConfig = new RegistryConfig (); registryConfig.setProtocol("zookeeper" ); registryConfig.setAddress("localhost" ); registryConfig.setPort(2181 ); return registryConfig; } @Bean public ProtocolConfig protocolConfig () { ProtocolConfig protocolConfig = new ProtocolConfig (); protocolConfig.setName("dubbo" ); protocolConfig.setPort(20880 ); return protocolConfig; } } }
Echo 客户端 使用 @Reference
注解来标注需要消费的服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.alibaba.dubbo.samples.echo.refer;import com.alibaba.dubbo.config.annotation.Reference;import com.alibaba.dubbo.samples.echo.api.EchoService;import org.springframework.stereotype.Component;@Component public class EchoConsumer { @Reference private EchoService echoService; public String echo (String name) { return echoService.echo(name); } }
然后定义基于注解的消费者的启动代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 package com.alibaba.dubbo.samples.echo;import com.alibaba.dubbo.config.ApplicationConfig;import com.alibaba.dubbo.config.ConsumerConfig;import com.alibaba.dubbo.config.RegistryConfig;import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;import com.alibaba.dubbo.samples.echo.refer.EchoConsumer;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;public class AnnotationConsumer { public static void main (String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext (ConsumerConfiguration.class); context.start(); EchoConsumer echoService = context.getBean(EchoConsumer.class); String hello = echoService.echo("Hello world!" ); System.out.println("result: " + hello); } @Configuration @EnableDubbo(scanBasePackages = "com.alibaba.dubbo.samples.echo") @ComponentScan(value = {"com.alibaba.dubbo.samples.echo"}) static class ConsumerConfiguration { @Bean public ApplicationConfig applicationConfig () { ApplicationConfig applicationConfig = new ApplicationConfig (); applicationConfig.setName("echo-annotation-consumer" ); return applicationConfig; } @Bean public ConsumerConfig consumerConfig () { return new ConsumerConfig (); } @Bean public RegistryConfig registryConfig () { RegistryConfig registryConfig = new RegistryConfig (); registryConfig.setProtocol("zookeeper" ); registryConfig.setAddress("localhost" ); registryConfig.setPort(2181 ); return registryConfig; } } }
输出:
result: Hello world!
基于 API 实现 Dubbo 框架支持 API 的方式实现暴露服务和消费服务。
Echo 服务端 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.alibaba.dubbo.samples.echo;import com.alibaba.dubbo.config.ApplicationConfig;import com.alibaba.dubbo.config.RegistryConfig;import com.alibaba.dubbo.config.ServiceConfig;import com.alibaba.dubbo.samples.echo.api.EchoService;import com.alibaba.dubbo.samples.echo.impl.EchoServiceImpl;import java.io.IOException;public class EchoProvider { public static void main (String[] args) throws IOException { ServiceConfig<EchoService> service = new ServiceConfig <>(); service.setApplication(new ApplicationConfig ("java-echo-provider" )); service.setRegistry(new RegistryConfig ("zookeeper://127.0.0.1:2181" )); service.setInterface(EchoService.class); service.setRef(new EchoServiceImpl ()); service.export(); System.out.println("java-echo-provider is running." ); System.in.read(); } }
Echo 客户端 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.alibaba.dubbo.samples.echo;import com.alibaba.dubbo.config.ApplicationConfig;import com.alibaba.dubbo.config.ReferenceConfig;import com.alibaba.dubbo.config.RegistryConfig;import com.alibaba.dubbo.samples.echo.api.EchoService;public class EchoConsumer { public static void main (String[] args) { ReferenceConfig<EchoService> reference = new ReferenceConfig <>(); reference.setApplication(new ApplicationConfig ("java-echo-consumer" )); reference.setRegistry(new RegistryConfig ("zookeeper://127.0.0.1:2181" )); reference.setInterface(EchoService.class); EchoService greetingsService = reference.get(); String message = greetingsService.echo("Hello world!" ); System.out.println(message); } }
输出:
Hello world!
参考资料