0. Dubbo 简介
Dubbo 是一个开源的 RPC 框架。详情见 Dubbo官网
1. 安装注册中心
ZooKeeper 是常用的注册中心之一。
下载地址
解压:
sudo tar -zxvf zookeeper-3.4.10.tar.gz
复制代码
配置 ZooKeeper,将 zookeeper-3.4.10/conf
下的 zoo_sample.cfg
复制一份,重命名为 zoo.cfg
cd zookeeper-3.4.10/conf
cp zoo_sample.cfg ./zoo.cfg
复制代码
配置采用默认的就可以。
配置环境变量
# ZooKeeper Env
export ZOOKEEPER_HOME=/xxx/xxx/zookeeper-3.4.8
export PATH=$PATH:$ZOOKEEPER_HOME/bin
复制代码
生效环境变量:
启动 ZooKeeper
zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /root/soft/zookeeper-3.4.10/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
复制代码
说明启动成功了。
2. 创建生产者(dubbomall-user)
新建一个空白的 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>dubbomall</artifactId>
<groupId>com.zdran</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbomall-user</artifactId>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring.version>4.1.3.RELEASE</spring.version>
<dubbo.version>2.5.3</dubbo.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<!-- 排除传递spring依赖 -->
<artifactId>spring</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- 导入zookeeper依赖 -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.3.3</version>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
复制代码
创建一个 Service:
public interface UserService {
/**
* 返回 hello 字符串
*
* @param name 姓名
* @return
*/
String sayHello(String name);
}
具体实现类:
@Service
public class UserServiceImpl implements UserService {
@Override
public String sayHello(String name) {
return "hello," + name;
}
}
复制代码
在 resources
下创建一个 dubbo-server.xml
dubbo 的配置文件,内容如下:
<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-4.0.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="dubbomall-user"/>
<!-- 这里使用的注册中心是zookeeper -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" client="zkclient"/>
<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20881"/>
<!-- 将该接口暴露到dubbo中 -->
<dubbo:service interface="com.zdran.dubbomall.user.service.UserService" ref="userServiceImpl"/>
<!-- 将具体的实现类加入到Spring容器中 -->
<bean id="userServiceImpl" class="com.zdran.dubbomall.user.service.impl.UserServiceImpl"/>
</beans>
复制代码
创建一个启动类:
public class ApplicationMain {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]
{"dubbo-server.xml"});
context.start();
System.in.read();
}
}
复制代码
注意:dubbo-server.xml 的路径是从 resources 下开始的
启动这个 Main 方法。
3. 查看服务注册情况
然后我们去 ZooKeeper 查看一下服务注册情况
连接 zookeeper
zkCli.sh -server 127.0.0.1:2181
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
[zk: 127.0.0.1:2181(CONNECTED) 0]
复制代码
出现上面的情况说明连接成功了。
使用 ls /
列出当前 zk 上的所有 节点
[zk: 127.0.0.1:2181(CONNECTED) 0] ls /
[dubbo, zookeeper]
复制代码
我们看到有一个 dubbo 的节点。查看一下这个节点下面的服务
[zk: 127.0.0.1:2181(CONNECTED) 1] ls /dubbo
[com.zdran.dubbomall.user.service.UserService]
复制代码
这次我们看到了我们自己定义的 Service 的包路径,然后我们再看一下,这个节点下面的东西
[zk: 127.0.0.1:2181(CONNECTED) 14]
ls /dubbo/com.zdran.dubbomall.user.service.UserService
[consumers, configurators, routers, providers]
复制代码
重点看一下 consumers(消费者)、providers(生产者) ,这两个下面的节点分别对应该服务的消费者和生产者。
我们现在只有生产者,所以先看一下生产者下面的节点
[zk: 127.0.0.1:2181(CONNECTED) 15] ls /dubbo/com.zdran.dubbomall.user.service.UserService/providers
[dubbo%3A%2F%2F192.168.56.1%3A20881%2Fcom.zdran.dubbomall.user.service.UserService
%3Fanyhost%3Dtrue%26application%3Ddubbomall-user%26dubbo%3D2.5.3%26interface
%3Dcom.zdran.dubbomall.user.service.UserService%26methods%3DsayHello%26pid
%3D5740%26side%3Dprovider%26timestamp%3D1542032564897]
复制代码
现在不不需要关心这堆看似乱码的字符串,主要注意这里面的两个信息,一个是 IP,如果不出意外的话,应该是你本地的 IP 地址,准确的说是,你启动 Main 方法的那台机器的 IP,另一个是我们暴露的接口的包路径以及方法名。
如果你看过第一篇文章的话,我们当时实现的最简单的一个 RPC 框架,其中的注册中心是不是就是通过这两个信息来调用的远程服务。
消费者通过服务名,从注册中心获取对应的 IP 地址,然后来与远程服务通信。
下面我们实现一个消费者。
4. 创建消费者(dubbomall-web)
重新创建一个项目。
添加生产者依赖。
<?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>dubbomall</artifactId>
<groupId>com.zdran</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbomall-web</artifactId>
<dependencies>
<dependency>
<groupId>com.zdran</groupId>
<artifactId>dubbomall-user</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
复制代码
导入 dubbo 服务,在 resources 目录下创建dubbo-server.xml
,内容如下:
<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-4.0.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="dubbo-web"/>
<!-- 这里使用的注册中心是zookeeper -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" client="zkclient"/>
<!-- 从注册中心中查找服务 -->
<dubbo:reference id="userService" interface="com.zdran.dubbomall.user.service.UserService"/>
</beans>
复制代码
实现 RPC 调用,创建一个启动类,实现 main 方法,调用远程的 UserService 服务
public class ApplicationMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[]{"dubbo-server.xml"});
context.start();
UserService demoService = (UserService) context.getBean("userService");
String hello = demoService.sayHello("dubbo");
System.out.println(hello);
}
}
复制代码
运行一下这个 main 方法,由于机器性能、网络问题等原因,调用结果可能要等待 10s 左右,才能得到结果。
5. 查看注册中心的消费者
我们去注册中心看一下消费者的情况。
注意:你要先运行消费者的 main 方法,然后运行期间不断的查看注册中心的消费者节点,才能看到。因为消费者一旦执行结束后,该节点就会自动被注册中心删除掉了
[zk: 127.0.0.1:2181(CONNECTED) 22] ls /dubbo/com.zdran.dubbomall.user.service.UserService/consumers
[]
[zk: 127.0.0.1:2181(CONNECTED) 23] ls /dubbo/com.zdran.dubbomall.user.service.UserService/consumers
[]
[zk: 127.0.0.1:2181(CONNECTED) 24] ls /dubbo/com.zdran.dubbomall.user.service.UserService/consumers
[]
[zk: 127.0.0.1:2181(CONNECTED) 25] ls /dubbo/com.zdran.dubbomall.user.service.UserService/consumers
[]
[zk: 127.0.0.1:2181(CONNECTED) 26] ls /dubbo/com.zdran.dubbomall.user.service.UserService/consumers
[consumer%3A%2F%2F192.168.56.1%2Fcom.zdran.dubbomall.user.service.UserService
%3Fapplication%3Ddubbo-web%26category%3Dconsumers%26check%3Dfalse%26dubbo
%3D2.5.3%26interface%3Dcom.zdran.dubbomall.user.service.UserService%26methods
%3DsayHello%26pid%3D4092%26side%3Dconsumer%26timestamp%3D1542034195230]
复制代码
还是看其中的两个重要信息,第一个是 IP,这个 IP 是消费者的 IP,准确的说是,消费者的那个 main 方法执行的机器 IP。因为我是在同一个机器上启动的消费者和生产者,所以这个 IP 是一样的。第二个就是接口的全路径以及方法名。有这两个信息,消费者就能从注册中心获取对应服务的 IP,发起调用了。
PS:消费者不应该直接依赖生产者。正确的做法是抽出一个 API 模块,由生产者来实现 API 的接口,然后消费者依赖 API。
就像我们在写代码时不会直接使用 UserServiceImpl ,而是使用 UserService,一样的道理。
评论