应用程序框架的概念几乎是与面向对象技术同时出现的,它已被证明是缩短开发时间、提高组件重用性以及能及时适应市场情况变化的一个有效方法。应用程序框架将先进的底层技术(比如.NET Remoting、ADO.NET和安全性)封装起来并提供用于程序开发的共用底层架构组件。应用程序开发小组能够集中精力开发商业功能的原因是该框架提供了所有必要的底层架构组件。同时,由于框架鼓励程序设计的一致性,因此你可以在应用程序的维护方面减少成本。
由于你的开发小组打算使用.NET技术进行开发,因此你会希望建立一个可靠的应用程序框架从而达到以一种节省成本的方式来使用这些性能的目的。在你这么做之前,了解有关程序管理及扩展性方面的问题是很重要的,你可以勾画出一个面向service的应用程序框架来解决这些问题,从而在你的企业中提高开发者的生产力。
应用程序的可管理和可扩展性是任何开发机构中都会涉及到的两个特殊问题。除非你一开始就把它们处理的很好,否则以后将会很难处理。首先,我将澄清可管理性和可扩展性的概念。一些程序组件(比如一个传入数据库连接字符串的组件)是需要一个配置文件来支持的。在你部署好这些组件之后,你可能需要在配置文件中添加新的条目或者对已有的条目进行修改。这种修改配置信息的能力和轻易地将它用在组件中的能力就说明你应用程序的可管理性很强。然而,在很多情况下,应用程序小组并没有权利访问产品服务器,因此需要服务器管理员来修改配置并重新启动服务器。对应用程序开发小组来说,如果有能力修改特定程序的配置信息就更好了。
可扩展性指的是将新的、可管理的组件添加到框架中而不会导致已有软件被改动的能力。通常你会用一系列的要求(比如数据库访问和安全性)来开始你底层架构的构建。当你想要添加新的性能时,(比如一个调度程序(scheduler)或者e-mail),你应该已经具备了一个作为这些组件的基础的标准对象模式。同样,你需要一个标准的方法来指定用于提供这些底层架构性能组件所使用的配置信息。
大多数应用程序框架主要用来为应用程序的开发提供一个模式,同时提高组件的重用性。为应用程序提供底层架构service是所有程序框架的主要功能目标,因此该框架中每个单独部分的可扩展性和可管理性应该是首要目标。
识别Service
在开始讨论架构问题之前,了解什么是service以及它是如何被应用于程序的框架中是非常重要的。不要将它们同Web services中的service混为一谈。一个Service是可独立管理的框架中的一个功能单元,每个service可能是运行的(started)和停止的(stopped),而且它有自己的配置信息。由于service有明确定义的界限,所以它们可以使好的系统更加巩固并使该框架以最小可分离成员进行扩展。
应用程序框架为一致性程序开发提供大量的底部架构组件。应用程序框架提供的组件被分为两类:工具组件(utility components)和service组件。我将主要介绍service组件,因此了解它们之间的区别是很重要的。
clearcase/" target="_blank" >cccc99>应用程序框架术语表 熟悉这些术语会方便你查找并为你的企业建立一个面向service的框架。 见下 |
应用程序框架术语表 熟悉这些术语会方便你查找并为你的企业建立一个面向service的框架:
|
比如说你有一个提供数据源(data-source)注册功能的组件。这个组件提供连接字符串和一个列出所有数据源的XML配置文件。该组件在启动时将文件加载到内存中并为数据源提供连接字符串。从该文件中加载配置是一个相当消耗内存的操作,因此你一定不希望在每次需要字符串的时候都新建这个组件。
设计平台
面向service架构的目的是提供一个用于可识别的service开发模式以及一个对这些service提供运行支持的服务器。为了解释它是如何运行的,我将概述一个范例场景。这个服务器是一个能够接纳(host)任何远程对象的简单程序。.NET中的Remoting是DCOM的替代品。它用来提供运行于不同应用程序域中的对象访问,该访问可以在同一个机器或不同机器中进行。由于可升级性(scalability)对于任何不平凡(nontrivial)的企业应用程序来说都是很重要的,因此你会希望将商务逻辑层从显示层中分开。所有需要参与分布式事务处理的组件必须在COM+中被当作企业service来使用;所有其他组件被当作.NET远程组件来使用。由于.NET不提供任何用于接纳远程组件的缺省容器程序,因此这个服务器正好填补了这个空缺。
|
提供服务器
在这个例子中,服务器是一个简单的Windows service,它为远程对象提供一个主机环境(hosting environment)并使它们能够在Transmission Control Protocol (TCP)通道中运行。服务器可以接纳任何在配置文件中提到的remoting类。它注册了一个名为Service Controller的内置远程对象。该对象是这个框架的组成部分因为它控制着所有service的活动周期。在启动时,Windows service会设置一个TCP通道,建立Service Controller对象,然后将它注册为一个远程对象。用户端能够通过一个名为Service Locator 的对象来访问这些service,该对象是按照工厂方法(factory-method)的模式来设计的。这使得这些service和客户端通过service实际位置(physical location)的封装信息来形成松散耦合。和其他任何Windows service一样,服务器可以通过控制面板来启动或者停止。每次当你重新启动这个服务器时,所有底层的service也会被重启。在配置文件中的任何改动都会导致服务器的重新启动。
在应用程序框架中,你可以将底层架构的功能单元(比如数据源管理器、安全管理器和e-mail发送器)作为service来实现。尽管它们具有不同的功能,但它们的概念都一样——都是service。
|
Service Controller提供了一些灵活的用法以便你想要使一个特殊的service临时无效。它可以在一个service返回客户端之前检查它的状态。在没有控制器的情况下,services必须被注册为远程对象。在这种情况下,service对象甚至会在已经向客户端发送出去之后被标注为无效,因为这个远程主机(remoting host)无法中断这个对service的请求。如果客户端不检查这个service的状态,它可能会试着使用一些无效的对象。Service Controller在用于记帐操作(bookkeeping operation)中也非常有用,比如跟踪发送到service的请求数和日志管理。
Service Locator提供了用于客户端位置透明(location-transparent)的service访问。你一定不想让客户端对象知道这些service的具体位置以及你用于访问它们的技术是什么。如果客户端了解了这些细节,客户端和service之间就会形成紧密耦合(tightly coupled)。当形成紧密耦合之后,如果一个service从一个服务器移向了另一个服务器,那么你就需要改变所有的客户端。你可以将执行信息集中放在Service Locator中。该类后面的XML配置文件会告诉你这个机器的名字,其中有哪些service在运行,以及在何种通道中运行(TCP或是HTTP)和端口数(port number)。为了使它的效率更高,你可以仿照该类的单实例模式,只读取一次配置信息并确保该类在应用程序域中只有一个实例。一个GetService()方法会将service名作为参数并返回service对象。它会先和Service Locator的远程对象取得联系,然后调用控制器中的一个方法来得到被请求的service。
和其他Service进行联系
service的范例还包括数据源注册(data-source registry)、日志(logger)service和安全性service。数据源注册service用来提供所有数据源的定义。这类信息主要位于诸如web.config等的程序配置信息中。这种方法存在两个问题。首先,包含在配置文件中的用户ID和密码并不安全;第二,任何数据源都可能被几个程序共用。因此最好将这些数据源信息(比如用户名、用户ID、密码、服务器和数据库)集中存储,比如放入XML文件或者Active Directory (AD)中。数据源注册service可以在启动时读取这些信息并把它们的定义传递给请求的应用程序。如果你在这个XML文件中添加了任何新的数据,可以很容易地重新启动它。
日志service提供了一个集中的工具来记录大量来自于应用程序的信息,它能够帮你追踪程序中的问题。这种集中的日志使你可以改变对程序进行日志记录的级别(调试、警告、信息)。你可以利用一个名为log4net的open-source日志包来实现这个功能(见资源)。你可以实现一个适合该架构的service封装器。
安全性service在用于提供验证(authentication)和用户授权方面是很有必要的。它可以通过AD来鉴别用户并确认用户是否有权访问该应用程序。如果用户被确认有权访问,安全性service会读取该用户被授与的角色以及所有与该角色相关的许可信息。
实现一个service和其他service的通话是很有必要的。比如,如果你有一个将消息记录到一个日志文件和数据库中的日志service,你可能想要在所有的service 中使用它。你可以通过在初始化时将ServiceContext 对象传入该service来激活这个通话连接。这个ServiceContext对象中包含一个名为GetService()的方法,它可以使用该service的名字并返回service对象。很重要的一点是所有这些service都运行于一个相同的处理过程和一个相同的应用程序域中。其结果是,service间的通话包含了简单本地程序调用,不牵扯远程。如果一个service在启动时试图使用其他的service,那么你就要保证XML配置文件中在该service之前列出了目标 service。
你可以在很多地方使用程序中的service,主要看这些service都提供了些什么功能,如果该service提供了一些可以用于显示层的东西,就从显示层中调用它。你可以从商务逻辑层中调用诸如信用卡处理的service。应用程序框架所提供的其他工具组件可以使用一些service,比如数据源注册service。了解何时从一个程序中调用一个service是很重要的,它通过.NET Remoting来访问,而不如本地程序调用那么快。你一定不想将架构中所有的组件都变成一个service。如果你的组件在启动时不会消耗内存,那么它就不用变成一个service。
由于所有的service中都包含一些运行行为所依赖的配置信息,你可能需要修改这些信息,你还可能想要终止service而使它暂时无效或者重新启动它。幸运的是,你可以用ASP.NET或者WinForm来建立一个service-manager应用程序,来提供执行这些功能的界面。由于这些配置信息是XML格式的,因此这个service-manager程序可以提供一个XML编辑工具来对这些配置进行修改。配置信息由控制器在启动时加载,所以你可以在内存中修改它,并在需要时将它保存到XML文件中。Service管理器还能够提供一个开始和停止service的工具。如果你将它作为一个ASP.NET程序进行开发,你可以通过浏览器来对所有的service进行配置,而无需在操作系统层访问服务器。
企业应用程序的开发是相当复杂的,因此你一定不想草率地开始每个.NET程序的开发。你可以通过花些时间和精力开发出一个好的应用程序框架来提高开发人员的生产力。
一个面向service的架构可以提高应用程序底层架构的可管理性和可扩展性。其中包括一个作为容器的Remoting Server,它为所有service提供运行支持。所有长时间的初始化操作在该容器中都被当作service来使用。Service Locator用于提供位置透明性来访问所有客户端的service。
这个用于面向service框架的Unified Modeling Language(UML)设计模式显示了所有框架的概念以及它们如何在结构上彼此关连。RemoteServer是一个Windows service,它用于接纳remoting ServiceController对象。ServiceController控制着所有service的活动周期。ServiceContext为每个service提供联系。客户端通过ServiceLocator来访问service。