解耦与模块化:鸿蒙平台上的服务注册与查找机制

server/2024/11/13 22:05:10/

文章目录

    • 背景
    • 一、Java中的服务注册和查找
      • 1.1 原理
      • 1.2 例子
    • 二、鸿蒙中使用TypeScript实现的服务注册和查找
      • 2.1 使用反射和配置文件模拟Java中的SeviceLoader
        • 2.1.1 SDK侧
        • 2.1.2 基座侧
      • 2.2 关键技术点
    • 三、优缺点分析
    • 四、结论

背景

服务注册和查找机制是一种常见的设计模式,它允许我们在运行时动态地加载和使用服务。本文的背景是为了在鸿蒙上实现我们Android版本中的服务注册和查找机制。在Android中我们利用服务注册和查找机制,将基座和第三方SDK的开发分离开来,用户可以按照我们给定的框架,自由开发他们的SDK,再和基座一起打包成APK。基座则基于服务框架,调用第三方SDK的能力。通过这种方式,将基座开发和第三方SDK的开发完全解耦。

一、Java中的服务注册和查找

1.1 原理

在Java中,ServiceLoader类提供了一种服务提供者框架,它允许模块化应用程序在运行时动态加载、查找和使用服务提供者。

ServiceLoader是Java的一种服务提供者加载设施,它遵循了服务提供者框架模式(Service Provider Framework Pattern)。这种模式包含三个组件:服务接口(Service Interface)、提供者注册API(Provider Registration API)、服务访问API(Service Access API)。在Java中,ServiceLoader类就是提供者注册API和服务访问API的实现。

ServiceLoader的工作原理主要基于Java的类路径(Classpath)搜索和META-INF/services目录。当使用ServiceLoader.load(Class<S> service)方法时,ServiceLoader会搜索类路径下所有META-INF/services/目录中名为服务接口全限定名的文件。这个文件是一个简单的文本文件,其中每一行都是一个服务提供者类的全限定名。ServiceLoader会读取这个文件,然后使用类加载器(ClassLoader)加载并实例化这些服务提供者类。

这种机制允许服务提供者在运行时被发现和加载,而无需在编译时进行硬编码,从而提供了很好的模块化和解耦。

1.2 例子

以下是一个简单的例子:

  1. 定义一个服务接口:
java">public interface IService {void doSomething();
}
  1. 实现这个接口:
java">public class MyService implements IService {public void doSomething() {System.out.println("Doing something...");}
}
  1. META-INF/services/目录下创建一个名为com.example.IService的文件(全限定名),文件内容是MyService的全限定名:
com.example.MyService
  1. 使用ServiceLoader加载和使用服务:
java">ServiceLoader<IService> services = ServiceLoader.load(IService.class);
for (IService service : services) {service.doSomething();
}

在这个例子中,当我们运行上述代码时,ServiceLoader会自动找到并加载MyService,然后调用其doSomething方法。

二、鸿蒙中使用TypeScript实现的服务注册和查找

2.1 使用反射和配置文件模拟Java中的SeviceLoader

2.1.1 SDK侧
  1. 定义一个服务接口:
typescript">export interface IService {doSomething(): void;
}
  1. 实现这个接口:
typescript">export class MyService implements IService {doSomething(): void {console.log("Doing something...");}
}
  1. 定义一个服务注册接口:
typescript">export interface IServiceRegister {registerService(): Array<IService>;
}
  1. 实现服务注册接口:
typescript">export class MyServiceRegister implements IServiceRegister {registerService(): Array<IService> {// 返回一个IService的实例数组return [new MyService(), new MyService()];}
}
  1. lib_third_libraryIndex.ets中暴露接口和服务注册实现类:
typescript">export { IService, IServiceRegister } from './src/main/ets/third_library/MyServiceRegister'
export { MyServiceRegister } from './src/main/ets/third_library/MyServiceRegister'
2.1.2 基座侧
  1. 基座调用方:
typescript">interface ClassData {className: string[];
}import('lib_third_library').then((ns: any) => {let fileName = 'meta.json';let res = $rawfile(fileName);// 读取文件内容并转换为字符串let jsonString = bytes2Str(ResUtil.getResManagerByResource(res).getRawFileContentSync(fileName));// 将字符串解析为 JSON 对象,并将其类型断言为 ClassDatalet classData = JSON.parse(jsonString) as ClassData;classData.className.forEach((className) => {console.log(className);let registerServiceFunctionName = 'registerService';// 使用类名实例化类let myServiceRegisterImpl: any = new ns[className]();// 调用 registerService 方法并获取返回的列表,列表中的每个元素都是 IService 类型let serviceList: IService[] = myServiceRegisterImpl[registerServiceFunctionName]();serviceList.forEach((service: IService) => {// 运行服务函数service.doSomething();});});
});
  1. meta.json文件:
{"className":["MyServiceRegister"]
}

在这个例子中,我们首先创建了一个 MyServiceRegister 来注册所有的服务。然后,我们从 MyServiceRegister 中获取 MyService,并调用其 doSomething 方法。

2.2 关键技术点

  1. meta.json是为了模拟javaMETA-INF/services/目录,需要SDK实现方写好实现类的名字:
{"className":["MyServiceRegister"]
}
  1. 通过反射,调用第三方SDK中的服务注册类的注册函数,模拟java中的SeviceLoader.load。
  • registerService 注册服务的函数名字固定不变
  • registerService返回的是service的数组
let registerServiceFunctionName = 'registerService';
// 使用类名实例化类
let myServiceRegisterImpl: any = new ns[className]();
// 调用 registerService 方法并获取返回的列表,列表中的每个元素都是 IService 类型
let serviceList: IService[] = myServiceRegisterImpl[registerServiceFunctionName]();

三、优缺点分析

Java和TypeScript中的服务注册和查找机制都有其各自的优缺点:

标准化易用性延迟加载服务生命周期管理解耦支持类型检查灵活度
Java是,Java的ServiceLoader是Java平台的一部分,所有的Java开发者都可以使用它,无需额外的库或框架。需要在META-INF/services/目录下创建配置文件,并且需要手动输入服务提供者的全限定名,这可能会导致错误。是,ServiceLoader支持延迟加载,只有在真正需要服务提供者时,才会加载和实例化它们。无法管理服务提供者的生命周期,例如,无法控制服务提供者的创建和销毁。是,通过使用ServiceLoader,服务的使用者和提供者可以完全解耦,它们只需要知道服务接口,而无需知道具体的实现。不支持,Java在编译时并不会检查服务的类型,可能会在运行时出现类型错误。较低,Java的ServiceLoader机制相对固定,不易进行定制。
TypeScript否,TypeScript没有标准的服务注册和查找机制,不同的项目可能会有不同的实现。需要实现接口并注册服务,创建一份自定义的配置文件。否,TypeScript的服务注册和查找机制无法实现服务的延迟加载。TypeScript的服务注册和查找机制通常无法管理服务的生命周期,除非在服务注册表中添加额外的逻辑。是,通过使用服务注册表,服务的使用者和提供者可以完全解耦,它们只需要知道服务接口,而无需知道具体的实现。是,由于TypeScript支持静态类型检查,因此可以在编译时检查服务的类型,避免了运行时类型错误。较高,TypeScript的服务注册和查找机制更加灵活,可以根据需要自定义服务注册表。

Java和TypeScript中的服务注册和查找机制各有优缺点,选择哪种机制取决于具体的需求和场景。

四、结论

Java的ServiceLoader提供了一种动态的、松耦合的服务加载机制,适合构建模块化的、可扩展的应用程序。本文在鸿蒙上模拟Java的ServiceLoader的机制,给出了一种可以在大型工程中解耦第三方SDK的鸿蒙实现,希望能给读者一些思路启发。


http://www.ppmy.cn/server/141265.html

相关文章

Nginx、Gateway的区别

Nginx 和 Gateway 都是用于处理网络流量的软件&#xff0c;但它们在设计、用途和功能上有所不同。以下是 Nginx 和 Gateway&#xff08;通常指的是 API Gateway&#xff09;之间的一些主要区别&#xff1a; 用途和目的&#xff1a; Nginx&#xff1a;最初设计为一个高性能的 HT…

Vue 中的定时刷新与自动更新实现

文章目录 Vue 中的定时刷新与自动更新实现定时刷新页面示例&#xff1a;每5秒刷新一次页面优缺点优点&#xff1a;缺点&#xff1a; 性能考虑&#xff1a; 定时更新组件的数据&#xff08;不刷新页面&#xff09;示例&#xff1a;每5秒自动更新数据优缺点优点&#xff1a;缺点&…

系统架构师2023版:习题

架构设计基础 计算机基础 目前处理器市场中存在 CPU 和 DSP 两种类型的处理器&#xff0c;分别用于不同的场景&#xff0c;这两种处理器具有不同的体系结构&#xff0c;DSP采用()。 A.冯诺依曼结构 B.哈佛结构 C.FPGA 结构 D.与 GPU 相同的结构 解析:…

zk在kafka集群中有何作用

ZooKeeper 主要用于管理和协调 Kafka 集群中的各个组件&#xff0c;确保集群的高可用性和一致性。 以下是 ZooKeeper 在 Kafka 集群中的主要作用&#xff1a; 集群成员管理 Broker 注册和发现&#xff1a;每个 Kafka Broker 在启动时会向 ZooKeeper 注册自己的信息&#xff0…

Android 各个版本授予应用信息权限及单次弹窗确认权限

依次添加需要的权限&#xff0c;进行默认打开应用信息的权限开关&#xff1b; 以下是不同版本提供的不同的授权方法进行授权&#xff1a; O版本&#xff1a; /frameworks/base/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java grantRuntimePe…

多模态AI:开启人工智能的新纪元

在人工智能的璀璨星河中&#xff0c;多模态AI技术正逐渐成为一颗耀眼的明星。随着科技的飞速发展&#xff0c;AI技术正以前所未有的速度迈向新的高峰&#xff0c;其中多模态AI的兴起尤为引人注目。本文将深入探讨多模态AI的定义、技术原理、应用场景以及未来发展趋势。 ps.图…

Flutter中有趣的级联语法

目录 前言 一、基本语法 二、级联语法的优点 三、使用场景 1.初始化对象的多个属性 2.Widget 链式构建 3.调用多个方法 4.链式操作异步请求 前言 在 Flutter&#xff08;Dart&#xff09;中&#xff0c;级联操作符&#xff08;cascade notation&#xff09; 使用两个点…

dolphin 配置data 从文件导入hive 实践(一)

datax 支持多种数据源的相互读写&#xff0c;作为开源软件&#xff0c;提供了离线采集功能&#xff0c;方便系统开发&#xff0c;过程中遇到诸多配置&#xff0c;需要开发者自己探索&#xff0c;免费同样有成本 配置模板 {"setting": {},"job": {"s…