开发来自 Java 平台的银行业设备服务
正如我在两部分系列的 第一部分所讨论的,Java 平台金融服务的扩展(J/XFS)是一个国际标准,它可用于为表示一块银行业硬件的众多组件定义一个清楚的接口。这些组件被称为 设备服务,并可以插入 J/XFS 系统。以 J/XFS 内核表示的 J/XFS 环境将设备服务作为独立的、内部可变的部分来对待。
在本文中,您将学到在 J/XFS 下开发银行业的设备服务的关键部分。到讨论结束时,您将会理解:
如果您还没有看过这个系列的第一篇文章,我建议您在开始读本文前先去读一下第一篇文章。
J/XFS 中的设备服务是控制特定的硬件设备的 Java 对象。应用程序不是直接的将消息发送到设备服务对象。取而代之,它们将操作请求消息发送到 J/XFS 内核,内核确保消息依次到达目的地。从图 1 中您可以看到,通常都是由内核来调用设备服务对象上的方法的。
响应发送回应用程序的方式也是一样的。设备服务对象从不把消息直接发送给应用程序。取而代之的是设备服务对象将消息发送给内核,然后由内核将消息发送给适当的接收器。图 2 说明了设备服务是如何向应用程序报告硬件已经改变了状态的。
这个系统可以很好的服务于 J/XFS 设备服务开发者。因为通常设备服务对象都是与 J/XFS 内核通信的,您所要做的全部事情就是遵照一些基本概念并实现恰当的设备服务接口。在下面的几节中,我将概述在 J/XFS 下开发设备服务时所必须理解和遵照的基本概念。
J/XFS 接口由两部分构成。第一部分定义了所有的设备服务共有的基本行为;第 2 部分是一个特定于每种类型的设备服务的 Java 接口的集合。每个设备服务都根据类型来分组的,并且已经为每种类型的设备服务定义好了一个接口集合。在每个集合中都有一个或多个特定于每个设备服务的接 口。设备服务仅实现那些符合它们的规范的接口。例如,一个用于 ATM 的设备服务不会去实现存折打印机的接口,因为这两个服务没有被分组在同一类型中。
J/XFS 设备服务封装了特定设备逻辑和行为,实现方法是对 J/XFS 环境隐藏所有的设备特性,仅使其可见由 J/XFS 标准定义的操作。
应用程序通过向 J/XFS 内核发送相应的消息来表明它们愿意与某个设备服务通信。内核通过注册一个带有设备服务对象的回调对象来对这个请求做出响应。设备服务为每一个回调对象分配 一个唯一的标识数字。然后内核为所有来自该应用程序的请求都添加上这个标识(ID)。该标识数字被称为 控制 ID;每个设备服务都有唯一的控制 ID。
进来的操作请求消息(消息请求您的设备服务器执行一个操作)就是用这个 ID 来区分的。这要求您记住控制 ID 和事件回调对象间的关联。
这些回调对象是设备服务对象所通信的 J/XFS 内核的一部分。它们的唯一目的就是使您能发送事件来报告当前所执行的操作的进展和结果。一旦应用程序不再需要您的设备服务,它通知 J/XFS 内核反注册它的回调对象。
几乎所有的在 J/XFS 设备服务上执行的操作都是以异步的方式执行的。当您的设备服务接收到需要在该设备上执行某一操作的请求时,必须接受该请求,并为其分配一个唯一的标识数字。该 ID 数字(被称为 标识 ID)然后被发送到请求者,所请求的操作在一个单独的线程中被执行。
将 控制 ID 和标识 ID 区分开是很重要的。标识 ID 唯一的命名了应用程序在硬件上执行一个操作的单一请求。 例如,如果一个应用程序需要在打印设备上打印一些信息并把打印出的那张纸吐出来,那么它需要通过内核向设备服务发送两个请求消息,一个用于打印,一个用于 吐纸。每个请求都通过设备服务分配给它的标识 ID 来区分。相反,控制 ID 将唯一的命名产生请求的应用程序。
一个操作一结 束,就会通过发送一个操作完成事件来将结果报告回来,操作完成事件包含操作结果和以前分配的 ID。如果设备服务在忙于执行前面接收到的操作请求时又收到了多个操作请求,每个请求都被放在队列中并且会按照到达的顺序被执行。这条规则的极少的特例在 J/XFS 规范中有清楚的描述(请参阅 参考资料)。
如 果操作请求被取消,请求的应用程序将向 J/XFS 内核发送一个请求来取消这个操作。然后内核向设备服务传送包含取消请求和被取消的操作的标识 ID 的消息。设备服务必须有一个机制,这个机制可以尽量的停止执行操作并把设备设为操作开始前的状态,尽管这并不总是可以实现的。
设备服务在运行时会呈现不同的状态。 大多数状态间的转换在相应的事件中会被报告给单独的或是所有的回调对象。在任何时候 J/XFS 内核都可以向设备服务发送消息请求它当前的状态。
在应用程序建立了它自身、J/XFS 和 设备服务间的通信基础架构后,应用程序就已经准备好与设备服务一起工作了。但在它可以请求任何相关设备的操作之前,它必须通过请求内核打开设备服务的方式 来正式的表达它要这样做的意图。在这一请求中内嵌了唯一的控制 ID。内核向设备服务发送一个请求为了操作而打开的消息。如果连接的硬件是可操作的,就通过发送一个相应的 操作完成事件来回答该请求。在这一点,设备服务对象的状态改变了;现在它“打开”来接收相关设备的操作请求。
应用程序一完成与设备服务的工作,并且在它请求内核反注册它的回调对象之前,它必须请求内核发送一个消息到设备服务,该消息包含为那个控制 ID 正式关闭设备服务的请求。此后,设备服务就不能再接受任何其它的关于该控制 ID 的相关设备的请求消息。
如你到目前为止所看到的,很多应用程序都可以请求内核为它们注册回调对象。操作请求可以以任何可能的顺序到达设备服务。多数情况下,按照接收的顺序来执行操作请求。
但 有时候,一个应用程序必须确保它的请求在被执行时不受其它应用程序的干扰。在这种情况下,应用程序将通过 J/XFS 内核向设备服务发送一个要求排它访问的请求。设备服务必须有一种机制来管理来自内核的排它访问的请求。它必须能够确保在给定的一段时间中仅有一个以控制 ID 来标识的应用程序被授权了排它访问的权限。一旦设备服务成功的将排它访问和控制 ID 关联起来,仅有控制 ID 所标识的操作请求消息可以被执行。所有的其它请求都被放在队列中。
在请求排它访问的任务完成后,内核代表应用程序发送一个请求除去排它访问状态的消息。
|
|
既然已经对在 J/XFS 下开发设备服务的基本要求有了些认识,我们再来熟悉一下 API 规范。这一节 首先来关注一下 API 的实用编程技巧。所有的说明指的是标准版本 1.0 和它所伴有的内核实现。在 FDI for J/XFS 这节中有对软件包层次结构的解释。
如我们前面所讨论的,设备服务对象在它的整个生命周期中呈现出不同的状态。所有可能的状态在所谓的状态类中都有规范进行定义。
JxfsStatus 类将每个设备服务可能呈现的布尔状态也归组进来。状态如下:
您需要注意设备服务对象所控制的硬件的情况(硬件所提供的所有信息)。在任何时间都必须可以从设备服务对象得到状态信息。大多数状态是彼此独立的,但也存在一些依赖。例如,设备服务对象一定要在被授权排它访问之前开放。状态间相互依赖以至于在 JxfsStatus 实例中的信息总是前后一致的,为了这些状态就必须使用某些种类的同步。
一些设备类型规范定义了 JxfsStatus 的子类来包入甚至更多的状态信息。例如,打印机设备的规范定义了 JxfsStatus 的子类: JxfsPtrStatus 类的子类,它可以提供额外的关于打印机调色剂和供纸单元的状态信息。
一些设备规范所使用的有两个更普遍的状态类: JxfsMediaStatus 收集了硬件单元在处理的介质时可能呈现的状态。例如,在打印机中,介质将是“纸”,纸张供应单元可能呈现的一种状态是“卡纸”。另一个类是 JxfsThresholdStatus ,用于监测可测量单元的级别。例如,在打印机中的供纸情况可以是“满”、“高”、“低”或者“空”。请参见 J/XFS 规范以对状态管理类有更多的了解。
事件是实现设备服务发送信息给应用程序从而向 J/XFS 内核传递信息的唯一途径,这样,就很有必要理解事件是怎样工作的。J/XFS 把事件分为三类: 操作完成事件、 中间事件和 状态事件。这些分别表示为 OperationCompleteEvent 类、 IntermediateEvent 类和 StatusEvent 类。
所有的事件为 J/XFS 内核标识事件源(设备服务对象)。这一引用必须作为第一个参数给予所有的事件类型。J/XFS 设备服务的每个异步的操作导致一个 操作完成事件,该事件报告操作的结果。一些特殊设备的操作使用操作完成事件的子类,但不幸的是大多数的设备规范的设计者并没有利用它们。规范为每个操作定义了表示为整数常量的可能结果。另外,为每个操作定义了表示为整数常量的一个 操作标识,以免应用程序记不起它所调用的操作。
中间事件在操作执行时报告操作的进展,其报告的方式与操作完成事件报告结果的方式相同。象上面描述的,当设备服务呈现一个新的状态时, 状态事件就会被发送。不是所有的状态改变都作为状态事件而被报告。设备服务的新状态是用一个整数常量来描述的。例如,如果一个打印机没有纸了,这一事实是通过状态事件来告之应用程序的。
异常机制是 J/XFS 的一个薄弱点,因为仅有一种异常类型: JxfsException 。异常被抛出的原因不是由于它的类型定义部分,而是用一个在接口 JxfsConst 中定义的整数常量来表示的。清单 1 说明了一个所请求的操作不能被支持时被抛出的异常。
/* ... */ |
|
所有的设备服务都要求支持一个主要的接口: IJxfsBaseService 。它声明了所有类型的设备服务共同的所有的方法。在接下来的几节中我们将来研究每个基本的服务方法。
初始化消息
当 J/XFS 内核启动设备服务时,J/XFS 向设备服务发送一个初始化消息,该消息包含了一个
JxfsLocalDeviceInformation
类型的对象。这个对象携带着关于设备服务和它所附着的 J/XFS 客户机的一般信息。它为设备服务提供对在 J/XFS
服务器上的虚拟空间的访问,这一点与那些信息至少是一样重要的。任何持久的数据都可以存储在 J/XFS
服务器上,这就提供了一个存储配置信息的好地方。 初始化消息一到,设备服务就第一次与真正的硬件设备联系。
设备关闭在 J/XFS 客户机关闭过程中,J/XFS 内核向所有的设备服务发送一个关闭消息,如清单 2 所示。这是清理也可能是关闭硬件的好时机。
public void initialize(JxfsLocalDeviceInformation deviceInformation) |
回调对象和控制 ID
J/XFS 内核向设备服务发送一个包含
IJxfsEventNotification 类型的回调对象的消息。设备服务用这个回调对象来向内核发回事件消息。为每个需要与设备服务交互的应用程序发送这种类型的对象。如清单 3 所示,为对象分配一个控制 ID 并返回该控制 ID。
public int registerControl(String deviceType, IJxfsEventNotification |
一旦内核除去了回调对象,就不能再用该回调对象了。
参数 deviceType
参数
deviceType 包含了设备的类型(假使设备服务支持不止一种的类型),但这是高级的设备服务开发,所以这里我们就不深入了。(详见规范)
“打开(open)” 消息
J/XFS 内核发送的消息
open 通知设备服务:很可能操作请求将在给定的控制 ID 后面传入。 参数
controlID 一定要是在一个
IJxfsEventNotification 的实例的
registerControl 方法中分配的一个有效的控制 ID,从而设备服务可以将操作结果报告回来。清单 4 给出了方法的用法:必须在设备服务中实现它以便接收来自内核的
open 消息。
public int open(int controlID) throws JxfsException |
“关闭(close)” 消息
在内核发送
deregisterControl 到设备服务前(因为 open 请求的一个
IJxfsEventNotification 实例已经被成功地处理了),内核必须发送一个
close 消息以表明没有需要那个控制 ID 的操作请求了,如清单 5 所示。
public int close(int controlID) throws JxfsException |
方法的声明(claim)和发布(release)
为了获得或返回对设备服务的排它访问,
claim 和
release 消息被发送到设备服务。 这些方法是少数的在 J/XFS 中不遵守异步操作的规则的方法中的两个方法。直到排它访问被成功的授权或是在参数
timeout 给定的时间里返回了,方法的调用才返回值,如清单 6 所示。
public boolean claim(int timeout, int controlID) throws JxfsException |
当然,排它访问必须在可被返回前授权,并且消息 open 必须在一个 claim 请求前被发送到设备服务而且被成功的处理了。
取消(cancel)请求
内核发送消息
cancel 到设备服务(如果操作是以
identificationID 来标识的话),由回调控制根据
controlID 来启动的操作就要被停止。如果可能的话,设备服务将把硬件置回操作开始之前的状态。取消请求的控制 ID 必须与要取消的操作的控制 ID 相同。没有标识 ID 分配给
cancel 请求,这就意味着
cancel 请求是不能被取消的(这有些不可思议吧)。清单 7 表示了一个取消(cancel)请求。
public void cancel(int identificationID, int controlID) throws JxfsException |
getStatus 操作
getStatus 操作是非常重要的,因为它把设备的当前状态通知 J/XFS 系统中所有相关的对象。如清单 8 所示,方法返回一个
JxfsStatus 的实例,因此这个方法是在 J/XFS 设备服务中异步处理规则的另一个例外。
public JxfsStatus getStatus(int controlID) throws JxfsException |
关于该方法您需要理解两点。如前面所概述的, JxfsStatus 和它的子类包含关于一些不同状态的信息。 第一点要求是相互依赖的状态必须一直前后一致。例如,状态“claimed”依赖状态“open”:设备服务必须在被声明前打开。当收集状态信息供给 JxfsStatus 的一个新的实例时,必须同步的访问那些状态。
第二点与 JxfsStatus 类的设计有关。 JxfsStatus 的实例是值对象,这意味着值对象的唯一作用是携带不提供任何逻辑的信息。这些对象的内容可以被任何其他的对其引用的对象更改。结果,设备服务必须为 getStatus 方法的每一个调用返回一个新的 JxfsStatus 实例,从而确保设备服务拥有一个对对象的引用,而其他对象都不能更改它的内容。
getStatus 操作的简单易懂的实现与清单 9 很相似。假定设备服务有一个内部的监视对象来同步访问方法 getStateMonitor() 返回的所有的状态信息。每个状态可以被相应的方法(例如, isClosed() )查询。实现必须确保当任何对象锁定了由 getStateMonitor() 返回的对象时,状态信息不可改变。所以,您必须检查设备服务是处于“打开”状态,并且如果不是的话就抛出定义的异常。请阅读关于每个方法的 J/XFS 规范来找出您必须检查什么条件。然后,创建一个新的 JxfsStatus 实例,设置所有的状态信息,并返回给访问者。
public JxfsStatus getStatus(int controlID) throws JxfsException |
设备服务信息
设备服务必须提供一些自身的版本信息和所控制硬件的描述。
getDeviceServiceVersion 操作在
JxfsVersion 的一个实例中提供当前安装的设备服务的版本。
清单 10 中所示的其他两个方法返回了与设备服务相连的硬件的类型和硬件的更详尽的描述。如果设备服务支持多种机器(例如相同类型的不同型号),这里设备服务应该给出实际上的配置。
public JxfsVersion getDeviceServiceVersion(int controlID) throws JxfsException |
固件管理支持
J/XFS 提供有限的固件管理支持。在
getDeviceFirmwareVersion 操作中,如清单 11 所示,设备服务返回
JxfsVersion 的一个实例来说明当前安装的硬件的版本。
另外,可以在 J/XFS 服务器上永久的存储固件。 getRepositoryFirmwareVersion 的结果是 J/XFS 服务器的对象库中的可用固件的版本。设备服务可以通过发送消息 getValueForKey 和 setValueForKey 到 JxfsLocalDeviceInformation 实例来读出和写入 J/XFS 服务器,该实例是设备服务在 initialize 方法中接收的。
如果设备服务不支持固件管理,设备服务一定要抛出 JxfsException 异常,错误代码是 JxfsConst.JXFS_E_NOT_SUPPORTED 。
getFirmwareStatus 操作比较这两个版本并且以一个整数常量来报告哪一个比较新和硬件的固件的更新是否可能使用 J/XFS 服务器上的那个版本。如果设备服务不支持固件的更新,设备服务必须返回 JxfsConst.NO_SUPPORT 。
如果选择为设备服务的用户提供固件更新的方便,实际的更新就在 updateFirmware 方法中处理。注意尽管这个操作不返回标识 ID ,它仍然是异步的。因为 J/XFS 服务器可被 J/XFS 环境中的许多对象使用,所以需要清楚的用文档说明为了固件管理在 J/XFS 服务器上使用了哪些密钥,以使数据不会被意外的重写。
清单 11 表示了 J/XFS 中与固件管理相关的四个方法。如果想让应用程序在与设备服务的结合体中使用 J/XFS 固件管理特性,就需要实现这些方法。
public JxfsVersion getDeviceFirmwareVersion(int controlID) throws JxfsException |
节能模式
如果硬件支持操作方式消耗较少的能量,那么通过在
isPowerSaveModeSupported 方法中返回
true 来表明这一点。处于这种方式是设备服务在
JxfsStatus 实例中报告的状态之一,象前面所说的,状态可以通过发送
getStatus 消息到设备服务来获得。
为了把硬件置回完全操作的方式,J/XFS 内核发送 wakeUpFromPowerSave 消息到设备服务,如清单 12 所示。
public boolean isPowerSaveModeSupported(int controlID) throws JxfsException |
处理一个丢失的连接
假
使与一个回调对象的连接由于某种原因而丢失了,J/XFS 内核就发送给设备服务一个包含回调对象的控制 ID
的消息。一收到那个消息,设备服务必须能够除去对给定的控制 ID 的排它访问,把对于那个 ID 的状态设为“关闭”,并且反注册回调对象。清单
13 表示了连接失败消息。
public void connectionFailure(int controlID) |
directIO 操作
directIO() 操作是
IJxfsBaseService 接口中唯一使用硬件的操作功能的操作。但与其他的在特定设备 J/XFS 接口中定义的操作相比它也是一个例外。如果硬件(您正为其开发设备服务)提供没有被包含在 J/XFS 标准中的功能,您可以使用这个操作包含被请求的信息。
从选择一个比 JxfsConst.JXFSDIRECTIO_OFFSET 大的整数值开始来标识特定硬件的功能。设备服务在硬件上执行必要步骤所需的所有信息一定要隐藏在一个 JxfsType 类型的对象中。子类 JxfsType 创建一个新的类来包含设备服务所需的所有信息。
理想情况,您决不需要支持 directIO 。因为使用 directIO 的代码还没有被标准化,所以如果要使用该代码就要损失可移植性。在多数情况下,您应该通过抛出 JxfsException 异常(错误代码 JxfsConst.JXFS_E_NOT_SUPPORTED )来实现 directIO ,如清单 14 所示。
public int directIO(int command, JxfsType serializable, int |
|
独立的 Java 接口用于声明 J/XFS 所支持的不同的硬件类型的功能。每种类型的硬件至少有一个接口。如果您想为给定的硬件类型建一个新的设备服务,您只需在实现上面所概述的 IJxfsBaseService 时同时实现针对于那种类型的硬件的适当的接口即可。
如果您不想支持在接口定义中所描述的某一特殊函数,在多数情况下,您可以通过抛出 JxfsException 异常(错误代码是 JxfsConst.JXFS_E_NOT_SUPPORTED )来表明这一点。
例如,描述打印机功能的接口之一是 IJxfsPrinterService 。它与其它的接口都包含的操作之一是用于复位打印机硬件的 resetPrinter 操作。如果您要写一个提供可复位硬件的打印机设备服务,那么您就要写一个新的类来实现 IJxfsBaseService 和 IJxfsPrinterService ,并把复位硬件的必要代码放在 resetPrinter 方法中。
|
面向 J/XFS 的金融设备接口是 J/XFS 内核的实现。您可以从 J/XFS 论坛主页上免费下载该接口(请参阅 参考资料)。除了实现标准的规范以外,FDI for J/XFS 还包括许多旨在方便在 J/XFS 环境中的软件开发的有用的条款。我们将在接下来的几节中研究这份文档。
在包含 FDI for J/XFS 的 ZIP 压缩文档中,您将看到描述框架的信息的五种来源:
与设备服务开发相关的数据包层次结构如下:
设备操作所需的所有的类都在与这些数据包一起的 J/XFS 标准中定义。下面的是一些附加的数据包:
J/XFS 定义了内置的日志和跟踪支持。当涉及到跟踪代码,尤其是一旦对于产品时,这就会很方便。发送所有的日志和跟踪信息给核心的 JxfsLogger 类型的对象,通过调用类的 getReference 方法来获得对对象的引用。
日志和跟踪入口是用唯一的 origin字符串来标识的。选择日志和跟踪信息所需的所有 origin(确信您可以在生成的日志和跟踪文件中容易的识别出每个 origin)。在可以使用日志和跟踪工具前,必须通过发送 registerModule 消息给 JxfsLogger 对象,让该对象知道 origin 的存在。在停止对一个给定的 origin 进行日志和跟踪前,不要忘记用 deregisterModule 消息反注册。
可以用不同的级别来按优先顺序处理跟踪入口。100 以下的整数值是为 J/XFS 内核保留的,但可以用所有的比 100 大的值。
日志信息随 writeErrorLog 消息被发送到日志记录器(logger)。需要为每个日志入口提供日志模块的 origin 字符串、错误代码以及扩展的错误代码。除了日志字符串外,您还可以提供关于如何解决通到日志入口的问题的附加信息和一个可以检索到附加信息的 URL。
writeLog 消息发送跟踪信息给日志记录器(logger)。因为跟踪应该是被广泛使用的,但是通常在运行时是禁用的,所以跟踪字符串的准备在计算能力方面就很昂贵了。节约计算能力还有找出对 origin 和级别的跟踪是否已被激活的一种方式是发送 isLogActive 消息给 J/XFS 日志记录器(logger)对象。
日志和跟踪消息都包含对入口生成的对象的一个引用。对于设备服务,这是个对设备服务对象的引用。清单 15 说明了 J/XFS 的日志性能是如何被使用的。
// ... |
J/XFS 在标准的规范文档中定义了设备接口。但对于现实的编程需要可以在代码中使用的 Java 类文件。FDI for J/XFS 产生必要的类。
除 接口外,FDI for J/XFS 为 J/XFS 详细说明的每种设备类型提供抽象超类。您最好把抽象类建立适当的子类,从而适应设备服务的实现。这可以确保如果一个设备规范被扩展了,那么相应的方法会被 包含进内核的一个新版本中。方法然后就可以在那些类中以这样的方式来实现:它们仅抛出 JxfsException 异常,出错代码是 JXFS_E_NOT_SUPPORTED 。
把根据旧的规范开发的抽象类上建立子类的设备服务继承了附加的方法而且继续与新版本的内核一起工作。对新性能的支持可以通过重写继承方法简便的加到设备服务上。
清单 16,作为一个示例说明了用于日志打印机的设备服务类。这个类用了抽象超类 com.jxfs.service.ptr.AJxfsJournalPrinterService 。
import com.jxfs.service.*; |
FDI for J/XFS 为设备服务的开发提供为数不多的类。这些类分组在数据包 com.jxfs.forum.support 中。
最重要的支持类是 QueueControl 。该类定义了一个队列,你可以使用该队列来实现设备服务中的操作请求的异步执行。思路是把所有的代码为一个设备操作而分解成一个独立的类。这样的类实现 IJxfsServiceJob 接口,因为这些“作业”对象可被加到队列控制对象。队列控制对象可被用在主动方式或被动方式中。不同之处是主动方式中队列控制使用它自己的控制线程来连续的执行队列中的作业,但在被动方式中您需自己创建一个控制线程并发送 getNextJob 消息给队列控制对象,从而获得并执行队列中的下一个作业。
支持数据包还包括操作请求的实现,操作请求请求的操作有 open 、 close 、 claim 和 release ,它们分别在 OpenJob 类、 CloseJob 类、 ClaimJob 类和 ReleaseJob 类中。请阅读有关这些类的文档以了解如何使用它们。
另一个有用的类: IDFactory 。这种类型的对象产生数字 ID,这些数字 ID 有些用于内核在设备服务注册时区分回调对象(控制 ID),另一些用于标识操作请求(标识 ID)。
|
我希望这个系列能够作为 J/XFS 平台和它的参考实现(即 FDI for J/XFS)的一个好的介绍。通常,一旦您理解了设备服务开发中的基本概念,实现它们就不太困难了。借助这个系列,我的目标是准备和鼓励您开发自己的 J/XFS 设备服务,从而满足来自银行业应用供应商的要求并扩展 J/XFS 和 Java 平台的使用。如果您有关于 J/XFS 的其他问题和关注,我鼓励您把它们发布在与本系列有关的 上。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/374079/viewspace-130102/ ,如需转载,请注明出处,否则将追究法律责任。