Dubbo 学习笔记(一) Hello,Dubbo

Dubbo 学习笔记(一) Hello,Dubbo


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

生效环境变量:

source .bashrc

启动 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,一样的道理。

转载请注明出处
本文链接:http://zdran.com/20181113.html