Dubbo基础篇

本文详细介绍了ApacheDubbo的核心组件和工作流程,包括服务提供者、消费者、注册中心的角色,以及Dubbo的分层架构,如Service层、Config层、Proxy层、Registry层、Monitor层、Protocol层、Exchange层、Transport层和Serialize层。此外,还探讨了基于XML和注解方式暴露和消费服务的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Dubbo 基础篇

Dubbo简介

Apache Dubbo 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

Dubbo 是一款高性能、轻量级的开源Java RPC框架,提供面向接口代理的高性能RPC调用、智能负载均衡、服务自动注册和发现、运行期流量调度、可视化服务治理和运维等功能。

Dubbo技术架构

Dubbo几个核心节点

节点角色说明
Provider暴露服务的服务提供方
Consumer调用远程服务的服务消费方
Registry服务注册与发现的注册中心
Monitor统计服务的调用次数和调用时间的监控中心
Container服务运行容器

Dubbo框架分层

第一层,Service层,接口层

说明

给服务提供者和消费者来实现的(留给开发人员来实现);

Provider端作用

定义接口,暴露服务

Consumer端作用

引入client依赖,消费服务

第二层,Config层,配置层

说明

主要是对 Dubbo 进行各种配置的,Dubbo 相关配置

Provider端作用

由服务配置类ServiceConfig进行初始化工作及服务暴露;

核心方法:ServiceConfig.export();

Consumer端作用

所有的dubbo引用服务均由ReferenceConfig进行服务的引用;

调用过程:ReferenceConfig.get();–>ReferenceConfig.init();

第三层,Proxy层,服务代理层

说明

透明生成客户端的 stub 和服务单的 skeleton,调用的是接口,实现类没有,所以得生成代理,代理之间再进行网络通讯、负责均衡等

Provider端作用

生成客户端的代理,调用过程:

ReferenceConfig.get();–>ReferenceConfig.init();–>ReferenceConfig.createProxy(map)–>AbstractProxyFactory.getProxy(invoker)–>JavassistProxyFactory.getProxy(invoker,interfaces)

Consumer端作用

生成服务端的代理,调用过程:

ServiceConfig.doExport();–>ServiceConfig.doExportUrls()–>ServiceConfig.doExportUrlsFor1Protocol()–>ServiceConfig.exportLocal(url)–>StubProxyFactoryWrapper.getInvoker(proxy,type,url)–>JavassistProxyFactory.getInvoker(proxy,type,url),

第四层,registry 层,服务注册层

说明

负责服务的注册与发现,Provider和consumer端都会将数据注册到zookeeper上

Provider端作用

注册provider的信息到zookeeper上,调用过程:

ServiceConfig.doExport();–>ServiceConfig.doExportUrls()–>ServiceConfig.doExportUrlsFor1Protocol()–>RegistryProtocol.export(originInvoker)–>FailbackRegistry.register(url);

Consumer端作用

向服务器发送订阅请求,调用过程:

ReferenceConfig.createProxy()–>RegistryProtocol.refer()–>RegistryProtocol.doRefer()–>FailbackRegistry.register(url);

首先注册consumer的信息到zookeeper上,调用过程:

RegistryProtocol.doRefer()–>FailbackRegistry.subscribe();

zookeeper的通知:

ZkclientZookeeperClient.stateChanged(state)通知所有的监听

第五层 cluster 层,路由层

说明

封装多个服务提供者的路由以及负载均衡,将多个实例组合成一 个服务;

首先是初始时会先从zookeeper读取路由信息,调用过程:

ReferenceConfig.createProxy()–>RegistryDirectory.init()–>-AbstractDirectory().init()–>AbstractDirectory.setRouters()

调用时,会进行路由匹配,调用过程:

MockClusterInvoker.invoker()–>AbstractClusterInvoker.invoke(invocation)–>AbstractCluster.list(invocation)

第六层 monitor 层,监控层

说明

主要是通过filter过滤每一个请求,并且进行信息采集,并且汇总一分钟内的数据,定时发送给监控服务:

第七层 protocol 层,远程调用层

说明

封装 rpc 调用

Provider端作用

进行服务的创立,调用过程:

ServiceConfig.doExport();–>ServiceConfig.doExportUrls()–>ServiceConfig.doExportUrlsFor1Protocol()–>RegistryProtocol.export(originInvoker)–>RegistryProtocol.doLocalExport()–>DubboProtocol.export()–>DubboProtocol.openServer()–>DubboProtocol.createServer(url)

Consumer端作用

调用远程服务,调用过程:

ReferenceConfig.createProxy()–>RegistryProtocol.refer()–>RegistryProtocol.doRefer()–>DubboProtocol.refer()–>DubboProtocol.getClients()–>DubboProtocol.getSharedClient(),

第八层 exchange 层,信息交换层

说明

封装请求响应模式,同步转异步;

在这一层主要有两个类HeaderExchangeServer和HeaderExchangeClient,进行消息的发送和接收

第九层 transport 层,网络传输层

说明

抽象 mina 和 netty 为统一接口;

Provider端作用

生成一个NettyServer,调用过程:

ServiceConfig.doExport();–>ServiceConfig.doExportUrls()–>ServiceConfig.doExportUrlsFor1Protocol()–>RegistryProtocol.export(originInvoker)–>RegistryProtocol.doLocalExport()–>DubboProtocol.export()–>DubboProtocol.openServer()–>DubboProtocol.createServer(url)–>NettyTrasporter.bind(),生成一个NettyServer,

线程池是FixedThreadPool,默认线程是200

Consumer端作用

生成一个NettyClient,调用过程:

ReferenceConfig.createProxy()–>RegistryProtocol.refer()–>RegistryProtocol.doRefer()–>DubboProtocol.refer()–>DubboProtocol.getClients()–>DubboProtocol.getSharedClient()–>NettyTransporter.connect(),

线程池是CachedThreadPool,默认线程存活时间是1分钟

在这一层是利用的第三方框架netty

第十层 serialize 层,数据序列化层

说明

数据序列化层。序列化层统一用的是第三方序列化框架hession

基于xml方式暴露和消费服务

Dubbo配置项说明:

配置名称是否必须说明
dubbo:application就是整个项目在分布式架构中的唯一名称,可以在 name 属性中配置,另外还可以配置 owner 字段,表示属于谁
dubbo:monitor监控中心配置, 用于配置连接监控中心相关信息,可以不配置,不是必须的参数。
dubbo:registry配置注册中心的信息,比如,这里我们可以配置 zookeeper 作为我们的注册中心。address 是注册中心的地址,这里我们配置的是 N/A 表示由 dubbo 自动分配地址。或者说是一种直连的方式,不通过注册中心。
dubbo:protocol服务发布的时候 dubbo 依赖什么协议,可以配置 dubbo、webserovice、Thrift、Hessain、http等协议。
dubbo:service这个节点就是我们的重点了,当我们服务发布的时候,我们就是通过这个配置将我们的服务发布出去的。interface 是接口的包路径,ref 是配置的接口的 bean。
bean配置 spring 的接口一样,配置接口的 bean

基于xml服务暴漏方式

在项目resources目录下,创建provider.xml文件:

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

    <!--定义了提供方应用信息,用于计算依赖关系;在 dubbo-admin 或 dubbo-monitor 会显示这个名字,方便辨识-->
    <!--<dubbo:application name="shop-web-provider" owner="programmer" organization="dubbox"/>-->
    <dubbo:application name="dubbo-provider" owner="dubbo-provider" />
    <!--使用 zookeeper 注册中心暴露服务,注意要先开启 zookeeper-->
    <!--<dubbo:registry address="multicast://224.5.6.7:1234"/>-->
    <dubbo:registry address="zookeeper://localhost:2181"/>

    <!-- 用dubbo协议在20880端口暴露服务 -->
    <dubbo:protocol name="dubbo" port="20880"/>

    <!--具体实现该接口的 bean-->
    <bean id="orderService" class="com.deepflow.shop.service.impl.OrderServiceImpl"/>

    <!--使用 dubbo 协议实现定义好的 DemoService 接口-->
    <dubbo:service interface="com.deepflow.shop.service.OrderService" ref="orderService"/>

</beans>

然后再主启动类main方法里加载该文件:

@SpringBootApplication
public class Provider {
    public static void main(String[] args) throws Exception {
        System.setProperty("java.net.preferIPv4Stack", "true");
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext(new String[]{"provider.xml"});
        context.start();
        System.out.println("服务提供方已经启动...");
        System.in.read(); // press any key to exit
    }
}

基于xml方式消费服务

在项目resources目录下,创建consumer.xml文件:

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

    <!-- consumer's application name, used for tracing dependency relationship (not a matching criterion),
    don't set it same as provider -->
    <dubbo:application name="shop-web-consumer" owner="programmer" organization="dubbed"/>

    <!-- use multicast registry center to discover service -->
    <!--<dubbo:registry address="multicast://224.5.6.7:1234"/>-->
    <dubbo:registry address="zookeeper://localhost:2181"/>

    <!-- generate proxy for the remote service, then demoService can be used in the same way as the
    local regular interface -->
    <dubbo:reference id="orderService" check="false" interface="com.deepflow.shop.service.OrderService"/>
</beans>

然后再主启动类main方法里加载该文件:

public class ConsumerWeb {

    public static void main(String[] args) {
        System.setProperty("java.net.preferIPv4Stack", "true");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"consumer.xml"});
        context.start();
        System.out.println("微商城移动端 消费方(Consumer)启动......");
        OrderService orderService = (OrderService) context.getBean("orderService"); // get remote service proxy
        System.out.println("消费方(Consumer)");
        while (true) {
            try {
                Thread.sleep(1000);
                String hello = orderService.sayHello("第2个:我是移动端"); // call remote method
                System.out.println(hello); // get result

            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }
    }
}

基于注解方式暴露和消费服务

dubbo框架核心注解

注解名全限定路径说明
@EnableDubbocom.alibaba.dubbo.config.spring.context.annotation.EnableDubbo放到启动类上。@EnableDubbo整合了三个注解@EnableDubboConfig、@DubboComponentScan、@EnableDubboLifecycle。@EnableDubbo的功能都是由这三个注解完成的
@Servicecom.alibaba.dubbo.config.annotation.Service放到要暴露的服务接口上
@Referencecom.alibaba.dubbo.config.annotation.Reference放到要消费的服务接口上

基于注解的方式暴露服务

在项目resources目录下,创建application.yml文件:

配置项的含义和xml一致

server:
  port: 28891


dubbo:
  application:
    name: user
  registry:
    address: zookeeper://localhost:2181
  protocol:
    port: 20880
    name: dubbo

然后再启动类上添加@EnableDubbo注解

@SpringBootApplication
@EnableDubbo
public class UserApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
        System.out.println(
                String.format(
                        "%s UserApplication service server started!",
                        new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]").format(new Date())
                )
        );
    }
}

然后定义一个service及其实现类

public interface UserService {

    String getUserName(String name);

}

@Service(interfaceClass = UserService.class, timeout = 4000)
public class UserServiceImpl implements UserService {

    @Override
    public String getUserName(String name) {
        System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name +
                ", request from consumer: " + RpcContext.getContext().getRemoteAddress());
        return "Hello " + name + ", response form provider: " + RpcContext.getContext().getLocalAddress();
    }

}

基于注解的方式消费服务

在项目resources目录下,创建application.yml文件:

server:
  port: 28890


dubbo:
  application:
    name: backend
  registry:
    address: zookeeper://localhost:2181
  protocol:
    port: 20880
    name: dubbo

然后再项目启动类上,添加@EnableDubbo注解

@SpringBootApplication
@EnableDubbo
public class Backend {
    public static void main(String[] args) {
        SpringApplication.run(Backend.class, args);
        System.out.println(
                String.format(
                        "%s Backend service server started!",
                        new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]").format(new Date())
                )
        );
    }
}

然后通过@Reference引入服务

@Component
public class UserProxy {

    @Reference(interfaceClass = UserService.class, timeout = 3000)
    private UserService userService;

    public String getUserName(String name) {
        return userService.getUserName(name);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值