背景java
本文将以 Dubbo 为例,介绍如何快速开发一个 Dubbo 应用。为了便于读者理解:git
首先会介绍一下传统的 RMI 的基本概念github
而后比较下现代的 RPC 框架与 RMI 的区别spring
再基于 Dubbo 提供的 API 展现最基本的 Dubbo 应用如何开发编程
最后介绍如何经过 start.dubbo.io 快速搭建 Dubbo 的脚手架工程api
Java RMI 简介网络
Java RMI (Remote Method Invocation) 远程方法调用,可以让客户端像使用本地调用同样调用服务端 Java 虚拟机中的对象方法。RMI 是面向对象语言领域对 RPC (Remote Procedure Call)的完善,用户无需依靠 IDL 的帮助来完成分布式调用,而是经过依赖接口这种更简单天然的方式。架构
Java RMI 工做原理app
一个典型的 RMI 调用以下图所示:框架
服务端向 RMI 注册服务绑定本身的地址;
客户端经过 RMI 注册服务获取目标地址;
客户端调用本地的 Stub 对象上的方法,和调用本地对象上的方法一致;
本地存根对象将调用信息打包,经过网络发送到服务端;
服务端的 Skeleton 对象收到网络请求以后,将调用信息解包;
而后找到真正的服务对象发起调用,并将返回结果打包经过网络发送回客户端。
(来源:https://www.cs.rutgers.edu/~pxk/417/notes/images/rpc-rmi_flow.png)
Java RMI 基本概念
Java RMI 是 Java 领域建立分布式应用的技术基石。后续的 EJB 技术,以及现代的分布式服务框架,其中的基本理念依旧是 Java RMI 的延续。在 RMI 调用中,有如下几个核心的概念:
经过接口进行远程调用
经过客户端的 Stub 对象和服务端的 Skeleton 对象的帮助将远程调用假装成本地调用
经过RMI 注册服务完成服务的注册和发现
对于第一点,客户端须要依赖接口,而服务端须要提供该接口的实现。对于第二点,在 J2SE 1.5 版本以前须要经过 rmic 预先编译好客户端的 Stub 对象和服务端的 Skeleton 对象。在以后的版本中,再也不须要事先生成 Stub 和 Skeleton 对象。
下面经过示例代码简单的展现 RMI 中的服务注册和发现:
服务端的服务注册
说明:
初始化服务对象实例;
经过 UnicastRemoteObject.exportObject 生成能够与服务端通信的 Stub 对象;
建立一个本地的 RMI 注册服务,监听端口为 1099。该注册服务运行在服务端,也能够单独启动一个注册服务的进程;
将 Stub 对象绑定到注册服务上,这样,客户端能够经过 Hello 这个名字查找到该远程对象。
客户端的服务发现
说明:
获取注册服务实例,在本例中,因为没有传入任何参数,假定要获取的注册服务实例部署在本机,并监听在 1099 端口上;
从注册服务中查找服务名为 Hello 的远程对象;
经过获取的 Stub 对象发起一次 RMI 调用并得到结果。
理解 RMI 的工做原理和基本概念,对掌握现代分布式服务框架颇有帮助,建议进一步的阅读 RMI 官方教材 [1]。
Dubbo 基本概念
现代的分布式服务框架的基本概念与 RMI 是相似的,一样是使用 Java 的 Interface 做为服务契约,经过注册中心来完成服务的注册和发现,远程通信的细节也是经过代理类来屏蔽。具体来讲,Dubbo 在工做时有如下四个角色参与:
服务提供者:启动时在指定端口上暴露服务,并将服务地址和端口注册到注册中心上。
服务消费者:启动时向注册中心订阅本身感兴趣的服务,以便得到服务提供方的地址列表。
注册中心 :负责服务的注册和发现,负责保存服务提供方上报的地址信息,并向服务消费方推送。
监控中心:负责收集服务提供方和消费方的运行状态,好比服务调用次数、延迟等,用于监控。
运行容器:负责服务提供方的初始化、加载以及运行的生命周期管理。
部署阶段
服务提供者在指定端口暴露服务,并向注册中心注册服务信息。
服务消费者向注册中心发起服务地址列表的订阅。
运行阶段
注册中心向服务消费者推送地址列表信息。
服务消费者收到地址列表后,从其中选取一个向目标服务发起调用。
调用过程服务消费者和服务提供者的运行状态上报给监控中心。
基于 API 的 Dubbo 应用
Dubbo 的应用通常都是经过 Spring 来组装的。为了快速得到一个能够工做的 Dubbo 应用,这里的示例摒弃了复杂的配置,而改用面向 Dubbo API 的方式来构建服务提供者和消费者,另外,注册中心和监控中心在本示例中也不须要安装和配置。
在生产环境,Dubbo 的服务须要一个分布式的服务注册中心与之配合,好比,ZooKeeper。为了方便开发,Dubbo 提供了直连[2]以及组播[3]两种方式,从而避免额外搭建注册中心的工做。在本例中,将使用组播的方式来完成服务的注册和发现。
定义服务契约
说明:
定义了一个简单的服务契约 GreetingsService,其中只有一个方法 sayHi 可供调用,入参是 String 类型,返回值也是 String 类型。
提供契约的实现
说明:
服务提供者须要实现服务契约 GreetingsService 接口。
该实现简单的返回一个欢迎信息,若是入参是 dubbo,则返回 hi, dubbo。
实现 Dubbo 服务提供方
说明:
建立一个 ServiceConfig 的实例,泛型参数信息是服务接口类型,即 GreetingsService。
生成一个 AplicatonConfig 的实例,并将其装配进 ServiceConfig。
生成一个 RegistryConfig 实例,并将其装配进 ServiceConfig,这里使用的是组播方式,参数是 multicast://224.5.6.7:1234。合法的组播地址范围为:224.0.0.0 - 239.255.255.255
将服务契约 GreetingsService 装配进 ServiceConfig。
将服务提供者提供的实现 GreetingsServiceImpl 的实例装配进 ServiceConfig。
ServiceConfig 已经具有足够的信息,开始对外暴露服务,默认监听端口是 20880。
为了防止服务端退出,按任意键或者 ctrl-c 退出。
在这里顺便给你们推荐一个架构交流群:617434785,里面会分享一些资深架构师录制的视频录像
实现 Dubbo 服务调用方
说明:
建立一个 ReferenceConfig 的实例,一样,泛型参数信息是服务接口类型,即 GreetingService。
生成一个 AplicatonConfig 的实例,并将其装配进 ReferenceConfig。
生成一个 RegistryConfig 实例,并将其装配进 ReferenceConfig,注意这里的组播地址信息须要与服务提供方的相同。
将服务契约 GreetingsService 装配进 ReferenceConfig。
从 ReferenceConfig 中获取到 GreetingService 的代理。
经过 GreetingService 的代理发起远程调用,传入的参数为 dubbo。
打印返回结果 hi, dubbo。
运行
完整的示例:
https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-api
在完整的示例中,因为配置了 exec-maven-plugin,能够很方便的在命令行下经过 maven 的方式执行。固然,您也能够在 IDE 里直接执行,可是须要注意的是,因为使用了组播的方式来发现服务,运行时须要指定:
-Djava.net.preferIPv4Stack=true。
★ 构建示例
经过如下的命令来同步示例代码并完成构建:
同步代码:git clone https://github.com/dubbo/dubbo-samples.git
构建:mvn clean package
当看到 BUILD SUCCESS 的时候代表构建完成,下面就能够开始进入运行阶段了。
★ 运行服务端
经过运行如下的 maven 命令来启动服务提供者:
当 first-dubbo-provider is running. 出现时,表明服务提供者已经启动就绪,等待客户端的调用。
★ 运行客户端
经过运行如下的 maven 命令来调用服务:
能够看到, hi, dubbo 是从服务提供者返回的执行结果。
快速生成 Dubbo 应用
Dubbo 还提供了一个公共服务快速搭建基于 Spring Boot 的 Dubbo 应用。访问 http://start.dubbo.io 并按照下图所示来生成示例工程:
说明:
在 Group 中提供 maven groupId,默认值是 com.example。
在 Artifact 中提供 maven artifactId,默认值是 demo。
在 DubboServiceName 中提供服务名,默认值是 com.example.HelloService。
在 DubboServiceVersion 中提供服务的版本,默认值是 1.0.0。
在 Client/Server 中选取本次构建的工程是服务提供者 (Server) 仍是服务消费者 (Client),默认值是 server。
使用 embeddedZookeeper 做为服务注册发现,默认为勾选。
是否激活 qos 端口,默认为不勾选,若是勾选能够经过 22222 端口访问。
点击 Generate Project 便可下载生成好的工程。
在本例中展现的是服务提供者,一样的,经过在生成界面选取 client 来生成对应的服务消费者。
★ 运行
用 IDE 打开生成好的工程,能够发现应用是一个典型的 Spring Boot 应用。程序的入口以下所示:
说明:
在 2181 端口上启动嵌入式 ZooKeeper。
启动 Spring Boot 上下文。
能够直接在 IDE 中运行,输出结果以下:
2018-05-28 16:59:38.072 INFO 59943 --- [ main] a.b.d.c.e.WelcomeLogoApplicationListener :
:: Dubbo Spring Boot (v0.1.0) : https://github.com/dubbo/dubbo-spring-boot-project
:: Dubbo (v2.0.1) : https://github.com/alibaba/dubbo
:: Google group : http://groups.google.com/group/dubbo
...
2018-05-28 16:59:39.624 INFO 59943 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 1.746 seconds (JVM running for 2.963)
说明:
输出中打印的以 dubbo. 开头的配置信息,定义在 main/resources/application.properties 中。
★ 经过 Telnet 管理服务
生成工程的时候若是选择了激活 qos 的话,就能够经过 telnet 或者 nc 来管理服务、查看服务状态。
目前 qos 支持如下几个命令,更详细的信息请查阅官方文档[4]:
ls:列出消费者、提供者信息
online:上线服务
offline:下线服务
help:联机帮助
总结
在本文中,从 RMI 开始,介绍了 Java 领域分布式调用的基本概念,也就是基于接口编程、经过代理将远程调用假装成本地、经过注册中心完成服务的注册和发现。
而后为了简单起见,使用简单的组播注册方式和直接面向 Dubbo API 编程的方式介绍了如何开发一个 Dubbo 的完整应用。深刻的了解 ServiceConfig 和 ReferenceConfig 的用法,对于进一步的使用 Spring XML 配置、乃至 Spring Boot 的编程方式有这很大的帮助。
最后,简单的介绍了如何经过 Dubbo 团队提供的公共服务 start.dubbo.io 快速搭建基于 Spring Boot 的 Dubbo 应用,并经过 qos 来作 Dubbo 服务的简单运维。