Your First Dubbo Demo
Java RMI Introduction(RMI简介)
RMI是一种机制,允许访问或者调用另一台JVM上的对象或者方法。RMI是一种特殊的RPC,使用了支持OOP的java语言来实现。用户可以不经过IDL(Interface Define Language)就可以建造分布式的应用,依赖于轻松自然的接口的方式。
Java RMI Work Flow(RMI工作流程)
- 服务端向RMI登记服务并绑定接口;
- 客户端向RMI等级服务并获取远程接口;
- 客户端调用本地存根对象的方法,就像调用本地其他对象的那样;
- 本地存根对象压缩请求信息,并通过网络将之发送到服务端;
- 服务端的框架代码接受到了网络请求,并将之解压缩。
- 服务端根据请求的信息调用目标对象的方法,并且将结果压缩并通过网络返回给客户端。
RMI的一些概念
java RMI是java领域创建分布式应用的技术基石。EJB技术和当前分布式服务的框架依然继承着java RMI的基本概念。在RMI的调用中,有以下几个核心概念:
- 远程调用依赖于接口
- 将远程调用伪装成本地调用,在客户端叫做Stub object ,在服务端叫做Skeleton object。
- 服务在RMI注册中心被注册和发现。
对于第一点:客户端依赖的接口应当被服务端实现。
对于第二点:在J2SE 1.5及之前,客户端和服务器需要通过rmic来预编译Stub object和Skeleton object。之后的版本就不需要这么做了。
代码示例:
Server service registry
// 初始化服务实例
Hello obj = new HelloImpl();
// 创建存根对象
Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0); // #2
// 创建注册服务
Registry registry = LocateRegistry.createRegistry(1099); // #3
// 注册并绑定存根对象,客户端即可以通过Hello来找到服务
registry.rebind("Hello", stub); // #4
Client service look-up
// 获取注册中心实例
Registry registry = LocateRegistry.getRegistry();
// 寻找名字叫Hello的那个服务实例
Hello stub = (Hello) registry.lookup("Hello");
// 调用RMI远程调用
String response = stub.sayHello();
理解RMI的工作流程和基础概念是非常有帮助的,对于当前的分布式服务框架。
推荐阅读RMI 官方文档来获取等多的信息。
Basic Concepts of Dubbo(dubbo的基本概念)
目前分布式服务框架的基本概念和RMI是类似的。他们都使用java 接口作为服务契约,通过注册中心来注册和查询,使用代理隐藏了远程通信的细节。特别的,当Dubbo运行的时候有以下四种类型的角色
- 服务提供者,初始化的时候在指定端口暴露服务,在注册中心注册服务的地址和端口。
- 服务消费者,初始化的时候在注册中心订阅自己感兴趣的服务,获取服务提供商的地址列表
- 注册中心,注册和查找服务。存储服务提供者的地址,并将之发送给消费者。
- 监控中心,收集并监控服务提供者和消费者的运行状态,调用次数,调用延迟等。
- 运行容器,初始化并且加载服务提供者,管理运行周期。
部署阶段
- 初始化的时候在指定端口暴露服务,在注册中心注册服务的地址和端口。
- 初始化的时候在注册中心订阅自己感兴趣的服务,获取服务提供商的地址列表
运行阶段
- 注册中心将地址发送给服务消费者;
- 接收到地址列表后,服务消费者选择出其中的一个并调用。
- 调用期间,服务提供者和消费者的运行状态被发送给监控中心。
Dubbo Applications Based on API
Dubbo通常由spring组装起来。为了快速创建一个Dubbo应用的话,这里的这个例子放弃了复杂的配置,以面向Dubbo Api的方式创建了服务提供者和服务消费者。另外,本例子中不需要安装或者配置注册中心和监控中心。
在生产环境中,Dubbo服务通常需要和分布式服务注册中心配合起来,比如zookeeper。出于方便的考虑,dubbo提供了俩种方式来避免额外的关于建构注册中心的工作,分别是【namely direct connection】和【assembled podcast】。
本例中使用了后者来注册和查找服务。
Define Service Contract(定义服务契约)
public interface GreetingsService {
String sayHi(String name); // #1
}
定义了一个简单的服务契约,仅仅只有一个方法【sayHi】会被调用。
入参和返回值都是string类型的。
Provide Contract Implementation(提供契约实现)
public class GreetingsServiceImpl implements GreetingsService { // #1
@Override
public String sayHi(String name) {
return "hi, " + name; // #2
}
}
服务提供者需要实现服务契约的接口【GreetingsService】。
Implement Dubbo Service Provider(实现服务提供者)
public class Application {
public static void main(String[] args) throws IOException {
// 创建一个ServiceConfig 实例,类型是GreetingsService
ServiceConfig<GreetingsService> service = new ServiceConfig<>();
// 创建一个ApplicationConfig 实例,并将之组装到ServiceConfig实例中
service.setApplication(new ApplicationConfig("first-dubbo-provider"));
// 创建一个RegistryConfig 实例,并将之组装到ServiceConfig实例中。
// 因为注册中心使用的是上文提到的第二种方案,所以参数应该是【multicast://224.5.6.7:1234】
// 有效的assembled地址范围是224.0.0.0 - 239.255.255.255
service.setRegistry(new RegistryConfig("multicast://224.5.6.7:1234"));
// 将服务契约GreetingsService 组装到ServiceConfig实例中
service.setInterface(GreetingsService.class);
// 将服务提供者提供的GreetingsServicelmpl实例组装到ServiceConfig实例中
service.setRef(new GreetingsServiceImpl());
// 装配好足够的信息后,ServiceConfig实例开始将自己暴露在默认的端口20880。
service.export();
// 按任意键或ctrl-c退出以避免服务器停止。
System.in.read();
}
}
Implement Dubbo Service Consumer(实现dubbo的服务消费者)
public class Application {
public static void main(String[] args) {
// 创建一个指定类型为GreetingsService的ReferenceConfig 实例
ReferenceConfig<GreetingsService> reference = new ReferenceConfig<>(); // #1
// AplicatonConfig实例
reference.setApplication(new ApplicationConfig("first-dubbo-client")); // #2
// 创建RegistryConfig实例,地址必须和服务提供者一样
reference.setRegistry(new RegistryConfig("multicast://224.5.6.7:1234")); // #3
reference.setInterface(GreetingsService.class); // #4
// 从ReferenceConfig中获得一个GreetingsService的代理
GreetingsService greetingsService = reference.get(); // #5
// 通过GreetingsService代理执行远程调用
String message = greetingsService.sayHi("dubbo"); // #6
System.out.println(message); // #7
}
}
run (运行这个例子)
完整的例子可以从 https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-api中获得。通过maven或者直接使用ide都可以很方便运行这个例子。一个值得注意的是:因为使用了委派的方式来查找服务,运行的时候需要加上【-Djava.net.preferIPv4Stack=true】。
Build Example(构造实例代码)
- 下载代码:git clone https://github.com/dubbo/dubbo-samples.git
- Build:mvn clean package
$ git clone https://github.com/dubbo/dubbo-samples.git
$ cd dubbo-samples/dubbo-samples-api/
$ mvn clean package
INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building dubbo-samples-api 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ dubbo-samples-api ---
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.182 s
[INFO] Finished at: 2018-05-28T14:56:08+08:00
[INFO] Final Memory: 20M/353M
[INFO] ------------------------------------------------------------------------
Run the server(运行服务)
$ mvn -Djava.net.preferIPv4Stack=true -Dexec.mainClass=org.apache.dubbo.samples.provider.Application exec:java
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building dubbo-samples-api 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ dubbo-samples-api ---
log4j:WARN No appenders could be found for logger (org.apache.dubbo.common.logger.LoggerFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
first-dubbo-provider is running.
Run the server(运行客户端)
$ mvn -Djava.net.preferIPv4Stack=true -Dexec.mainClass=org.apache.dubbo.samples.consumer.Application exec:java
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building dubbo-samples-api 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ dubbo-samples-api ---
log4j:WARN No appenders could be found for logger (org.apache.dubbo.common.logger.LoggerFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
hi, dubbo
Quick Creation of A Dubbo Application
从 http://start.dubbo.io下载(跟spring.io下载boot项目类似)