Dubbo入门

引子

趁着五一的功夫搞了搞Jenkins布署和Dubbo,面试的时候总会问用过Dubbo没

前一家公司是做SpringCloud的微服务,所以就一直没有了解过这个技术,写个基础入门的教程留待备忘

Dubbo是什么?

Dubbo是阿里巴巴开源的一款高性能Java RPC框架 (远程服务调用的分布式框架)。旨在服务拆分后提供服务治理功能,目前已由Apache基金会维护

它提供了三大核心能力:面向接口的远程方法调用智能容错和负载均衡,以及服务自动注册和发现

它的架构如图:

Dubbo入门_第1张图片

了解SpringCloud的注册中心Eureka或Consul就会发现其功能很接近:

  1. 服务提供者将服务地址与方法参数注册到注册中心
  2. 服务消费者启动时订阅服务提供者的服务地址,服务提供者变更时注册中心将服务地址列表发给消费者
  3. 通过得到的地址调用服务接口返回结果,包含负载均衡,失败则调用其它
  4. 异步服务调用计数,用于监控各服务调用情况,如,调用时间/调用次数

其中第3步与Eureka和Consul的Http调用不同,Dubbo底层调用使用的是Netty建立的NIO通道,其高性能就在于此,即没有Http调用频繁开启关闭通道维护session和很多为了标识客户端状态的信息,通过非阻塞(NIO)长连接直接拿到业务数据

HelloWorld 01

以官方推荐Zookeeper注册中心为例,代码在https://github.com/HellxZ/DubboLearn.git 的master分支上

启动Zookeeper注册中心

下载最新的Zookeeper:Download

解压并进入解压缩后的文件夹下的conf目录,复制zoo_sample.cfg,创建新的配置

cd zookeeper-3.4.14/conf
cp zoo_sample.cfg zoo.cfg
vim zoo.cfg

编辑zoo.cfg,按照Zookeeper官方推荐修改dataDir,选择自己想要的路径

Dubbo入门_第2张图片

保存修改退出

进入可执行文件目录,启动Zookeeper服务端

cd ../bin
./zkServer.sh start #启动服务端

查看启动状态./zkServer.sh status,如下图即正常启动成功

查看Zookeeper日志tail -f zookeeper.out,在bin路径下的zookeeper.out,不要关闭终端方便观察

创建服务提供者

思路:使用两个Spring项目分别代表提供者与消费者,使用Dubbo注册到注册中心,不使用Tomcat以求配置最简化,展示xml全配置方式是如何操作

Dubbo入门_第3张图片

新建个Maven项目ServiceProvider,pom文件如下:



    
        XmlConfiguration
        com.cnblogs.hellxz
        1.0-SNAPSHOT
    
    4.0.0

    ServiceProvider

    
        4.1.4.RELEASE
        1.2.17
        1.7.7
    

    
        
        
            org.springframework
            spring-core
            ${spring.version}
        
        
        
            org.springframework
            spring-context
            ${spring.version}
        
        
            org.springframework
            spring-context-support
            ${spring.version}
        
        
        
            org.springframework
            spring-test
            ${spring.version}
        
        
        
            org.springframework
            spring-web
            ${spring.version}
        
        
            org.springframework
            spring-webmvc
            ${spring.version}
        
        
        
            org.springframework
            spring-aop
            ${spring.version}
        
        
        
            org.aspectj
            aspectjweaver
            1.8.5
        
        
        
            javax.servlet
            javax.servlet-api
            3.0.1
        
        
        
            log4j
            log4j
            ${log4j.version}
        
        
            org.slf4j
            slf4j-api
            ${slf4j.version}
        
        
            org.slf4j
            slf4j-log4j12
            ${slf4j.version}
        
        
        
            com.alibaba
            fastjson
            1.1.41
        
        
        
            com.alibaba
            dubbo
            2.6.5
        
        
            org.apache.zookeeper
            zookeeper
            3.4.6
        
        
            org.apache.curator
            curator-recipes
            2.7.0
        
        
            io.netty
            netty-all
            4.1.32.Final
        

    

    
        serviceProvider
        
            
                src/main/java
                
                    **/*.xml
                
            
        

        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    1.8
                    1.8
                
            
        
    

创建个服务接口与实现类

package com.cnblogs.hellxz.service;

public interface IProviderService {
    String call();
}
package com.cnblogs.hellxz.service.impl;

import com.cnblogs.hellxz.service.IProviderService;

public class ProviderServiceImpl implements IProviderService {
    @Override
    public String call() {
        //为了演示清楚,打印红色的输出,并非错误信息
        System.err.println("服务调用成功");
        return "Call service-provider success!";
    }
}

在resources下新建provider.xml,内容如下:



    

    
    

    
    
    
    

    
    
    
    

log4j.properties

#日志输出级别
log4j.rootLogger=INFO,stdout
#设置stdout的日志输出控制台
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#输出日志到控制台的方式,默认为System.out
log4j.appender.stdout.Target=System.out
#设置使用灵活布局
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#灵活定义输出格式
log4j.appender.stdout.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH:mm:ss}] %l %m %n

项目启动类ProviderMain

package com.cnblogs.hellxz;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;

/**
 * 服务提供者启动类
 */
public class ProviderMain {
    public static void main(String[] args) throws IOException {
        //读取配置文件,初始化Spring容器
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("provider.xml");
        //保持线程存活
        System.in.read();
    }
}

启动项目,我们观察到Zookeeper.out有日志出现了,即注册成功

Dubbo入门_第4张图片

创建服务消费者

结构如图:Dubbo入门_第5张图片

pom文件:



    
        XmlConfiguration
        com.cnblogs.hellxz
        1.0-SNAPSHOT
    
    4.0.0

    Consumer

    
        4.1.4.RELEASE
        1.2.17
        1.7.7
    

    
        
        
            org.springframework
            spring-core
            ${spring.version}
        
        
        
            org.springframework
            spring-context
            ${spring.version}
        
        
            org.springframework
            spring-context-support
            ${spring.version}
        
        
        
            org.springframework
            spring-test
            ${spring.version}
        
        
        
            org.springframework
            spring-web
            ${spring.version}
        
        
            org.springframework
            spring-webmvc
            ${spring.version}
        
        
        
            org.springframework
            spring-aop
            ${spring.version}
        
        
        
            org.aspectj
            aspectjweaver
            1.8.5
        

        
        
            log4j
            log4j
            ${log4j.version}
        
        
            org.slf4j
            slf4j-api
            ${slf4j.version}
        
        
            org.slf4j
            slf4j-log4j12
            ${slf4j.version}
        
        
        
            com.alibaba
            fastjson
            1.1.41
        
        
        
            com.alibaba
            dubbo
            2.6.5
        
        
        
            org.apache.curator
            curator-recipes
            2.7.0
        
        
        
            io.netty
            netty-all
            4.1.32.Final
        
    

    
        consumer
        
            
                src/main/java
                
                    **/*.xml
                
            
        

        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    1.8
                    1.8
                
            
        
    

pom文件中有些依赖没有会导致一些错误,本人已经将依赖添加的理由写上了,可以去除测试是否如实

log4j配置同提供者项目配置,如下是consumer.xml



    

    
    

    
    
        
        
        
        
    

    
    

    
    

调用服务提供者的方法接口的包路径、类名、方法名须与提供者完全相同

创建消费者项目启动类,演示一次调用。启动main方法

package com.cnblogs.hellxz;

import com.cnblogs.hellxz.service.IProviderService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 消费者启动类
 */
public class ConsumerMain {
    public static void main(String[] args) {
        //初始化spring容器
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("consumer.xml");
        //取出容器中的bean
        IProviderService providerService = (IProviderService)ctx.getBean("providerService");
        //打印调用结果 为了演示清楚,打印红色的输出,并非错误信息
        System.err.println(providerService.call());
    }
}

如图,调用成功

Dubbo入门_第6张图片

这里我们发现:如果我们调用一个方法,必须要写一个重复的接口类,如果服务提供者变更就可能出现不一致的问题,所以在下一个demo中把公共的接口抽取成一个模块,顺便把注解使用写在一起了

Hello World 02

与上一个demo区别:包含注解使用、抽取公共接口模块,代码在https://github.com/HellxZ/DubboLearn.git 的xml-base01分支上

这个分支是从上一个代码中checkout出来的,所以有部分全配置设置,这里只需关心带annotation的xml和启动方法就好

公共接口

与上个demo中服务接口相同,不上代码了,可以参考代码

Dubbo入门_第7张图片

服务提供者

pom.xml



    
        XmlConfiguration
        com.cnblogs.hellxz
        1.0-SNAPSHOT
    
    4.0.0

    ServiceProvider

    
        4.1.4.RELEASE
        1.2.17
        1.7.7
    

    
        
        
            com.cnblogs.hellxz
            CommonInterface
            1.0-SNAPSHOT
        
        
        
            org.springframework
            spring-core
            ${spring.version}
        
        
        
            org.springframework
            spring-context
            ${spring.version}
        
        
            org.springframework
            spring-context-support
            ${spring.version}
        
        
        
            org.springframework
            spring-test
            ${spring.version}
        
        
        
            org.springframework
            spring-web
            ${spring.version}
        
        
            org.springframework
            spring-webmvc
            ${spring.version}
        
        
        
            org.springframework
            spring-aop
            ${spring.version}
        
        
        
            org.aspectj
            aspectjweaver
            1.8.5
        
        
        
            javax.servlet
            javax.servlet-api
            3.0.1
        
        
        
            log4j
            log4j
            ${log4j.version}
        
        
            org.slf4j
            slf4j-api
            ${slf4j.version}
        
        
            org.slf4j
            slf4j-log4j12
            ${slf4j.version}
        
        
        
            com.alibaba
            fastjson
            1.1.41
        
        
        
            com.alibaba
            dubbo
            2.6.5
        
        
        
            com.alibaba.spring
            spring-context-support
            1.0.2
        
        
        
            org.apache.zookeeper
            zookeeper
            3.4.6
        
        
            org.apache.curator
            curator-recipes
            2.7.0
        
        
            io.netty
            netty-all
            4.1.32.Final
        
        
            junit
            junit
            4.12
        

    

    
        serviceProvider
        
            
                src/main/java
                
                    **/*.xml
                
            
        

        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    1.8
                    1.8
                
            
        
    

provider-annotation-config.xml


    

    
    
    
    
    
    

    
    
    
    

    

log4j日志配置不变,下面是ProviderMain

package com.cnblogs.hellxz;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.IOException;

/**
 * 服务提供者启动类
 */
public class ProviderMain {

    /**
     * 以全配置方式启动spring容器,提供服务
     */
    @Test
    public void testFullXmlConfig() {
        initSpringContextWithConfigXml("provider-full-xml-config.xml");
    }

    /**
     * 使用配置方式开启注解,启动spring容器,提供服务
     */
    @Test
    public void testAnnotation() {
        initSpringContextWithConfigXml("provider-annotation-config.xml");
    }

    /**
     * 使用配置文件启动spring容器
     *
     * @param springConfigXmlName 配置文件在classPath下的路径名称
     */
    private void initSpringContextWithConfigXml(String springConfigXmlName) {
        //读取配置文件,初始化Spring容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext(springConfigXmlName);
        try {
            //保持线程存活,输入任意字符回车停止
            System.in.read();
        } catch (IOException e) {
            //仅作演示不处理
            e.printStackTrace();
        }
    }
}

ProviderServiceImpl相对于Hello World 01中只是加了个@Service注解,但是注意这个注解是dubbo包下的

package com.cnblogs.hellxz.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.cnblogs.hellxz.service.IProviderService;

@Service
public class ProviderServiceImpl implements IProviderService {

    @Override
    public String call() {
        //为了演示清楚,打印红色的输出,并非错误信息
        System.err.println("服务调用成功");
        return "Call service-provider success!";
    }
}

启动testAnnotation方法即可启动服务

请先关掉上个demo中启动的方法

服务消费者

pom.xml



    
        XmlConfiguration
        com.cnblogs.hellxz
        1.0-SNAPSHOT
    
    4.0.0

    Consumer

    
        4.1.4.RELEASE
        1.2.17
        1.7.7
    

    
        
        
            org.springframework
            spring-core
            ${spring.version}
        
        
        
            org.springframework
            spring-context
            ${spring.version}
        
        
            org.springframework
            spring-context-support
            ${spring.version}
        
        
        
            org.springframework
            spring-test
            ${spring.version}
        
        
        
            org.springframework
            spring-web
            ${spring.version}
        
        
            org.springframework
            spring-webmvc
            ${spring.version}
        
        
        
            org.springframework
            spring-aop
            ${spring.version}
        
        
        
            org.aspectj
            aspectjweaver
            1.8.5
        

        
        
            log4j
            log4j
            ${log4j.version}
        
        
            org.slf4j
            slf4j-api
            ${slf4j.version}
        
        
            org.slf4j
            slf4j-log4j12
            ${slf4j.version}
        
        
        
            com.alibaba
            fastjson
            1.1.41
        
        
        
            com.alibaba
            dubbo
            2.6.5
        
        
        
            org.apache.curator
            curator-recipes
            2.7.0
        
        
        
            io.netty
            netty-all
            4.1.32.Final
        
        
        
            com.cnblogs.hellxz
            CommonInterface
            1.0-SNAPSHOT
            compile
        
        
            junit
            junit
            4.12
        
        
        
            com.alibaba.spring
            spring-context-support
            1.0.2
        
    

    
        consumer
        
            
                src/main/java
                
                    **/*.xml
                
            
        

        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    1.8
                    1.8
                
            
        
    

consumer-annotation-config.xml


    

    
    
    
    
    
    

    
    
        
        
        
        
    

    
    

    

需要有一个bean在spring容器中对应Dubbo引用的接口上

package com.cnblogs.hellxz.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.cnblogs.hellxz.service.IProviderService;
import org.springframework.stereotype.Service;

/**
 * 这个类主要作用就是dubbo引用的接口与providerService这个bean名称作绑定
 * 在全xml配置方式中无需存在,注意这回的@Service注解是spring的
 */
@Service("providerService")
public class ProviderServiceImpl implements IProviderService {

    @Reference
    private IProviderService iProviderService;

    @Override
    public String call() {
        return iProviderService.call();
    }
}

注意事项:

  1. 这回的@Service注解是spring的
  2. 使用Springmvc时无需再包这一层,在@Controller或@RestController的类中直接写@Reference就可以了

贴出启动方法,这次用的是Junit测试的

    @Test
    public void testAnnotationConfig() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer-annotation-config.xml");
        IProviderService providerService = (IProviderService) context.getBean("providerService");
        System.err.println(providerService.call());
    }

测试结果与Demo01相同

报错与解决

1.在注册中心找不到对应的服务

java.lang.IllegalStateException: Failed to check the status of the service *.*.*.xxService . No provider available for the service *.*.*.xxService

这个错误原因是服务端没有将xxService服务注册到注册中心,原因无非三种

  1. 没加com.alibaba.dubbo.config.annotation包下的@Service注解或引错包;
  2. 服务端没启动起来,检查服务端状态
  3. 服务端没注册到注册中心,检查服务端测试中心配置

2. 无法连接到注册中心

  1. 检查Zookeeper是否正常运行
  2. 检查报错项目的注册中心地址配置

3. ClassNotFound异常

3.1
Caused by: java.lang.ClassNotFoundException: org.apache.curator.framework.api.CuratorWatcher

添加依赖

        
            org.apache.curator
            curator-recipes
            2.7.0
        
3.2
ClassNotFoundException: com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor

添加依赖

        
            com.alibaba.spring
            spring-context-support
            1.0.2
        

4. NoClassDefFoundError错误

java.lang.NoClassDefFoundError: io/netty/channel/nio/NioEventLoopGroup

添加依赖

        
            io.netty
            netty-all
            4.1.32.Final
        

5. java.net.BindException: 地址已在使用

    
    
        
        
        
        
    

最后

与SpringBoot的集成的版本后续会开发到新分支下,本文仅介绍Dubbo的架构与基础用法

欢迎关注点赞评论转载,比B站多一连 :),您的支持就是我的动力

本文为实操笔记,转载请注明出处

你可能感兴趣的:(Dubbo入门)