CSDN博客

img ddarkelf

用一个面向service的架构来提高你应用程序底层架构的可管理性和可扩展性。

发表于2004/9/15 12:33:00  855人阅读

分类: c#

应用程序框架的概念几乎是与面向对象技术同时出现的,它已被证明是缩短开发时间、提高组件重用性以及能及时适应市场情况变化的一个有效方法。应用程序框架将先进的底层技术(比如.NET Remoting、ADO.NET和安全性)封装起来并提供用于程序开发的共用底层架构组件。应用程序开发小组能够集中精力开发商业功能的原因是该框架提供了所有必要的底层架构组件。同时,由于框架鼓励程序设计的一致性,因此你可以在应用程序的维护方面减少成本。

由于你的开发小组打算使用.NET技术进行开发,因此你会希望建立一个可靠的应用程序框架从而达到以一种节省成本的方式来使用这些性能的目的。在你这么做之前,了解有关程序管理及扩展性方面的问题是很重要的,你可以勾画出一个面向service的应用程序框架来解决这些问题,从而在你的企业中提高开发者的生产力。

应用程序的可管理和可扩展性是任何开发机构中都会涉及到的两个特殊问题。除非你一开始就把它们处理的很好,否则以后将会很难处理。首先,我将澄清可管理性和可扩展性的概念。一些程序组件(比如一个传入数据库连接字符串的组件)是需要一个配置文件来支持的。在你部署好这些组件之后,你可能需要在配置文件中添加新的条目或者对已有的条目进行修改。这种修改配置信息的能力和轻易地将它用在组件中的能力就说明你应用程序的可管理性很强。然而,在很多情况下,应用程序小组并没有权利访问产品服务器,因此需要服务器管理员来修改配置并重新启动服务器。对应用程序开发小组来说,如果有能力修改特定程序的配置信息就更好了。

可扩展性指的是将新的、可管理的组件添加到框架中而不会导致已有软件被改动的能力。通常你会用一系列的要求(比如数据库访问和安全性)来开始你底层架构的构建。当你想要添加新的性能时,(比如一个调度程序(scheduler)或者e-mail),你应该已经具备了一个作为这些组件的基础的标准对象模式。同样,你需要一个标准的方法来指定用于提供这些底层架构性能组件所使用的配置信息。

大多数应用程序框架主要用来为应用程序的开发提供一个模式,同时提高组件的重用性。为应用程序提供底层架构service是所有程序框架的主要功能目标,因此该框架中每个单独部分的可扩展性和可管理性应该是首要目标。

识别Service
在开始讨论架构问题之前,了解什么是service以及它是如何被应用于程序的框架中是非常重要的。不要将它们同Web services中的service混为一谈。一个Service是可独立管理的框架中的一个功能单元,每个service可能是运行的(started)和停止的(stopped),而且它有自己的配置信息。由于service有明确定义的界限,所以它们可以使好的系统更加巩固并使该框架以最小可分离成员进行扩展。

应用程序框架为一致性程序开发提供大量的底部架构组件。应用程序框架提供的组件被分为两类:工具组件(utility components)和service组件。我将主要介绍service组件,因此了解它们之间的区别是很重要的。

应用程序框架术语表

熟悉这些术语会方便你查找并为你的企业建立一个面向service的框架。
更多
工具组件本身是轻量级的(lightweight),意思是创建它们不会消耗大量的内存。通常它们也是无状态的(stateless),如果说是有状态(stateful)的话也只是在很短的一段时间内,比如当客户端在一个中间层处理请求时。工具组件的例子包括集中访问数据库的数据访问组件,以及一个使e-mail地址生效的组件。这些组件无需大量初始化代码来完成创建工作。

一个service组件提供一定的功能,同时在每次启动时有资源耗费。出于几个原因,每次都要新建对象是效率很低的。比如,一个service可能会有一个需要在启动时被加载的配置文件;在这种情况下,多次新建这个组件就会使效率降低。同时,这个组件或许需要在启动时执行耗时初始化(time-consuming initialization)。你一定不希望在每次需要一个service的时候都要忍受这样的延迟,这就是为什么你想要实现只要一开启这个service就可以一次次地调用它们的原因了。因此,一旦一个service开始运行,你就需要有一个好办法来使它暂时不可用或者重新启动。

比如说你有一个提供数据源(data-source)注册功能的组件。这个组件提供连接字符串和一个列出所有数据源的XML配置文件。该组件在启动时将文件加载到内存中并为数据源提供连接字符串。从该文件中加载配置是一个相当消耗内存的操作,因此你一定不希望在每次需要字符串的时候都新建这个组件。

设计平台
面向service架构的目的是提供一个用于可识别的service开发模式以及一个对这些service提供运行支持的服务器。为了解释它是如何运行的,我将概述一个范例场景。这个服务器是一个能够接纳(host)任何远程对象的简单程序。.NET中的Remoting是DCOM的替代品。它用来提供运行于不同应用程序域中的对象访问,该访问可以在同一个机器或不同机器中进行。由于可升级性(scalability)对于任何不平凡(nontrivial)的企业应用程序来说都是很重要的,因此你会希望将商务逻辑层从显示层中分开。所有需要参与分布式事务处理的组件必须在COM+中被当作企业service来使用;所有其他组件被当作.NET远程组件来使用。由于.NET不提供任何用于接纳远程组件的缺省容器程序,因此这个服务器正好填补了这个空缺。

图1.
图1. 合理的架构
这个架构主要由Remoting Server、Service Context、 Service、Service Controller和Service Locator组成。Remoting Server包括两个堆栈;左边的堆栈显示所有它所接纳的远程对象列表(见图1)。这个Service Controller是这个框架中的一个特殊的远程对象,而且服务器会自动对它进行注册。如果任何其他远程对象需要在服务器中被接纳,它们可以被添加到服务器的配置文件中。该Service Controller还控制着位于右手边堆栈中的所有service的活动周期。应用程序的各层(显示层、商务逻辑层和数据访问层)均通过Service Locator对象来实现和service的通话。既然你已经了解了组成这个架构的组件,那么我将继续介绍它的实现问题(见图2)。

提供服务器
在这个例子中,服务器是一个简单的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。

图2.
图2. 合理的设计
Service Controller是一个单实例的(singleton)、由服务器激活的远程对象范例,该对象是在我前面提到过的服务器(Windows service)中运行的(见资源)。它在构造时读取XML配置文件并启动文件中提到的所有service。XML文件中有一个名为的部分,它用来提供有关每个service的配置细节,比如class名和assembly名。所有service都可以通过这个对象来访问,任何需要访问这些service的客户端会首先得到该控制器的实例,然后通过名字向控制器请求一个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程序的开发。你可以通过花些时间和精力开发出一个好的应用程序框架来提高开发人员的生产力。

0 0

相关博文

我的热门文章

img
取 消
img