Dubbo服务的注册与发现

94 篇文章 9 订阅
68 篇文章 5 订阅

Dubbo服务的注册与发现

前言

最近参与的项目是一个基于Dubbo的项目,在开发过程中有些同事对于Dubbo服务的注册与发现机制,似乎不太了解。所以我抽空和他简单聊了聊我对Dubbo机制的了解。

正文

Java SPI

SPI即服务提供商接口,它是一种动态加载服务实现者的机制,通过JavaSPI我们可以优雅地根据一个接口来获取该接口的所有实现类。

值得注意的是使用的Java SPI需要有以下的前提:

1.需要在 classpath 下创建一个目录,该目录命名必须是:META-INF/service

2.在该目录下创建一个 properties 文件,该文件需要满足以下几个条件 :

  • 文件名必须是扩展的接口的全路径名称
  • 文件内部描述的是该扩展接口的所有实现类
  • 文件的编码格式是 UTF-8

3.通过 java.util.ServiceLoader 的加载机制来发现

META-INF文件夹相当于一个信息包,目录中的文件和目录获得Java 2平台的认可与解释,用来配置应用程序、扩展程序、类加载器和服务。

我们最常用的mysql驱动 mysql-connector-java就是借助JavaSPI来实现的:

  • Java定义了java.sql.Driver用于API接口用于进行数据库连接,但是没有去实现它。
  • Java通过SPI机制可以适配不同的数据源,只要其驱动类实现java.sql.Driver接口即可。

在这里插入图片描述

但是JavaSPI存在一个弊端,Java SPI 在查找扩展实现类的时候遍历 SPI 的配置文件并且将实现类全部实例化,假设一个实现类初始化过程比较消耗资源且耗时,但是你的代码里面又用不上它,这就产生了资源的浪费。所以说 Java SPI 无法按需加载实现类。

Dubbo SPI

Dubbo发现服务实现者的方式也是借助SPI的设计思想,但与JavaSPI还是有区别的。

Dubbo 对配置文件目录的约定,不同于 Java SPIDubbo 分为了三类目录:

  • META-INF/services/ 目录:该目录下的 SPI 配置文件是为了用来兼容 Java SPI
  • META-INF/dubbo/目录:该目录存放用户自定义的 SPI 配置文件。
  • META-INF/dubbo/internal/ 目录:该目录存放 Dubbo 内部使用的 SPI 配置文件。

Dubbo对外接口和其实现类的对应关系是配置在文件中的,ExtensionLoader会解析文件将数据添加到一个Map中,我们把获取对外接口的实现类的过程称为获取扩展点,它可以分为三种:

自适应扩展点:它是根据class进行匹配,同一个class只能有一个

ExtensionLoader.getExtensionLoader(xxx.class).getAdaptiveExtension();

指定名称的扩展点

ExtensionLoader.getExtensionLoader(xxx.class).getExtension(name);

激活扩展点

ExtensionLoader.getExtensionLoader(xxx.class).getActivateExtension(url, key);

这里以 Dubbo Protocol(RPC协议) 为例

Dubbo 官方支持10种通讯协议,Dubbo通过SPI机制来实现适配不同协议

<dubbo:protocol name="dubbo"  port="20880"  threads="1000" />

Dubbo Protocol会采用自适应的方式进行扩展

Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

Dubbo默认提供一个dubboProtocol扩展点

  • @SPI("dubbo"): 用来定义扩展点
  • @Adaptive:将目标标记实现了一个适配器类,会通过上面讲的三种方式去获取扩展点,如@Adaptive({Constants.PROXY_KEY})为自适应扩展点
@SPI("dubbo")  
public interface Protocol {  
      
    int getDefaultPort();  
  
    @Adaptive  
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;  
  
    @Adaptive  
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;  


    void destroy();  
  
}

Dubbo SPI 的工作流程

Dubbo SPI不会一下子去将实现类全部实例化,只会在使用到的时候才会去使用ExtensionLoader去获取扩展点。并且通过反射和缓存机制,进一步提升了动态加载服务实现者的性能。

ExtensionLoader去加载扩展点的流程可以概括为:

1.通过类名得到一个ExtensionLoader

2.通过定义的名字从ExtensionLoader找到实现类实例

  • 如果存在缓存,直接从缓存中获取实例
  • 如果没有缓存,通过反射建个实例,然后执行 set
    方法依赖注入。如果有找到包装类的话,再包一层。如果标记了@Adaptive,会将实例放在缓存中。

Dubbo 注册和引用服务的方式

我们在实际的使用过程中并不需要关心 Dubbo SPIDubbo本身对Dubbo注册和引用服务进行了更加简洁地封装。

Dubbo引用外部服务

  • @Reference 用在消费端,表明使用的是服务端的什么服务
@Reference(interfaceClass = IUserService.class,retries=0,check=false,timeout = 50000,mockClass=MockUserService.class)
private IUserService iUserService;

可等同于在xml中这样配置

<!-- 消息推送 -->
<dubbo:reference id="user" interface="com.luo.api.service.IUserService" retries="0" timeout="50000"
                 check="false"
                 mock="com.luo.api.service.mockimpl.MockUserService" />

Dubbo注册对外服务

  • @Service 用在服务提供者中,在类或者接口中声明。
@Service(cluster ="failfast")
public class UserServiceImpl implements IUserService{
}

可等同于在xml中这样配置

<!-- dubbo管理平台接口 -->
<bean id="UserService" class="com.luo.producer.rpcservice.UserServiceImpl" />
<dubbo:service interface="com.luo.api.service.IUserService" ref="UserService"  cluster="failfast"/>

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值