第一个dubbo程序
开始研究rpc框架,传统的服务调用都是一个接口对应几个实现类,在分布式系统中,如何将请求平均得分发给各个节点,这就需要远程调用的负载均衡了
江湖规矩,不写hello world不算入门
dubbo官网dubbo官网的中文文档十分友好,就从文档入手,学习这个框架
这是官方的架构图,在这个图里,有着三个比较重要的角色,消费者,生产者,和注册中心,生产者会把自己的服务注册到注册中心,消费者会从注册中心订阅服务,对服务进行消费,有一个监视器会统计调用和被调用的次数
准备工作
有了一个简单的概念后,直接写代码吧,写代码之前,先要安装注册中心zookeeper,从官网下载zookeeper解压,修改conf文件夹下的zoo.cfg
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
# 主要修改这个地方,存放数据文件
dataDir=/usr/local/zookeeper/data
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
修改后进入bin目录执行./zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
创建项目,组织maven依赖
创建最外层的项目
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>dubbo-demo</artifactId>
<groupId>rpc</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service</artifactId>
<packaging>pom</packaging>
<modules>
<module>api</module>
<module>core</module>
<module>impl</module>
</modules>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.0</version>
</dependency>
<!-- 注册中心选用的zookeeper,要引入zookeeper的客户端 -->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
</dependencies>
</project>
创建消费者模块
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>service</artifactId>
<groupId>rpc</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>api</artifactId>
<dependencies>
<dependency>
<groupId>rpc</groupId>
<artifactId>core</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
创建接口定义模块,接口定义模块只定义接口结构和实体类,被生产者和消费者引用,本身不依赖任何模块(后期的单元测试里,引入core模块方便对代码进行单元测试,引入api模块就是远程接口调用了)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>service</artifactId>
<groupId>rpc</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>core</artifactId>
</project>
创建消费者模块
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>service</artifactId>
<groupId>rpc</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>impl</artifactId>
<dependencies>
<dependency>
<groupId>rpc</groupId>
<artifactId>core</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
项目结构如下
开始写代码
首先是core模块里接口的结构定义,嗯,就是这么简单
package com.demo.service.core;
public interface HelloService {
String sayHello(String world);
}
有了接口,接下来在impl模块里写他的实现类
package com.demo.service.impl;
import com.demo.service.core.HelloService;
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String word) {
return "hello, " + word + ".";
}
}
接下来要将这个服务注册到注册中心
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 随便取 -->
<dubbo:application name="dubbo_application"/>
<!-- 注册中心,zookeeper默认2181 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 本服务的端口号 -->
<dubbo:protocol name="dubbo" port="20880" />
<!-- 服务的接口,实现类 -->
<dubbo:service interface="com.demo.service.core.HelloService" ref="helloService"/>
<!-- spring的bean -->
<bean id ="helloService" class="com.demo.service.impl.HelloServiceImpl"/>
</beans>
消费者不需要定义接口,也不需要提供实现类,需要向注册中心订阅服务
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 随便取 -->
<dubbo:application name="dubbo_application"/>
<!-- 注册中心,需要知道去哪订阅 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 通过设置register可以只订阅,如果服务正在开发中,注册到注册中心后 -->
<!-- <dubbo:registry address="zookeeper://127.0.0.1:2181" register="false"/> -->
<!-- 启动时检查,出现了循环依赖,必须有一方先启动,通过此设置关闭检查 -->
<dubbo:consumer check="false"/>
<!-- url指定了点对点直连提供者,分布式最少是两个节点了,可以绕过注册中心,推荐用于开发测试环境 -->
<dubbo:reference id="helloService" interface="com.demo.service.core.HelloService" url="dubbo://localhost:20880">
<!-- 集群容错模式 出现失败重试其他服务器,默认是2 -->
<dubbo:method name="sayHello" retries="2"/>
</dubbo:reference>
</beans>
启动测试
首先是生产者
package com.demo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
public class Provider {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml");
context.start();
// 阻塞生产者
System.out.println(System.in.read());
}
}
启动,假装没看见红字-.-
接下来是消费者
package com.demo;
import com.demo.service.core.HelloService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Consumer {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
HelloService helloService = (HelloService) context.getBean("helloService");
System.out.println(helloService.sayHello("world"));
}
}
启动,生产者不能关闭
输出了hello world,教练,我入门了!
小结
可以使用zookeeper客户端查看服务的提供者
# 启动客户端
./zkCli.sh
ls /dubbo/com.demo.service.core.HelloService/providers
终端输出的就是提供者的信息,这里只有一个,用url转义了
解码之后就比较清楚了,记录了我们接口的一些配置信息.