服务提供商interface简介

什么是服务?

服务是声音处理功能的单元,当应用程序使用 Java Sound API 的实现时,这些功能会自动提供。它们由负责读取,写入,混合,处理和转换音频和 MIDI 数据的对象组成。 Java Sound API 的实现通常提供一组基本的服务,但是 API 中还包含了一些机制,以支持第三方开发人员(或实现本身的供应商)开发新的声音服务。这些新服务可以“插入”现有已安装的实现中,以扩展其功能而无需新版本。在 Java Sound API 架构中,第三方服务以某种方式集成到系统中,使得应用程序与第三方服务的interface与“内置”服务的interface相同。在某些情况下,使用javax.sound.sampledjavax.sound.midi软件包的应用程序开发人员甚至可能不知道他们正在使用第三方服务。

潜在的第三方采样音频服务的示例包括:

  • 声音文件读写器

  • 在不同音频数据格式之间转换的转换器

  • 新的音频混音器和 Importing/输出设备,无论是纯软件实现还是带软件interface的硬件实现

第三方 MIDI 服务可能包括:

  • MIDI 文件读取器和写入器

  • 各种音库文件的阅读器(通常特定于特定的合成器)

  • MIDI 控制的声音合成器,音序器和 I/O 端口,无论是纯软件实现还是带软件interface的硬件实现

服务的工作方式

javax.sound.sampledjavax.sound.midi软件包向希望在其应用程序中包括声音服务的应用程序开发人员提供功能。这些软件包用于声音服务的“Consumer”,提供用于获取有关,控制以及访问音频和 MIDI 服务的信息的interface。另外,Java Sound API 还提供了两个软件包,它们定义了声音服务的“提供者”要使用的抽象类:javax.sound.sampled.spijavax.sound.midi.spi软件包。

新的声音服务的开发人员在 SPI 包中实现适当类的具体子类。这些子类以及支持新服务所需的任何其他类都放置在 Java 归档(JAR)归档文件中,其中包含所包含服务的描述。当将此 JAR 文件安装在用户的CLASSPATH中时,运行时系统将自动使新服务可用,从而扩展 Java 平台的运行时系统的功能。

一旦安装了新服务,就可以像以前安装的任何服务一样对其进行访问。服务的使用者可以通过调用AudioSystemMidiSystem类(分别在javax.sound.sampledjavax.sound.midi包中)的方法来返回有关新服务的信息,或者获取有关新服务的信息,或者获取新服务类本身的实例。返回新的或现有服务类本身的实例。应用程序不需要(也不应)直接引用 SPI 包(及其子类)中的类来利用已安装的服务。

例如,假设一个名为 Acme Software,Inc.的假设服务提供商有兴趣提供一种允许应用程序读取新格式的声音文件(但其音频数据为标准数据格式的文件)的程序包。可以将 SPI 类AudioFileReader子类化为称为AcmeAudioFileReader的类。在新的子类中,Acme 将提供AudioFileReader中定义的所有方法的实现;在这种情况下,只有两种方法(带有参数变体),getAudioFileFormatgetAudioInputStream。然后,当应用程序try读取碰巧是 Acme 的文件格式的声音文件时,它将调用javax.sound.sampledAudioSystem类的方法来访问文件和有关该文件的信息。方法AudioSystem.getAudioInputStreamAudioSystem.getAudioFileFormat提供了用于读取音频流的标准 API;安装了AcmeAudioFileReader类后,此interface将扩展为透明地支持新文件类型。应用程序开发人员不需要直接访问新注册的 SPI 类:AudioSystem对象方法将查询传递给已安装的AcmeAudioFileReader类。

这些“工厂”类有什么意义?为什么不允许应用程序开发人员直接访问新提供的服务?那是一种可能的方法,但是让服务的所有 管理 和实例化都通过 Gatekeeper 系统对象进行传递,使应用程序开发人员不必知道有关已安装服务的身份的任何信息。应用程序开发人员只是使用对他们有价值的服务,甚至可能没有意识到它。同时,该体系结构允许服务提供商有效地 管理 其程序包中的可用资源。

新声音服务的使用通常对应用程序是透明的。例如,设想一种情况,应用程序开发人员希望从文件中读取音频流。假设thePathName标识了音频 Importing 文件,程序将执行以下操作:

File theInFile = new File(thePathName);
    AudioInputStream theInStream = AudioSystem.getAudioInputStream(theInFile);

在幕后,AudioSystem确定哪些已安装的服务可以读取该文件,并要求它提供音频数据作为AudioInputStream对象。开发人员可能不知道,甚至不关心 Importing 的音频文件是否为某种新文件格式(例如 Acme 的格式),并受安装的第三方服务支持。程序与流的第一次接触是通过AudioSystem对象,而对流的所有后续访问及其属性都是通过AudioInputStream的方法。两者都是javax.sound.sampled API 中的标准对象;新文件格式可能需要的特殊处理已完全隐藏。

提供者如何准备新服务

服务提供者以特殊格式的 JAR 文件提供其新服务,这些文件将安装在用户系统上 Java 运行时将在其中找到它们的目录中。 JAR 文件是归档文件,每个文件都包含可能在归档内的分层目录结构中组织的文件集。在接下来的几页中,将讨论有关准备进入这些归档文件的类文件的详细信息,这些文件描述了音频和 MIDI SPI 软件包的详细信息。在这里,我们将仅概述 JAR 文件的创建过程。

一个或多个新服务的 JAR 文件应包含 JAR 文件中支持的每个服务的类文件。按照 Java 平台的约定,每个类文件都具有新定义的类的名称,该类是抽象服务提供者类之一的具体子类。 JAR 文件还必须包含新服务实现所需的任何支持类。为了使运行时系统的服务提供者机制可以定位一个或多个新服务,JAR 文件还必须包含特殊文件(如下所述),这些文件将 SPI 类名称 Map 到所定义的新子类。

为了 continue 上述示例,Acme Software,Inc.正在分发一包新的采样音频服务。让我们假设这个包包含两个新服务:

  • 上面提到的AcmeAudioFileReader类是AudioFileReader的子类

  • AudioFileWriter的子类AcmeAudioFileWriter,它将以 Acme 的新格式写入声音文件

从任意目录开始(我们将其命名为/devel),在该目录中,我们创建子目录并将新的类文件放入其中,其组织方式以提供所需的路径名来引用新类:

com/acme/AcmeAudioFileReader.class
    com/acme/AcmeAudioFileWriter.class

此外,对于每个要继承的新 SPI 类,我们都在一个特别命名的目录META-INF/services中创建一个 Map 文件。该文件的名称是要子类化的 SPI 类的名称,并且该文件包含该 SPI 抽象类的新子类的名称。

我们创建文件

META-INF/services/javax.sound.sampled.spi.AudioFileReader

其中包括

# Providers of sound file-reading services 
    # (a comment line begins with a pound sign)
    com.acme.AcmeAudioFileReader

还有文件

META-INF/services/javax.sound.sampled.spi.AudioFileWriter

其中包括

# Providers of sound file-writing services 
    com.acme.AcmeAudioFileWriter

现在,我们可以使用命令行从任何目录运行jar

jar cvf acme.jar -C /devel .

-C选项使jar切换到/devel目录,而不使用执行命令的目录。 final period 参数指示jar归档该目录的所有内容(即/devel),而不归档目录本身。

此运行将创建包含以下内容的文件acme.jar

com/acme/AcmeAudioFileReader.class
com/acme/AcmeAudioFileWriter.class
META-INF/services/javax.sound.sampled.spi.AudioFileReader
META-INF/services/javax.sound.sampled.spi.AudioFileWriter
META-INF/Manifest.mf

jarUtil 本身生成的文件Manifest.mf,是存档中包含的所有文件的列表。

用户如何安装新服务

对于希望通过其应用程序访问新服务的final用户(或系统 管理 员),安装很简单。他们将提供的 JAR 文件放在其CLASSPATH.的目录中。执行后,Java 运行时将在需要时找到引用的类。

为同一服务安装多个提供程序不是错误。例如,两个不同的服务提供商可能会提供支持以读取相同类型的声音文件。在这种情况下,系统会任意选择提供者之一。关心选择哪个提供程序的用户,应仅安装所需的提供程序。