vlambda博客
学习文章列表

dubbo 2.7 的 3种入门案例实战

回顾

大家好,我是老马。

上一节我们一起学习了 。

本文大家一起来学习下 dubbo 的入门案例,共计 3 种方式,总有一款适合你!

Dubbo

Dubbo是一个分布式的高性能RPC框架,可为应用程序提供服务导入/导出功能。

架构

架构

节点角色说明

角色说明

调用关系说明

  • 服务容器负责启动,加载,运行服务提供者。

  • 服务提供者在启动时,向注册中心注册自己提供的服务。

  • 服务消费者在启动时,向注册中心订阅自己所需的服务。

  • 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

这样直接看一遍还是没啥感觉,我们通过 3 种方式的入门案例,加深一下大家的理解。

基于 api 实现

个人理解最简单的 dubbo 入门案例应该是基于 api 的定义实现,因为 dubbo 是完全可以独立于 spring 存在的。

虽然 dubbo 可以和 spring 进行很好的整合,但是最基本的 api 定义显然更容易理解。

pom.xml 定义

引入最基本的依赖

<properties>
    <source.level>1.8</source.level>
    <target.level>1.8</target.level>
    <dubbo.version>2.7.7</dubbo.version>
    <junit.version>4.12</junit.version>
    <maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo</artifactId>
        <version>${dubbo.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-dependencies-zookeeper</artifactId>
        <version>${dubbo.version}</version>
        <type>pom</type>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven-compiler-plugin.version}</version>
            <configuration>
                <source>${source.level}</source>
                <target>${target.level}</target>
            </configuration>
        </plugin>
    </plugins>
</build>

接口定义

接口作为客户端和服务端之间的约定,如下:

public interface DemoService {

    String say();

}

越抽象越简单,意味着越稳定。

一般公司中,服务端系统都会将接口打包上传到公司的私服 neuxs 仓库,便于客户端下载使用。

服务端

服务端针对上面的接口,实现如下:

public class DemoServiceImpl implements DemoService {
    @Override
    public String say() {
        return "hello";
    }
}

服务端启动该代码:

import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;

import java.util.concurrent.CountDownLatch;

public class Server {
    private static String zookeeperHost = System.getProperty("zookeeper.address""127.0.0.1");

    public static void main(String[] args) throws Exception {
        ServiceConfig<DemoService> service = new ServiceConfig<>();
        service.setApplication(new ApplicationConfig("first-dubbo-provider"));
        service.setRegistry(new RegistryConfig("zookeeper://" + zookeeperHost + ":2181"));
        service.setInterface(DemoService.class);
        service.setRef(new DemoServiceImpl());
        service.export();

        System.out.println("dubbo service started");
        new CountDownLatch(1).await();
    }

}

这里我们依赖了 zookeeper 作为注册中心,你需要首先启动 zookeeper。

zookeeper 入门使用

客户端

客户端和服务端的唯一依赖就是接口,这样以后服务端变更客户端基本可以不关心。

这位分布式系统中的协作开发,提供了极大的便利性。

import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;

/**
 * @author 老马啸西风
 * @since 1.0.0
 */

public class Client {

    private static String zookeeperHost = System.getProperty("zookeeper.address""127.0.0.1");

    public static void main(String[] args) {
        ReferenceConfig<DemoService> reference = new ReferenceConfig<>();
        reference.setApplication(new ApplicationConfig("first-dubbo-consumer"));
        reference.setRegistry(new RegistryConfig("zookeeper://" + zookeeperHost + ":2181"));
        reference.setInterface(DemoService.class);
        DemoService service = reference.get();
        String message = service.say();
        System.out.println(message);
    }

}

日志输出如下:

hello

虽说用起来非常简单,但是底层的原理还是相对比价复杂的。我们后续会展开 rpc 手写实现系列,感兴趣的可以关注一波。

spring xml 配置

说明

spring xml 配置曾经风靡一时,我们这里作为经典版本给大家演示一下。

毕竟 dubbo 和 spring 的整合,使用起来才是更加方便。

宝剑配英雄,更能章显威力。

maven 依赖

这次需要和 spring 整合,所以新增了 spring 的相关依赖。

<properties>
    <maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
    <source.level>1.8</source.level>
    <target.level>1.8</target.level>
    <dubbo.version>2.7.7</dubbo.version>
    <spring.version>4.3.16.RELEASE</spring.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo</artifactId>
        <version>${dubbo.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-dependencies-zookeeper</artifactId>
        <version>${dubbo.version}</version>
        <type>pom</type>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven-compiler-plugin.version}</version>
            <configuration>
                <source>${source.level}</source>
                <target>${target.level}</target>
            </configuration>
        </plugin>
    </plugins>
</build>

接口定义和实现

和上面一样,此处不再赘述。

内嵌 zk

这里官方 demo 引入了一个内嵌的 zk 类 EmbeddedZooKeeper,这样基本的学习演示,就可以不用下载 apache zookeeper 了。

服务端

服务端作为服务的提供者,声明如下:

public class BasicProvider {

    public static void main(String[] args) throws Exception {
        new EmbeddedZooKeeper(2181false).start();
        // wait for embedded zookeeper start completely.
        Thread.sleep(1000);

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-demo-provider.xml");
        context.start();

        System.out.println("dubbo service started");
        new CountDownLatch(1).await();
    }
}

其中 dubbo-demo-provider.xml 是 xml 配置,如下:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
>

    <context:property-placeholder/>

    <dubbo:application name="demo-provider"/>

    <dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>

    <bean id="demoService" class="com.github.houbb.dubbo.learn.basic.DemoServiceImpl"/>

    <dubbo:service interface="com.github.houbb.dubbo.learn.basic.DemoService" ref="demoService"/>

</beans>

客户端

实现如下:

package com.github.houbb.dubbo.learn.basic;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BasicConsumer {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-demo-consumer.xml");
        context.start();
        DemoService demoService = (DemoService) context.getBean("demoService");
        String hello = demoService.say();
        System.out.println(hello);
    }

}

其中 dubbo-demo-consumer.xml 的实现如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
>

    <context:property-placeholder/>

    <dubbo:application name="demo-consumer"/>

    <dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>

    <dubbo:reference id="demoService" check="true" interface="com.github.houbb.dubbo.learn.basic.DemoService"/>

</beans>

测试

首先启动服务端,然后启动客户端。

启动客户端时报错如下:

[DUBBO] qos-server can not bind localhost:22222dubbo version: 2.6.4current host: 169.254.68.252
java.net.BindExceptionAddress already in usebind

[DUBBO] Fail to start qos server: , dubbo version: 2.6.4current host: 169.254.68.252
java.net.BindExceptionAddress already in usebind
  • 问题原因

Qos=Quality of Service,qos是Dubbo的在线运维命令,可以对服务进行动态的配置、控制及查询。

consumer启动时qos-server也是使用的默认的22222端口,但是这时候端口已经被provider给占用了,所以才会报错的。

  • 解决方案

我们将 dubbo-demo-consumer.xml application 配置进行调整,指定一个不同的端口即可。

<!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
<dubbo:application name="demo-consumer">
    <dubbo:parameter key="qos.enable" value="true" />
    <dubbo:parameter key="qos.accept.foreign.ip" value="false" />
    <dubbo:parameter key="qos.port" value="33333" />
</dubbo:application>

重新启动测试通过。

注解版本

说明

个人最喜欢的还是注解版本,实现起来更加优雅。

定义

接口定义和内嵌的 zk 和上面一样,不再赘述。

服务端

代码

注意,这里使用 @DubboService 修饰实现类。

package com.github.houbb.dubbo.learn.annotation.provider;

import com.github.houbb.dubbo.learn.annotation.api.DemoService;
import org.apache.dubbo.config.annotation.DubboService;

/**
 * @author 老马啸西风
 * @since 1.0.0
 */

@DubboService
public class DemoServiceImpl implements DemoService {
    @Override
    public String say() {
        return "hello";
    }
}

服务端配置类:

package com.github.houbb.dubbo.learn.annotation.provider;

import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

/**
 * @author binbin.hou
 * @since 1.0.0
 */

@Configuration
@EnableDubbo(scanBasePackages = "com.github.houbb.dubbo.learn.annotation.provider")
@PropertySource("classpath:dubbo-provider.properties")
public class ProviderConfiguration {
}

这里通过 @EnableDubbo 执行扫包操作。

  • dubbo-provider.properties 配置

内容如下:

dubbo.application.name=annotation-provider
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880

客户端

package com.github.houbb.dubbo.learn.annotation.consumer;

import com.github.houbb.dubbo.learn.annotation.api.DemoService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Component;

/**
 * @author 老马啸西风
 * @since 1.0.0
 */

@Component
public class AnnotationAction {

    @DubboReference
    private DemoService demoService;

    public String say() {
        return demoService.say();
    }

}

这里通过 @DubboReference 注解注入依赖的服务。

客户端配置注解如下:

package com.github.houbb.dubbo.learn.annotation.consumer;

import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

/**
 * @author 老马啸西风
 * @since 1.0.0
 */

@Configuration
@EnableDubbo(scanBasePackages = "com.github.houbb.dubbo.learn.annotation.client")
@PropertySource("classpath:dubbo-consumer.properties")
@ComponentScan(value = {"com.github.houbb.dubbo.learn.annotation.consumer"})
public class ConsumerConfiguration {
}

其中 dubbo-consumer.properties 配置如下:

# dubbo-consumer.properties
dubbo.application.name=annotation-consumer
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.consumer.timeout=3000

测试

启动服务端

package com.github.houbb.dubbo.learn.annotation;


import com.github.houbb.dubbo.learn.annotation.provider.ProviderConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.concurrent.CountDownLatch;

public class AnnotationProviderBootstrap {

    public static void main(String[] args) throws Exception {
        new EmbeddedZooKeeper(2181false).start();

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
        context.start();

        System.out.println("dubbo service started.");
        new CountDownLatch(1).await();
    }

}

日志如下:

dubbo service started.

启动客户端

package com.github.houbb.dubbo.learn.annotation;

import com.github.houbb.dubbo.learn.annotation.consumer.AnnotationAction;
import com.github.houbb.dubbo.learn.annotation.consumer.ConsumerConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AnnotationConsumerBootstrap {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
        context.start();
        final AnnotationAction annotationAction = (AnnotationAction) context.getBean("annotationAction");

        System.out.println("hello : " + annotationAction.say());
    }


}

日志如下:

hello : hello

小结

本次的 dubbo 入门实战到这里就告一段落了。

dubbo 让远程服务调用起来像本地一样自然,和 spring 整合为我们提供了更大的编程便利性。

后续我们将和大家一起实现属于自己的 RPC 框架,感兴趣的小伙伴可以关注一波,实时获得最新消息。

希望本文对你有所帮助,如果喜欢,欢迎点赞收藏转发一波。

我是老马,期待与你的下次相遇。