简介:
了解 IBM 如何定义面向服务的体系结构(Service-Oriented Architecture,SOA)治理——了解其定义以及为何对 SOA 项目的成功十分关键。
面向服务的体系结构 (SOA) 是一项引人注目的技术,用于开发与业务模型保持最佳一致性的软件应用程序。不过,SOA
会提高业务和信息技术(Information Technology,IT)以及 IT
部门和各个团队间所需的合作和协调级别。这个合作和协调是通过 SOA 治理提供的,涵盖了用于指定和管理如何支持服务和 SOA
应用程序的各个任务和流程。
在本文中,我们将了解治理和管理的含义以及其之所以重要的原因。然后,我们将讨论以下 SOA 治理的一些重要方面:
通过本文,您将能很好地理解为何 SOA 工作需要 SOA 治理的支持。您将建立起如何为您的组织构建其 SOA 治理方案的一些基本理念。
在讨论什么是治理之前,让我们了解一下在公司 IT 部门中通常的情况;即没有治理时的情况如何。
让我们假定您开发了一个很不错的小型服务来进行货币值转换。您需要在正在处理的订单处理程序中的几个不同位置使用此服务,
因此将代码编写为具有可重用功能,以便从程序中的任何位置进行调用。由于在另一个程序中需要此服务,因此将代码放到 Java .jar
文件中,以便将其添加到任何需要此服务的程序的类路径中。但该服务存在一个问题,由于需要使用货币汇率(如 Yahoo 的货币转换器网站
发
布的汇率)进行初始化,因此启动需要很长时间。这些步骤在每次需要对货币量进行转换时,都会花太多的时间进行初始化。因此,您在自己的小程序中承载转换
器,这个程序在启动并初始化后将始终运行,可以随时通过远程 API 从任何程序对其进行调用。此 API 可以作为 SOAP-over-HTTP
Web 服务实现,也可以是支持 RMI-over-IIOP 的远程 Enterprise JavaBean (EJB) 接口。
您现在获得的就是一个货币转换器服务。不仅您的多个程序可以使用它,您的部门同时也很喜欢这个小东西,开始从他们自己的程
序对其进行调用。不久后,您可能不知道,公司的其他部门中您从来没有听说过的程序也在使用这个服务了。转换器运行频率非常高,而导致其响应时间延长,因此
您劝说经理购买更为强大的计算机来承载您的服务。经理并不喜欢将预算中的资金花在另一台进行简单工作的计算机上,不过您说服了他。
一个周末,计算机系统崩溃了,而这却是您公司的某个从来没有听说过的人打电话到您家里告诉您的,他让您到办公室进行必要的
工作,以便使转换程序重新开始运行。后来,您的经理说其他部门的人抱怨您的转换器汇率更新并不及时。他希望您对此进行处理,但不希望耽误您的本职工作。您
怎么开始对所有这些负责了呢?
有一天您说“去他的”。您不想再负责转换器的工作,将其关闭了。大量的投诉电子邮件开始在公司内出现,人们尝试找出谁负责
转换器程序以及为什么没有再运行了。其中很多电子邮件抱怨说,由于没有了转换器服务,很多非常有用的程序不再能继续工作了。客户非常生气,您的公司因此而
蒙受着利润损失——如果运气不好,每个人发现要对此负责的是您,您很可能会被辞退。怎么会是这样呢?
现在让我们看一下另一方面。假定您是该公司中的另一名员工,在处理产品目录应用程序。不同国家的用户希望能够看到以其相应
货币表示的产品价格。一位同事告诉您可以调用此服务将每个产品的价格转换为使用用户的货币表示。您试了一下,的确可以正常工作,因此使用该服务实现了您的
应用程序。您的经理非常高兴您能以创记录的时间完成新功能,客户非常喜欢这个功能,网站的销售额大幅度提高。
然后,您的网站在某个周末停止工作了:无法以其他货币显示价格。您的经理打电话到家里,要求您赶快修复程序。您打电话到同
事家,得知是他的朋友的朋友告知他这项服务的。同时,销售副总裁的助手打电话告诉您客户对此很不满意。您告诉他是朋友的朋友编写的这个服务。副总裁的助手
打电话给这个人,让他马上到办公室进行相关工作,以使此服务恢复运行。尽管您的应用程序本身没有问题,而是调用的服务出现了问题,您同时也因为目录应用程
序停止工作而被指责。这怎么会是您的错呢?
欢迎来到 SOA 治理的世界。或,在本例中,缺乏有效治理的世界。服务提供者和服务使用者都开始负责很多最初的职责之外的事务。如何在不造成这样的失控局面的前提下使用服务呢?
我们已经了解了治理无效时可能出现的情况。那么,如果治理更好,IT 是不是会工作得更好?首先,我们需要了解什么是治理,以及它如何影响 IT 和服务。
通常来说,治理意味着建立和执行工作组为了一起工作而一致同意的工作指南。具体来说,治理包括以下方面:
治理确定谁负责制定决策,需要制定什么决策,以及使决策制定保持一致的决策。
治理不同于管理。治理规划需要制定什么决策,而管理是制定和实施决策的过程。治理重在建立决策,而管理重在贯彻执行决策。
IT 治理是指针对 IT 的治理;即:针对 IT
组织及其人员、流程和信息应用治理,以提供指导,使这些资产支持业务需求。SOA 治理是 IT 治理的一种特殊化,其将关键 IT
治理决策置于服务组件、服务和业务流程的生命周期上下文中。SOA 治理对生命周期进行有效管理,生命周期是其关键目标。
IT 治理比SOA 治理更广泛。IT 治理涉及 IT 的所有方面,包括影响 SOA 的问题(如数据模型和安全性)以及 SOA 之外的问题(如数据存储和桌面支持)。SOA 治理重点关注服务生命周期的一些方面,例如:计划、发布、发现、版本治理、管理和安全性。
治理在 SOA 中比在普通 IT 中更为重要。在 SOA
中,服务使用者和服务提供者运行于不同的进程中,由不同的部门开发和管理,为了成功地一起工作,需要进行大量的协调工作。为了 SOA
能成功,多个应用程序需要能共享相同的服务,这意味着它们需要进行协调,以便共享和重用这些服务。这些就是治理问题,比采用独立应用程序时(甚至包括使用
可重用代码和组件时)要复杂得多。
随着各个公司开始使用 SOA 来更好地保持 IT 与业务间的一致,可以使用 SOA 治理来非常理想地改进总体 IT
治理。如果公司要实现 SOA 的各种好处,采用 SOA 治理是非常关键的。对于 SOA 的成功,SOA
业务和技术治理不是可选的,而是必须使用的手段。
在实践中,SOA 治理指导可重用资产的开发,确立如何设计和开发服务,以及这些服务如何随时间增长进行更改。它将在服务提供者和服务使用者之间建立一个协议,告知使用者可以希望得到什么功能,告知提供者应该提供什么功能。
SOA 治理并不设计服务,而是指导将如何设计服务。这可帮助回答很多有关 SOA
的问题:提供了哪些服务?谁可以使用这些服务?它们的可靠性如何?将在多长时间内支持这些服务?是否可以确定这些服务不会更改?如果为了各种目的(如修复
错误或添加新功能)而希望进行更改时该怎么办?如果两个使用者希望相同的服务以不同的方式工作时该怎么办?是否因为您决定公开服务就意味着有责任永远为其
提供支持?如果您决定使用服务,是否能保证明天不会关闭这个服务?
SOA 治理以现有 IT 治理技术和实践为基础。使用 Java 2 Platform, Enterprise Edition (J2EE)
等面向对象的技术时,IT 治理的一个关键方面就是代码重用。代码重用也体现了 IT
治理的难点所在。每个人都认为可重用资产很好,但实际工作时却非常困难:谁为开发可重用资产付款?开发团队是否会实际尽力进行重用?是否每个人都认同可重
用资产的单一行为集,或者每个人都采用自己的自定义版本,实际上完全不能进行重用?SOA
和服务使这些治理问题变得更加重要了,它们的结果也因此变得更为重要。
治理更多的是政策问题,而不是技术或业务问题。技术的重点是匹配接口和调用协议。业务的重点是为客户服务的功能。技术和业务都关注的是需求。虽然治理也涉
及这些方面,但它更多的是要确保所有部分一起工作,独立的工作彼此并不会冲突。治理并不会确定决策的结果是什么,而是考虑必须进行哪些决策以及谁进行这些
决策。
使用者和提供者双方彼此就如何一起工作达成一致。这些认识上的一致大部分都能在服务水平协议(Service-Level
Agreement,SLA)进行捕获,形成服务提供者愿意提供且服务使用者愿意接受的可度量目标。这个协议就像各方之间的契约,而且可以成为事实上的具
有法律效力的合同。SLA 至少要清楚说明提供者必须进行怎样的工作,以及使用者可以期望得到什么服务。
SOA 治理是由精英团队(Center of Excellence,COE)(一组知识丰富的 SOA
技术人员)制订的,他们负责建立策略并监督其执行,从而帮助确保企业的 SOA 成功。COE 将建立各种策略,以用于标识和开发服务、建立
SLA、管理注册中心以及进行其他提供有效治理的工作。COE 成员随后将这些策略付诸实施,指导和帮助团队开发服务和组合应用程序。
治理 COE 制订了策略后,就可以使用相关技术来管理这些策略。技术并不会定义
SLA,但可以用于执行和度量遵从情况。例如,技术可以限制哪些使用者可以调用某个服务以及何时可以调用服务。可以向使用者发出警告,告知服务已经弃用。
可以对服务的可用性和响应时间进行度量。
技术执行治理策略的一个不错的途径是通过企业服务总线(Enterprise Service
Bus,ESB)和服务注册中心的组合。可以采用特定的方式公开服务,以便只有特定的 ESB 才能调用该服务。然后
ESB/注册中心就可以控制使用者的访问,监视和测定使用情况,确定 SLA 遵从情况等。通过这种方式,服务可以将重点放在提供业务功能上,而
ESB/注册中心则主要负责治理方面的工作。
治理可能成为 SOA
中任何错误的替罪羊。和性能一样,治理可能成为极大的顾虑,成为所有问题的托词和每个有问题的解决方案的正当借口。只需要在任何 SOA
讨论中扔出一句火药味十足的话(随后将成为一个修辞“手榴弹”),然后就可以看着原本有用的讨论瞬时间陷入一片静寂。SOA
的一个挑战就是明智地使用治理来使 SOA 更好地工作,而不会让治理方面的顾虑淹没了所有其他事项。
服务开发遵循生命周期原则,IBM 将这一生命周期称为 SOA 生命周期。SOA 治理也同样遵循生命周期原则,即
SOA 治理生命周期。这两个生命周期相互配合、同时运行,并且一起被使用来产生 SOA 组合应用程序及其服务。 SOA
治理生命周期产生一个治理模型来管理 SOA 生命周期。SOA 治理生命周期如图 1 所示。
IBM 的 SOA Governance and Management Method (SGMM) 是一个完整的流程,用于执行 SOA 治理生命周期,以将治理应用于 SOA 生命周期。SGMM 包括四个阶段:
通常帮助执行 SOA 治理生命周期和 SGMM 的产品是 IBM Rational Method Composer
的 SOA 治理插件。IBM Global Business Services (GBS) 能够执行 IBM SOA/Web Services
Center of Excellence 的工作,以帮助组织建立 SOA 精英团队并开发 SOA 治理实践。
SOA 治理不是一组实践操作,而是很多彼此协调工作的系列操作实践。SOA 治理的每个方面都值得在以后的文章中进一步地深入讨论。此处的讨论仅是简单的概述。有关其中一些方面的更多信息,可以参阅本文最后的参考资料
部分。
SOA
治理最基础的方面就是监视服务的创建过程。必须对服务进行标识,必须描述其功能,确定其行为范围并设计其接口。治理 COE
可以不执行这些任务,但要确保有人执行这些任务。COE 对创建服务和需要使用这些服务的团队进行协调,以确保满足相关的需求,并避免重复工作。
通常,什么应该是服务这个问题的答案并不明显。功能应该与一组可重复的业务任务匹配。服务的边界应当封装一项可重用、不受上下文约束的功能。接口应该公开
服务进行的工作,但要隐藏服务是如何实现的,并允许更改实现或采用替代实现。从头设计服务时,可以将其设计成对业务进行建模;包装现有服务时,创建并实现
好的业务接口可能会更难。
定义服务边界的潜在困难的一个有意思的例子就是在何处设置事务边界。服务通常在自己的事务中运行,确保其工作要么完全完
成,要么完全回滚。不过,服务协调程序(也称为协调器或编排器)可能希望在单个事务中调用多个服务(最好是通过指定的交互,如
WS-AtomicTransactions)。此任务要求服务接口公开其事务支持,以便能参与调用方的事务。但这样的公开要求对调用方信任,对提供者具
有很大的风险。例如,提供者可能会锁定执行服务的资源,但如果调用方永远不完成事务(没有提交或回滚),提供者将很难干净地释放资源锁定。正如这种情况所
表明的,服务的范围以及谁具有控制权有时候并不太容易确定。
服务并不会瞬间立即形成,然后永远存在。和任何软件一样,需要进行规划、设计、实现、部署、维护,并最后退役。应用程序生命周期可以为公开性的,从而影响组织的很多方面;但服务的生命周期的影响甚至可能更大,因为多个应用程序可能会依赖于单个服务。
当考虑使用注册中心时,服务的生命周期变得最为明显。何时应将新服务添加到注册中心?注册中心中的所有服务是否都具有必要的可用性,可以随时进行重用?是否应将已退役的服务从注册中心删除?
虽然并没有适合所有组织和所有服务的万用生命周期模式,不过,服务开发生命周期通常都具有五个主要的阶段:
退役可以有效地关闭服务版本,应该事先对退役数据进行计划和公布。在退役前,服务应在一段合适的时间内处于已弃用状态,以便以编程方式警告用户,从而使他们据此进行相应的计划。弃用和退役计划应在 SLA 中指定。
此列表中可能不会出现的一个阶段是“维护”阶段。维护在服务处于活动状态时进行;可能会对服务重新进行测试,以再次验证其具有恰当的功能,不过这可能给依赖于活动服务提供者的现有用户带来问题。
维护在服务中出现的频率远比您可能预期的要低很多;服务的维护通常不会涉及到更改现有服务,而会产生一个新的服务版本。
提供服务后不久,这些服务的用户就开始需要进行一些相应的更改。需要对问题进行修复,需要添加新功能,需要重新设计接口,还需要删除不需要的功能。服务反映业务的情况,因此,随着业务发生变化,服务也需要进行相应的更改。
不过,对于服务的现有用户,需要采用巧妙的方式进行更改,以便不会干扰他们的成功操作。同时,现有用户对稳定性的需求不能对用户希望使用其他功能的需求造成障碍。
服务版本治理可满足这些相互矛盾的目标。版本治理允许满足服务现有功能的用户继续以不变的方式使用服务,并同时允许对服务进行改进,以满足具有新需求的用
户。当前服务接口和行为将保留为一个版本,而同时会将较新的服务作为另一个版本引入。版本兼容性允许使用者调用不同但兼容的服务版本。
版本治理可帮助解决这些问题,但同时也带来了一些新问题,例如需要进行迁移工作。
即使使用版本治理,使用者也不能期望永远提供和支持某个服务(或更准确地说,希望使用的一个服务版本)。服务提供者最终一定会停止提供此服务。版本兼容性
可以帮助延迟这个“最后审判日”,但却不能消除这个问题。版本治理并不会使服务开发生命周期过时,而会允许生命周期扩展到多个连续的代。
当使用者开始使用服务时,将会创建对该服务的依赖关系,必须对此依赖关系进行管理。管理技术可用于有计划地周期性迁移到服务的较新版本。此方法还允许使用者利用添加到服务的新功能。
不过,即使在采用了最佳治理的企业中,服务提供者也不能仅依赖于使用者迁移。由于各种原因(遗留代码、人力、预算、优先
级),一些使用者可能无法及时地进行迁移。这是否意味着提供者必须永远支持相应的服务版本?提供者是否可以在所有使用者已进行了迁移后直接禁用相应的服务
版本?
这两个极端都不甚合意。一个不错的折衷办法是为每个服务版本采用有计划的弃用和退役计划,如服务部署生命周期
中所述。
服务提供者如何提供和宣传其服务?服务使用者如何查找其希望调用的服务?这些都在服务注册中心的职责范围内。服务注册中心将担当可用服务清单的角色,并提供调用服务的地址。
服务注册中心还可以帮助进行服务版本的协调工作。使用者和提供者可以指定它们需要或提供的版本,注册中心将随后确保仅列举
出使用者所需版本的提供者。注册中心可以管理版本兼容性,跟踪版本间的兼容性并列举出使用者所需的版本或兼容版本的提供者。注册中心还可以支持服务状态,
如测试状态和(如前面提到的)已弃用状态,且仅向希望使用服务的使用者提供具有这些状态的服务。
当用户开始使用服务时,将在此服务上创建一个依赖关系。每个使用者清楚地知道其所依赖的服务,但在企业全局范围内,这些依
赖关系可能很难检测,更谈不上管理了。注册中心不仅列出服务和提供者,还可以跟踪使用者和服务间的依赖关系。这个跟踪功能可以帮助回答一个很古老的问题:谁在使用此服务?
可识别依赖关系的注册中心能向使用者通知提供者方面的更改情况,如某个服务变成了已弃用状态。
IBM 的 WebSphere Service Registry and Repository
是一款用于实现服务注册中心的产品。它担当服务定义的存储库以及这些服务的提供者的注册中心角色。它提供了一个中心目录,供开发人员查找可重用服务,并且
在运行时使用,以便服务使用者和企业服务总线 (ESB) 查找服务提供者及调用服务的地址。
在服务调用中,使用者和提供者必须就消息格式达成一致。当独立开发团队分开设计两个部分时,他们很容易陷入难于就公共消息
格式达成一致的困境。再加上数十个使用典型服务的应用程序和使用数十个服务的典型应用程序,您就不难理解直接协商消息格式如何会变成需要全力投入来完成的
任务。
用于避免消息格式混乱的一种常见方法是使用规范数据模型。规范数据模型是一组公共数据格式,独立于任何应用程序,由所有应用程序共享。这样,应用程序就不
必就消息格式达成一致,可以直接同意使用现有规范数据格式。规范数据模型处理消息中的数据格式,因此仍然需要对消息格式的其他部分达成一致(如
Header 字段、消息有效负载包含什么数据以及数据如何安排),但规范数据模型可极大地促进协议的达成。
中央治理委员会可以充当中立方,负责开发规范数据模型。作为应用程序调查和服务设计工作的一部分,还可以设计在服务调用中使用的公共数据格式。
如果服务提供者停止工作,您如何知道呢?是否要等到使用这些服务的应用程序停止,使用这些应用程序的人开始抱怨,才会知道服务已停止了呢?
结合使用多个服务的组合应用程序的可靠性只与其依赖的服务的可靠性相当。由于多个组合应用程序可能共享一个服务,单个服务出现故障可能会影响很多应用程序。必须定义 SLA,以描述使用者可以依赖的可靠性和性能。必须监视服务提供者,以确保其达到了所定义的 SLA。
一个与此相关的方面是问题确定。当组合应用程序停止工作时,确定为什么会这样。这可能是由于应用程序用于与用户进行交互的 UI
停止了运行造成的。但也可能 UI
运行正常,但所使用的其他服务或这些服务使用的某些服务未正常运行。因此,务必注意,不仅要监视每个应用程序的运行状况,还要监视每个服务(提供者整体)
和各个提供者的运行状况。单个业务事务中服务间的事件的相关性非常重要。
此类监视可以帮助在问题出现前检测和防止问题。可以检测不均衡和停机状况,能在这些情况造成重大影响前发出警告,甚至可以尝试自动纠正问题。可以对长时间的使用情况进行度量,以帮助预测使用率会变得更高的服务,以便为其提供更高的容量。
当多个组合服务使用一个服务时,谁负责此服务?是那个人或组织负责它们吗?如果是其中一个,是哪一个?其他人是否认为他们拥有这个服务的所有权?欢迎来到服务所有权的混沌世界。
无论是社区公园、可重用 Java 框架,还是服务提供者,任何共享资源都很难获得和得到相应的照顾。不过,所需的采用池化技术的资源可提供远远超过任何参与者成本的价值:公路系统就是这样。
企业通常围绕其业务操作组织员工报告结构和财务报告结构。SOA 采用相同的方式围绕相同的操作组织企业的
IT,负责特定操作的部门也可以负责这些操作的 IT 的开发和运行。该部门拥有这些服务。SOA
中的服务和组合应用程序经常并不遵循企业严格的层次报告和财务结构,从而在 IT 责任方面造成空白和重叠。
一个相关的问题就是用户角色。由于 SOA 的重点是保持 IT
和业务的一致,而另一个重点是企业重用,组织中很多不同的人员对什么将成为服务、这些服务如何工作以及将如何使用都有发言权。这些角色包括业务分析人员、
企业架构师、软件架构师、软件开发人员和 IT 管理员。所有这些角色在确保服务正确为企业需求和工作服务方面都负有责任。
SOA 应该能反映其业务。这通常意味着要更改 SOA 来适应业务,但在这种情况下,可能有必要更改业务来与 SOA
匹配。如果不可能,则需要提高多个部门间的合作水平,以分担开发公共服务的任务。这样的合作可以通过跨组织的独立委员会来实现,此委员会实际上拥有服务,
并对其进行管理。
服务部署生命周期包括测试阶段,在此阶段,团队将在激活服务前确认服务能正确工作。如果测试了服务提供者,且表明其工作正常,使用者是否需要也对其进行重新测试?是否采用同样的严格要求对服务的所有提供者进行测试?如果服务更改,是否需要对其进行重新测试?
SOA 增加了以独立的方式测试功能的机会,并提高了对其按预期工作的期望值。不过,SOA
也为每个不一定信任服务的新使用者提供了重新测试相同功能的机会,以便确定服务一致地工作。同时,由于组合应用程序共享服务,单个存在错误的服务就可以对
一系列看起来不相关的应用程序造成负面影响,从而扩大这些编程错误的后果。
为了利用 SOA 的重用好处,服务使用者和提供者需要就提供者合理的测试级别达成一致,并需要确保测试按照双方达成的协议执行。然后,服务使用者只需要测试自己的功能以及到服务的连接,并假定服务将按照预期的方式工作。
是否允许任何人调用任何服务?具有一系列用户的服务是否允许其所有用户访问所有数据?服务使用者和提供者之间交换的数据是否需要进行保护?服务是否需要足够的安全,以满足其最偏执的用户或最懒散的用户的需求?
对于任何应用程序,安全是一个困难但必要的命题。功能需要限制为授权的用户,需要对数据进行保护,以防止被窃 听。通过提供更多的功能访问点(即服务),SOA 有可能会大幅度增加组合应用程序中的漏洞。
SOA
可创建非常容易重用的服务,甚至哪些不应该重用这些服务的使用者也能对其进行重用。即使在授权用户中,并非所有用户都应该具有服务能够访问的所有数据的访
问权。例如,用于访问银行帐户的服务应该仅提供特定的用户帐户(尽管其代码也具有访问其他用户的其他帐户的权限)。一些服务使用者比相同服务的其他使用者
具有更大的数据保密性、完整性和不可否认性。
服务调用技术必须能够提供所有这些安全功能。必须对服务的访问进行控制,且将访问权仅限于授权使用者。用户标识必须传播到
服务中,并用于授权数据访问。数据保护的质量必须表示为相应范围内的策略。这就允许使用者说明最低级别的保护和最大功能,并能与可能实际包含其他保护的相
应提供者进行匹配。
本文说明了为什么 SOA 治理对企业的 SOA
成功非常关键。治理涉及到建立相关职责和授权负责方,而管理则涉及到确保治理策略实际执行。技术不仅可以用于设置治理,也可以用于执行管理。服务调用期间
管理的治理可以由 ESB 进行有效的管理,可简化提供者和使用者的职责。
SOA 治理涉及很多方面,其中包括以下内容:
如何处理其中的每个方面本身都足以另外单独成文。
致谢:
作者希望感谢 IBM 同事对本文所做的贡献:Steve Graham、Arnauld
Desprets、Randy Langel、Kerrie Holley、Ali Arsanjani、Emily Plachy、Bob
Vanorsdale、Jon Richter、Mandy Chessell、Mark Cocker、Mark Ernest、Steven
Adler 和 Fill Bowen。
下面列出了一些非常有用的参考资料和资源。
学习
获得产品和技术
讨论
Bobby Woolf
是 IBM Software Services for WebSphere
的 WebSphere J2EE 顾问。Bobby 使用 IBM Rational Application Developer 来帮助客户开发 IBM WebSphere Application Server 的应用程序。他是 Enterprise Integration Patterns
和 The Design Patterns Smalltalk Companion
两书的合著者之一。他还有一个 IBM developerWorks 博客 J2EE in Practice。Bobby 经常在会议上发表演讲。