「源码解读」Dubbo SPI

本文详细介绍了JavaSPI和DubboSPI的工作原理,通过示例展示了它们的用法,并深入分析了DubboSPI加载扩展类的源码过程,包括依赖注入和AOP特性。

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

1.简介

SPI 全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。SPI 机制在第三方框架中也有所应用,比如 Dubbo 就是通过 SPI 机制加载所有的组件。不过,Dubbo 并未使用 Java 原生的 SPI 机制,而是对其进行了增强,使其能够更好的满足需求。在 Dubbo 中,SPI 是一个非常重要的模块。基于 SPI,我们可以很容易的对 Dubbo 进行拓展。如果大家想要学习 Dubbo 的源码,SPI 机制务必弄懂。接下来,我们先来了解一下 Java SPI 与 Dubbo SPI 的用法,然后再来分析 Dubbo SPI 的源码。

需要特别说明的是,本篇文章以及本系列其他文章所分析的源码版本均为 dubbo-2.6.4。因此大家在阅读文章的过程中,需注意将代码版本切换到 dubbo-2.6.4 tag 上。

2.SPI 示例

2.1 Java SPI 示例

前面简单介绍了 SPI 机制的原理,本节通过一个示例演示 Java SPI 的使用方法。首先,我们定义一个接口,名称为 Robot。

接下来定义两个实现类,分别为 OptimusPrime 和 Bumblebee。

接下来 META-INF/services 文件夹下创建一个文件,名称为 Robot 的全限定名 org.apache.spi.Robot。文件内容为实现类的全限定的类名,如下:

做好所需的准备工作,接下来编写代码进行测试。

最后来看一下测试结果,如下:

从测试结果可以看出,我们的两个实现类被成功的加载,并输出了相应的内容。关于 Java SPI 的演示先到这里,接下来演示 Dubbo SPI。

2.2 Dubbo SPI 示例

Dubbo 并未使用 Java SPI,而是重新实现了一套功能更强的 SPI 机制。Dubbo SPI 的相关逻辑被封装在了 ExtensionLoader 类中,通过 ExtensionLoader,我们可以加载指定的实现类。Dubbo SPI 所需的配置文件需放置在 META-INF/dubbo 路径下,配置内容如下。

与 Java SPI 实现类配置不同,Dubbo SPI 是通过键值对的方式进行配置,这样我们可以按需加载指定的实现类。另外,在测试 Dubbo SPI 时,需要在 Robot 接口上标注 @SPI 注解。下面来演示 Dubbo SPI 的用法:

测试结果如下:

Dubbo SPI 除了支持按需加载接口实现类,还增加了 IOC 和 AOP 等特性,这些特性将会在接下来的源码分析章节中一一进行介绍。

3. Dubbo SPI 源码分析

上面简单演示了 Dubbo SPI 的使用方法。我们首先通过 ExtensionLoader 的 getExtensionLoader 方法获取一个 ExtensionLoader 实例,然后再通过 ExtensionLoader 的 getExtension 方法获取拓展类对象。这其中,getExtensionLoader 方法用于从缓存中获取与拓展类对应的 ExtensionLoader,若缓存未命中,则创建一个新的实例。该方法的逻辑比较简单,本章就不进行分析了。下面我们从 ExtensionLoader 的 getExtension 方法作为入口,对拓展类对象的获取过程进行详细的分析。

上面代码的逻辑比较简单,首先检查缓存,缓存未命中则创建拓展对象。下面我们来看一下创建拓展对象的过程是怎样的。

createExtension 方法的逻辑稍复杂一下,包含了如下的步骤:

1通过 getExtensionClasses 获取所有的拓展类
2通过反射创建拓展对象
3向拓展对象中注入依赖
4将拓展对象包裹在相应的 Wrapper 对象中

以上步骤中,第一个步骤是加载拓展类的关键,第三和第四个步骤是 Dubbo IOC 与 AOP 的具体实现。在接下来的章节中,将会重点分析 getExtensionClasses 方法的逻辑,以及简单介绍 Dubbo IOC 的具体实现。

3.1 获取所有的拓展类

我们在通过名称获取拓展类之前,首先需要根据配置文件解析出拓展项名称到拓展类的映射关系表(Map<名称, 拓展类>),之后再根据拓展项名称从映射关系表中取出相应的拓展类即可。相关过程的代码分析如下:

这里也是先检查缓存,若缓存未命中,则通过 synchronized 加锁。加锁后再次检查缓存,并判空。此时如果 classes 仍为 null,则通过 loadExtensionClasses 加载拓展类。下面分析 loadExtensionClasses 方法的逻辑。

loadExtensionClasses 方法总共做了两件事情,一是对 SPI 注解进行解析,二是调用 loadDirectory 方法加载指定文件夹配置文件。SPI 注解解析过程比较简单,无需多说。下面我们来看一下 loadDirectory 做了哪些事情。

loadDirectory 方法先通过 classLoader 获取所有资源链接,然后再通过 loadResource 方法加载资源。我们继续跟下去,看一下 loadResource 方法的实现。

loadResource 方法用于读取和解析配置文件,并通过反射加载类,最后调用 loadClass 方法进行其他操作。loadClass 方法用于主要用于操作缓存,该方法的逻辑如下:

如上,loadClass 方法操作了不同的缓存,比如 cachedAdaptiveClass、cachedWrapperClasses 和 cachedNames 等等。除此之外,该方法没有其他什么逻辑了。

到此,关于缓存类加载的过程就分析完了。整个过程没什么特别复杂的地方,大家按部就班的分析即可,不懂的地方可以调试一下。接下来,我们来聊聊 Dubbo IOC 方面的内容。

3.2 Dubbo IOC

Dubbo IOC 是通过 setter 方法注入依赖。Dubbo 首先会通过反射获取到实例的所有方法,然后再遍历方法列表,检测方法名是否具有 setter 方法特征。若有,则通过 ObjectFactory 获取依赖对象,最后通过反射调用 setter 方法将依赖设置到目标对象中。整个过程对应的代码如下:

在上面代码中,objectFactory 变量的类型为 AdaptiveExtensionFactory,AdaptiveExtensionFactory 内部维护了一个 ExtensionFactory 列表,用于存储其他类型的 ExtensionFactory。Dubbo 目前提供了两种 ExtensionFactory,分别是 SpiExtensionFactory 和 SpringExtensionFactory。前者用于创建自适应的拓展,后者是用于从 Spring 的 IOC 容器中获取所需的拓展。这两个类的类的代码不是很复杂,这里就不一一分析了。

Dubbo IOC 目前仅支持 setter 方式注入,总的来说,逻辑比较简单易懂。

4.总结

本篇文章简单分别介绍了 Java SPI 与 Dubbo SPI 用法,并对 Dubbo SPI 的加载拓展类的过程进行了分析。另外,在 Dubbo SPI 中还有一块重要的逻辑这里没有进行分析,即 Dubbo SPI 的扩展点自适应机制。该机制的逻辑较为复杂,我们将会在下一篇文章中进行详细的分析。

好了,本篇文章就先到这里了。如果文章中有错误不妥之处,欢迎大家提 issue 进行反馈,或者提 pull request 进行修正。让我们携手共建 Dubbo 社区。

### 基于Unity3D的ACT游戏的设计与实现 #### 摘要与关键词解析 本项目聚焦于使用Unity3D引擎开发一款2D动作类游戏(ACT),旨在为玩家提供沉浸式的游戏体验以及成就感。游戏开发过程中,作者不仅关注游戏的核心玩法,还深入探讨了如何利用Unity内置的各种工具和技术来提升游戏性能、改善用户体验。 **关键词**: - **Unity**:一个跨平台的综合游戏开发引擎,支持2D和3D游戏开发。 - **ScriptableObject**:Unity中的一种特殊脚本类型,用于存储数据和配置信息,方便在多个场景间共享。 - **游戏开发**:涵盖了游戏设计、编程、美术创作等多个方面的工作。 - **2D游戏**:指采用二维画面的游戏,相比3D游戏,具有更简洁的视觉风格和较低的技术门槛。 - **状态机**:一种常用的编程模式,用于管理游戏对象的状态转换,如角色的动作变化等。 - **Cinemachine**:Unity的一个插件,提供了高级的相机控制系统,能够创建出电影级的摄像机动画效果。 #### 第1章:绪论 在本章中,作者首先阐述了游戏开发的背景及意义。随着科技的进步,数字娱乐已经成为人们生活中不可或缺的一部分,而游戏作为其中的一种形式,更是受到了广泛的关注。游戏不仅能够提供娱乐,还能培养玩家的逻辑思维能力和解决问题的能力。因此,开发高质量的游戏产品显得尤为重要。 随后,作者介绍了本项目的起源和发展过程,包括为何选择Unity作为开发工具,以及项目的目标和预期成果。此外,作者还提到了Unity引擎的特点及其在游戏开发中的优势,比如跨平台兼容性、丰富的资源库、强大的社区支持等。 #### 技术选型与实现细节 1. **C#语言**:Unity主要使用的编程语言是C#,它是一种面向对象的语言,具有良好的可读性和扩展性。在本项目中,C#被用来编写游戏逻辑、实现用户交互等功能。 2. **UGUI和Text Mesh Pro**:UGUI是Unity提供的用户界面系统,可以轻松地创建各种界面元素,如按钮、滑块等。Text Mesh Pro则是一款高级文本渲染插件,能够提高文本的渲染质量和性能,使得游戏中的文字更加清晰易读。 3. **有限状态机**:状态机是一种常见的游戏开发模式,用于管理和控制游戏对象的不同状态。在本项目中,状态机被用来处理游戏角色的动作变化,例如攻击、跳跃、行走等。通过这种方式,可以更加高效地组织代码,提高游戏逻辑的清晰度和可维护性。 4. **ScriptableObject**:这是一种特殊的脚本类型,在Unity中主要用于存储数据和配置信息。通过ScriptableObject,开发者可以在编辑器中直接编辑这些数据,而无需重启游戏。这种机制极大地提高了开发效率,并且使得多人协作变得更加容易。 5. **物理系统**:Unity内置的物理引擎能够模拟真实的物理行为,如重力、碰撞等。在本项目中,物理系统被用来处理角色和环境之间的互动,确保游戏中的物理效果逼真可靠。 #### 测试与优化 为了确保游戏的质量,作者进行了多轮的测试,包括功能测试、性能测试以及玩家体验测试。通过不断地调整和优化,最终实现了游戏在低配置设备上的流畅运行。 **总结**: 通过上述分析可以看出,《基于Unity3D的ACT游戏的设计与实现》项目不仅关注游戏本身的玩法设计,还深入探讨了如何利用先进的技术和工具来提高游戏的品质。从技术选型到具体实现,再到后期的测试与优化,每一个环节都体现了作者的专业水平和对游戏开发的热情。对于想要进入游戏开发领域的初学者来说,该项目提供了一个非常好的学习案例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值