架构蓝图--软件架构 "4+1" 视图模型

见维基百科

http://en.wikipedia.org/wiki/Software_architecture

2005 年 1 月 01 日

本文基于多个并 发视图的使用情况来说明描述软件密集型系统架构的模型。使用多重视图允许独立地处理各"风险承担人":最终用户、开发人员、系统工程师、项目经理等所关注 的问题,并且能够独立地处理功能性和非功能性需求。本文分别对五种视图进行了描述,并同时给出了捕获每种视图的表示方法。这些视图使用以架构为中心的、场 景驱动以及迭代开发过程来进行设计。

引言

我们已经看到在许多文章和书籍中,作者欲使用单张视图来捕捉所有的系统架构要点。通过仔细地观察这些图例中的方框和箭头, 不难发现作者努力地在单一视图中表达超过其表达限度的蓝图。方框是代表运行的程序吗?或者是代表源代码的程序块吗?或是物理计算机吗?或仅仅是逻辑功能的 分组吗?箭头是表示编译时的依赖关系吗?或者是控制流吗?或是数据流吗?通常它代表了许多事物。是否架构只需要单个的架构样式?有时软件架构的缺陷源于过 早地划分软件或过分的强调软件开发的单个方面:数据工程、运行效率、开发策略和团队组织等。有时架构并不能解决所有"客户"(或者说"风险承担 人",USC 的命名)所关注的问题。许多作者都提及了这个问题:Garlan & Shaw 1、CMU 的 Abowd & Allen、SEI 的 Clements。作为补充,我们建议使用多个并发的视图来组织软件架构的描述,每个视图仅用来描述一个特定的所关注的方面的集合。



回页首

架构模型

软件架构用来处理软件高层次结构的设计和实施。它以精心选择的形式将若干结构元素进行装配,从而满足系统主要功能和性能需 求,并满足其他非功能性需求,如可靠性、可伸缩性、可移植性和可用性。Perry 和 Wolfe 使用一个精确的公式来表达,该公式由 Boehm 做了进一步修改:

软件架构 = {元素,形式,关系/约束}

软件架构涉及到抽象、分解和组合、风格和美学。我们用由多个视图或视角组成的模型来描述它。为了最终处理大型的、富有挑战 性的架构,该模型包含五个主要的视图(请对照图 1):

  • 逻辑视图(Logical View),设计的对象模型(使用面向对象的设计方法时)。
  • 过程视图(Process View),捕捉设计的并发和同步特征。
  • 物理视图(Physical View),描述了软件到硬件的映射,反映了分布式特性。
  • 开发视图(Development View),描述了在开发环境中软件的静态组织结构。

架构的描述,即所做的各种决定,可以围绕着这四个视图来组织,然后由一些用例 (use cases)或场景(scenarios)来说明,从而形成了第五个视图。正如将看到的,实际上软件架构部分从这些场景演进而来,将在下文中讨论。

图 1 - "4+1"视图模型
图 1 - "4+1"视图模型

我们在每个视图上均独立地应用 Perry & Wolf 的公式,即定义一个所使用的元素集合(组件、容器、连接符),捕获工作形式和模式,并且捕获关系及约束,将架构与某些需求连接起来。每种视图使用自身所特 有的表示法-蓝图(blueprint)来描述,并且架构师可以对每种视图选用特定的架构风格(architectural style),从而允许系统中多种风格并存。

我们将轮流的观察这五种视图,展现各个视图的目标:即视图的所关注的问题,相应的架构蓝图的标记方式,描述和管理蓝图的工 具。并以非常简单的形式从 PABX 的设计中,从我们在Alcatel 商业系统(Alcatel Business System)上所做的工作中,以及从航空运输控制系统(Air Traffic Control system)中引出一些例子―旨在描述一下视图的特定及其标记的方式,而不是定义这些系统的架构。

"4+1"视图模型具有相当的"普遍性",因此可以使用其他的标注方法和工具,也可以采用其他的设计方法,特别是对于逻辑 和过程的分解。但文中指出的这些方法都已经成功的在实践中运用过。

逻辑结构

面向对象的分解

逻辑架构主要支持功能性需求――即在为用户提供服务方面系统所应该提供的功能。系统分解为一系列的关键抽象,(大多数)来 自于问题域,表现为对象或对象类的形式。它们采用抽象、封装和继承的原理。分解并不仅仅是为了功能分析,而且用来识别遍布系统各个部分的通用机制和设计元 素。我们使用 Rational/Booch 方法来表示逻辑架构,借助于类图和类模板的手段 4。 类图用来显示一个类的集合和它们的逻辑关系:关联、使用、组合、继承等等。相似的类可以划分成类集合。类模板关注于单个类,它们强调主要的类操作,并且识 别关键的对象特征。如果需要定义对象的内部行为,则使用状态转换图或状态图来完成。公共机制或服务可以在类功能 (class utilities)中定义。对于数据驱动程度高的应用程序,可以使用其他形式的逻辑视图,例如 E-R 图,来代替面向对象的方法(OO approach)。

逻辑视图的表示法

逻辑视图的标记方法来自 Booch 标记法4。当仅考虑具有架构意义的条目时,这种表示法相当简单。特别是在这种设计级别上,大量的修饰作用不大。我们使用 Rational Rose? 来支持逻辑架构的设计。

图 2 - 逻辑蓝图的表示法
图 2 - 逻辑蓝图的表示法

逻辑视图的风格

逻辑视图的风格采用面向对象的风格,其主要的设计准则是试图在整个系统中保持单一的、一致的对象模型,避免就每个场合或过 程产生草率的类和机制的技术说明。

逻辑结构蓝图的样例

图 3 显示了 Télic PABX 架构中主要的类。

图 3 - a. Télic PABX 的逻辑蓝图 b.空中交通系统的蓝图
图 3 - a. Télic PABX 的逻辑蓝图 b.空中交通系统的蓝图

PABX 建立终端间的通信连接。终端可以是电话设备、中继线(例如,连接到中央办公室)、连接线(PABX 专线到 PABX 线)、电话专线、数据线、ISDN 等等。不同的线路由不同的接口卡提供支持。线路 controller 对象的职责是在接口卡上对所有的信号进行解码和注入,在特定于接口卡的信号与一致性的小型事件集合之间进行相互转换:开始、停止、数字化等。 controller 对象同时承载所有的实时约束。该类派生出许多子类以满足不同的接口类型。terminal 对象的责任是维持终端的状态,代表线路协调各项服务。例如,它使用 numbering plan 服务来解释拨号。conversation 代表了会话中的一系列终端 。conversation 使用了Translation Service(目录、逻辑物理映射、路由),以及建立终端之间语音路径的Connection Service 。

对于一个包含了大量的具有架构重要意义的类的、更大的系统来说,图 3 b 描述了空中交通管理系统的顶层类图,包含 8 个类的种类(例如,类的分组)。

进程架构

过程分解

进程架构考虑一些非功能性的需求,如性能和可用性。它解决并发性、分布性、系统完整性、容错性的问题,以及逻辑视图的主要 抽象如何与进程结构相配合在一起-即在哪个控制线程上,对象的操作被实际执行。

进程架构可以在几种层次的抽象上进行描述,每个层次针对不同的问题。在最高的层次上,进程架构可以视为一组独立执行的通信 程序(叫作"processes")的逻辑网络,它们分布在整个一组硬件资源上,这些资源通过 LAN 或者 WAN 连接起来。多个逻辑网络可能同时并存,共享相同的物理资源。例如,独立的逻辑网络可能用于支持离线系统与在线系统的分离,或者支持软件的模拟版本和测试版 本的共存。

进程是构成可执行单元任务的分组。进程代表了可以进行策略控制过程架构的层次(即:开始、恢复、重新配置及关闭)。另外, 进程可以就处理负载的分布式增强或可用性的提高而不断地被重复。

软件被划分为一系列单独的任务。任务是独立的控制线程,可以在处理节点上单独地被调度。

接着,我们可以区别主要任务、次要任务。主要任务是可以唯一处理的架构元素;次要任务是由于实施原因而引入的局部附加任务 (周期性活动、缓冲、暂停等等)。它们可以作为 Ada Task 或轻量线程来实施。 主要任务的通讯途径是良好定义的交互任务通信机制:基于消息的同步或异步通信服务、远程过程调用、事件广播等。次要任务则以会见或共享内存来通信。在同一 过程或处理节点上,主要任务不应对它们的分配做出任何假定。

消息流、过程负载可以基于过程蓝图来进行评估,同样可以使用哑负载来实现"中空"的进程架构,并测量在目标系统上的性能。 正如 Filarey et al. 在他的 Eurocontrol 实验中描述的那样。

进程视图的表示法

我们所使用的进程视图的表示方法是从Booch最初为 Ada 任务推荐的表示方法扩展而来。同样,用来所使用的表示法关注在架构上具有重要意义的元素。(图 4)

图 4 - 过程蓝图表示法
图 4 - 过程蓝图表示法

我们曾使用来自 TRW 的 Universal Network Architechure Services(UNAS0) 产品来构建并实施过程和任务集合(包扩它们的冗余),使它们融入过程的网络中。UNAS 包含 Software Architect Lifecycle Environment(SALE)工具,它支持上述表示方法。SALE 允许以图形的形式来描述进程架构,包括对可能的交互任务通信路径的规格说明,正是从这些路径中自动生成对应的 Ada 或 C++ 源代码。使用该方法来指定和实施进程架构的优点是易于进行修改而不会对应用软件造成太多的影响。

进程视图的风格

许多风格可以适用于进程视图。例如采用 Garlan 和 Shaw 的分类法1,我们可以得到管道和过滤器(Pipes and filters),或客户端/服务器,以及各种多个客户端/单个服务器和多个客户端/多个服务器的变体。对于更加复杂的系统,可以采用类似于 K.Birman 所描述的ISIS系统中进程组方法以及其它的标注方法和工具。

进程蓝图的例子

图 5 - Télic PABX 的过程蓝图(部分)
图 5 - Télic PABX 的过程蓝图(部分)

所有的终端由单个的 Termal process 处理,其中 Termal process 由输入队列中的消息进行驱动。Controller 对象在组成控制过程三个任务之中的一项任务上执行:Low cycle rate task 扫描所有的非活动终端(200 ms),将 High cycle rate task(10 ms)扫描清单中的终端激活,其中 High cycle rate task 检测任何重要的状态变化,将它们传递给 Main controller task,由它来对状态的变更进行解释,并通过向对应的终端发送消息来通信。这里 Controller 过程中的通信通过共享内存来实现。

开发架构

子系统分解

开发架构关注软件开发环境下实际模块的组织。软件打包成小的程序块(程序库或子系统),它们可以由一位或几位开发人员来开 发。子系统可以组织成分层结构,每个层为上一层提供良好定义的接口。

系统的开发架构用模块和子系统图来表达,显示了"输出"和"输入"关系。完整的开发架构只有当所有软件元素被识别后才能加 以描述。但是,可以列出控制开发架构的规则:分块、分组和可见性。

大部分情况下,开发架构考虑的内部需求与以下几项因素有关:开发难度、软件管理、重用性和通用性及由工具集、编程语言所带 来的限制。开发架构视图是各种活动的基础,如:需求分配、团队工作的分配(或团队机构)、成本评估和计划、项目进度的监控、软件重用性、移植性和安全性。 它是建立产品线的基础。

开发蓝图的表示方法

同样,使用 Booch 方法的变形,仅考虑具有架构意义的项。

图 5 - 开发蓝图表示方法
图 5 - 开发蓝图表示方法

来自 Rational 的 Apex 开发环境支持开发架构的定义和实现、和前文描述的分层策略,以及设计规则的实施。Rational Rose 可以在模块和子系统层次上绘制开发蓝图,并支持开发源代码(Ada、C++)进程的正向和反向工程。

开发视图的风格

我们推荐使用分层(layered)的风格,定义 4 到 6 个子系统层。每层均具有良好定义的职责。设计规则是某层子系统依赖同一层或低一层的子系统,从而最大程度地减少了具有复杂模块依赖关系的网络的开发量,得 到层次式的简单策略。

图 6 - Hughes 空中交通系统(HATS)的 5 个层
图 6 - Hughes 空中交通系统(HATS)的 5 个层

开发架构的例子

图 6 代表了加拿大的 Hughes Aircraft 开发的空中交通控制系统(Air Traffic Control system)产品线的 5 个分层开发组织结构。这是和图 3 b 描述的逻辑架构相对应的开发架构。

第一层 和第二层组成了独立于域的覆盖整个产品线的分布式基础设施,并保护其免受不同硬件平台、操作系统或市售产品(如数据库管理系统)的影响。第三层为该基础设 施增加了 ATC 框架,形成一个特定领域的软件架构(domain-specific software architecture)。使用该框架,可以在第四层上构建一个功能选择板。层次 5 则非常依赖于客户和产品,包含了大多数用户接口和外部系统接口。72 个子系统分布于 5 个层次上,每层包含了 10 至 50 个模块,并可以在其他蓝图上表示。

物理架构

软件至硬件的映射

物理架构主要关注系统非功能性的需求,如可用性、可靠性(容错性),性能(吞吐量)和可伸缩性。软件在计算机网络或处理节 点上运行,被识别的各种元素(网络、过程、任务和对象),需要被映射至不同的节点;我们希望使用不同的物理配置:一些用于开发和测试,另外一些则用于不同 地点和不同客户的部署。因此软件至节点的映射需要高度的灵活性及对源代码产生最小的影响。

物理蓝图的表示法

大型系统中的物理蓝图会变得非常混乱,所以它们可以采用多种形式,有或者没有来自进程视图的映射均可。

图 7 - 物理蓝图的表示法
图 7 - 物理蓝图的表示法

TRW 的 UNAS 提供了数据驱动方法将过程架构映射至物理架构,该方法允许大量的映射 的变更而无需修改源代码。

物理蓝图的示例

图 8 - PABX 的物理蓝图
图 8 - PABX 的物理蓝图

图 8 显示了大型 PABX 可能的硬件配置,而图 9 和图 10 显示了两种不同物理架构上的进程映射,分别对应一个小型和一个大型 PABX。C、F 和 K 是三种不同容量的计算机,支持三种不同的运行要求。

图 9 - 带有过程分配的小型 PABX 物理架构
图 9 - 带有过程分配的小型 PABX 物理架构
图10-显示了过程分配的大型PABX物理蓝图
图10-显示了过程分配的大型PABX物理蓝图

场景

综合所有的视图

四种视图的元素通过数量比较少的一组重要场景(更常见的是用例)进行无缝协同工作,我们为场景描述相应的脚本(对象之间和 过程之间的交互序列)。正如 Rubin 和 Goldberg 所描述的那样6。

在某种意义上场景是最重要的需求抽象,它们的设计使用对象场景图和对象交互图来表示4。

该视图是其他视图的冗余(因此"+1"),但它起到了两个作用:

  • 作为一项驱动因素来发现架构设计过程中的架构元素,这一点将在下文中讨论。
  • 作为架构设计结束后的一项验证和说明功能,既以视图的角度来说明又作为架构原型测试的出发点。

场景的表示法

场景表示法与组件逻辑视图非常相似(请对照图 2),但它使用过程视图的连接符来表示对象之间的交互(请对照图 4),注意对象实例使用实线来表达。至于逻辑蓝图,我们使用 Rational Rose 来捕获并管理对象场景。

场景的例子

图 11 显示了小型 PABX 的场景片段。相应的脚本是:

1. Joe的电话控制器检测和校验摘机状态的变换,并发送消息唤醒相应的终端对象。

2. 终端分配一些资源,并要求控制器发出拨号音。

3. 控制器接受拨号并传递给终端。

4. 终端使用拨号方案来分析数字流。

5. 有效的数字序列被键入,终端开始会话。

图 11 - 本地呼叫的初期场景――阶段选择
图 11 - 本地呼叫的初期场景――阶段选择

视图之间的对应性

各种视图并不是完全是正交的或独立的。视图的元素根据某种设计规则和启发式方法与其他视图中的元素相关联。

从逻辑视图到过程视图

我们发现逻辑视架构有几项重要特性:

  • 自主性:对象是主动的、被动的还是被保护的?
    • 主动对象享有调用其他对象或其自身操作的主动权,并且当其他对象对其进行调用时,具有对其自身 操作的完全控制权。
    • 被动对象不能主动调用任何操作,对其他对象调用自身的操作没有控制。
    • 被保护对象不能主动调用任何操作。但对自身的操作有一定的控制功能。
  • 持久化:对象是暂时的还是持久化的?它们是否会导致过程或处理器的终止?
  • 依赖性:对象的存在或持久化是否依赖于另一个对象?
  • 分布性:对象的状态或操作是否能被物理架构中的许多节点所访问?或是被进程架构中的几个进程所访问?

在逻辑视图中,我们认为每个对象均是主动的,具有潜在的"并发性",即与其他对象具有"平行的"行为,我们并不考虑所要达 到的确切并发程度。因此,逻辑结构所考虑的仅是需求的功能性方面。

然而,当我们定义进程架构时,由于巨大的开销,为每个对象实施各自的控制线程(例如,Unix 进程或 Ada 任务),在目前的技术状况下是不现实的。此外,如果对象是并发的,那么必须以某种抽象形式来调用它们的操作。

另一方面,由于以下几种原因需要多个控制线程。

  • 为了快速响应某类外部触发,包括与时间相关的事件。
  • 为了在一个节点中利用多个 CPU,或者在一个分布式系统中利用多个节点。
  • 为了提高 CPU 的利用率,在某些控制线程被挂起,等待其他活动结束的时候(例如,访问外部对象其他活动对象时),为其他的活动分配 CPU。
  • 为了划分活动的优先级(提高潜在的响应能力)。
  • 为了支持系统的可伸缩性(借助于共享负载的其他过程)。
  • 为了在软件的不同领域分离关注点。
  • 为了提高系统的可用性(通过 Backup 过程)。

我们同时使用两种策略来决定并发的程度和定义所需的过程集合。考虑一系列潜在的物理目标架构。以下两种形式我们可以任选其 一:

  • 从内至外:
    由逻辑架构开始:定义代理任务,该任务将控制一个类的多个活动对象的单个线程进行多元化处理;同一代理任务还执行持久化处理那些依赖于一个主动对象的对 象;需要相互进行操作的几个类或仅需要少量处理的类共享单个代理。这种聚合会一直进行,直到我们将过程减少到合理的较少数量,而仍允许分布性和对物理资源 的使用。
  • 由外至内:
    从物理结构开始:识别系统的外部触发;定义处理触发的客户过程和仅提供服务(而非初始化它们)的服务器进程;使用数据完整性和问题的串行化 (serialization)约束来定义正确的服务器设置,并且为客户机与服务器代理分配对象;识别出必须分布哪些对象。

其结果是将类(和它们的对象)映射至一个任务集合和进程架构中的进程。通常,活动类具有代理任务,也存在一些变形:对于给 定的类,使用多个代理以提高吞吐量,或者多个类映射至单个代理,因为它们的操作并不是频繁地被调用,或者是为了保证执行序列。

注意这并不是产生最佳过程架构的线性的、决定性的进程;它需要若干个迭代来得到可接受的折衷。还存在许多其他方法,例如 Birman 等人5 或 Witt 等人7提出的方法。 确切的实施映射的方法不在本文的讨论范围,但我们以一个小的例子来说明一下。

图 12 显示了一个小的类集合如何从假想的空中交通控制系统映射至进程。

flight 类映射至一个 flight 代理集合:有许多航班等待处理,外部触发的频率很高,响应时间很关键,负载必须分布于多个 CPU。并且,航班处理的持久化和分布性方面都取决于 flight server,为了满足可用性,还是使用 flight server 的一台备份服务器。

航班的 profile 和 clearance 总是从属于某个航班,尽管它们是复杂的类,但它们共享 flight 类的进程。航班分布于若干其他进程,特别是对于显示和外部接口。

sectorization 类,为 controller 的权限分配建立了空域划分。由于完整性约束,仅能被一个代理处理,但可以与 flight 类共享服务器过程:更新得并不频繁。

location 和 arispace 及其他的静态航空信息是受到保护的对象,在几个类中共享,很少被更新;它们被映射至各自的服务器,分布于其他过程。

图 12 - 从逻辑视图到过程视图的映射
图 12 - 从逻辑视图到过程视图的映射

从逻辑视图到开发视图

类通常作为一个模块来实现,例如 Ada 包中可视部分的一个类型。密切相关的类(类的种类)的集合组合到子系统中。子系统的定义必须考虑额外的约束,如团队组织、期望的代码规模(通常每个子系统 为 5 K 或 20 K SLOC)、可重用性和通用性的程度以及严格的分层依据(可视性问题),发布策略和配置管理。所以,通常最后得到的不是与逻辑视图逐一对应的视图。

逻辑视图和开发视图非常接近,但具有不同的关注点。我们发现项目规模越大,视图间的差距也越大。例如,如果比较图 3 b 和图 6,则会发现并不存在逐一对应的类的不同种类到层的映射。而如果我们考虑类的种类的"外部接口"-网关种类时,它的实现遍布若干层:通讯协议在第 1 层或以下的层,通用网关机制在第 2 层,而特定的网关在第 5 层子系统。

从进程视图到物理视图

进程和进程组以不同的测试和部署配置映射至可用的物理硬件。Birman 在 ISIS 项目中描述了详细的映射模式5。

场景主要以所使用类的形式与逻辑视图相关联;而与进程视图的关联则是考虑了一个或多个控制线程的、对象间的交互形式。

模型的剪裁

并不是所有的软件架构都需要"4+1"视图。无用的视图可以从架构描述中省略,比如: 只有一个处理器,则可以省略物理视图;而如果仅有一个进程或程序,则可以省略过程视图。 对于非常小型的系统,甚至可能逻辑视图与开发视图非常相似,而不需要分开的描述。场景对于所有的情况均适用。

迭代过程

Witt 等人为设计和架构指出了 4 个阶段:勾画草图、组织、具体化和优化,分成了 12 个 步骤7。他们还指出需要某种程度的反向工程。而我们认为对于大型的项目,该方法太"线性 化"了。在 4 个阶段的末尾,可用于验证架构的内容太少。我们提倡一种更具有迭代性质的方法,即架构先被原形化、测试、估量、分析,然后在一系列的迭代过程中被细化。该 方法除了减少与架构相关的风险之外,对于项目而言还有其他优点:团队合作、培训,加深对架构的理解,深入程序和工具等等(此处提及的是演进的原形,逐渐发 展成为系统,而不是一次性的试验性的原形)。这种迭代方法还能够使需求被细化、成熟化并能够被更好地理解。

场景驱动(scenario-driven)的方法

系统大多数关键的功能以场景(或 use cases)的形式被捕获。关键意味着:最重要的功能,系统存在的理由,或使用频率最高的功能,或体现了必须减轻的一些重要的技术风险。

开始阶段:

  • 基于风险和重要性为某次迭代选择一些场景。场景可能被归纳为对若干用户需求的抽象。
  • 形成"稻草人式的架构"。然后对场景进行"描述",以识别主要的抽象(类、机制、过程、子系统),如 Rubin 与 Goldberg6 所指出的 ―― 分解成为序列对(对象、操作)。
  • 所发现的架构元素被分布到 4 个蓝图中:逻辑蓝图、进程蓝图、开发蓝图和物理蓝图。
  • 然后实施、测试、度量该架构,这项分析可能检测到一些缺点或潜在的增强要求。
  • 捕获经验教训。

循环阶段:

下一个迭代过程开始进行:

  • 重新评估风险,
  • 扩展考虑的场景选择板。
  • 选择能减轻风险或提高结构覆盖的额外的少量场景,

然后:

  • 试着在原先的架构中描述这些场景。
  • 发现额外的架构元素,或有时还需要找出适应这些场景所需的重要架构变更。
  • 更新4个主要视图:逻辑视图、进程视图、开发视图和物理视图。
  • 根据变更修订现有的场景。
  • 升级实现工具(架构原型)来支持新的、扩展了的场景集合。
  • 测试。如果可能的话,在实际的目标环境和负载下进行测试。
  • 然后评审这五个视图来检测简洁性、可重用性和通用性的潜在问题。
  • 更新设计准则和基本原理。
  • 捕获经验教训。

终止循环

为了实际的系统,初始的架构原型需要进行演进 。较好的情况是在经过 2 次或 3 次迭代之后,结构变得稳定:主要的抽象都已被找到。子系统和过程都已经完成,以及所有的接口都已经实现。接下来则是软件设计的范畴,这个阶段可能也会用到 相似的方法和过程。

这些迭代过程的持续时间参差不齐,原因在于:所实施项目的规模,参与项目人员的数量、他们对本领域和方法的熟悉程度,以及 该系统和开发组织的熟悉程度等等。因而较小的项目迭代过程可能持续 2-3 周(例如,10 K SLOC),而大型的项目可能为 6-9 个月(例如,700 K SLOC)。

架构的文档化

架构设计中产生的文档可以归结为两种:

  • 软件架构文档,其结构遵循"4+1"视图(请对照图 13,一个典型的提纲)
  • 软件设计准则,捕获了最重要的设计决策。这些决策必须被遵守,以保持系统架构的完整性。
    图 13 - 软件架构文档提纲
    图 13 - 软件架构文档提纲



回页首

结束语

无论是否经过一次本地定制的和技术上的调整,"4+1"视图都能在许多大型项目中成功运用。事实上,它允许不同的"风险承 担人"找出他们就软件架构所关心的问题。系统工程师首先接触物理视图,然后转向进程视图;最终用户、顾客、数据分析专家从逻辑视图入手;项目经理、软件配 置人员则从开发视图来看待"4+1"视图。 在 Rational 和其他地方,提出并讨论了其他系列视图,例如 Meszaros(BNR)、Hofmeister。Nord 和 Soni(Siemenms)、Emery 和 Hilliard(Mitre),但我们发现其他视图通常可以归入我们所描述的 4 个视图中的一个。例如 Cost&Schedule 视图可以归入开发视图,将一个数据视图归入一个逻辑视图,以及将一个执行视图归入进程视图和物理视图的组合。

表 1 - "4+1"视图模型一览表
表 1 - "4+1"视图模型一览表

Continue reading 架构蓝图--软件架构 "4+1" 视图模型

【转】Comet is Always Better Than Polling

Comet is Always Better Than Polling

by Greg WilkinsNovember 6th, 2007            

               

Comet techniques are advocated when your application needs low latency events to be delivered from the server to the browser. Comet can deliver sub-second latency for messages making possible web applications like chat, games and real-time monitoring of prices and states.

It is often asserted that for applications that don’t need low latency (e.g. email readers), traditional polling is a better alternative. However, some rudimentary analysis shows this assertion to be wrong, and that Comet techniques can be applied to all required latencies and event rates to provide improved data rates and average latencies.

For this analysis, I have considered polling vs. the long-polling technique where a server may hold a poll request for a period of time while waiting for events/messages to be delivered to the browser. In order to ensure that we are comparing apples with apples and oranges with oranges, I have compared configurations that provide the same maximum latency. For example, for a maximum latency of 10s, the polling technique must issue a poll every 10s and the average latency is half that. For the Comet technique long polling, a long poll needs to be issued 10s after the last long poll completes, but the server may hold the long poll for up to 300s while waiting for an event.

The attached spreadsheet contains the calculations, which I have graphed for 1s, 10s and 100s maximum latency for message rates of 1, 10, 100 and 1000 messages per second for 1000 users. The results show that the Comet long polling technique uses less bandwidth than polling in all situations, and uses significantly less bandwidth when the average period between messages is longer than the maximum latency:

Not only does Comet long-polling provide superior data rates, it also provides superior average latency. The Comet technique allows the average latency to be lower than the maximum latency because once the pause between polls is complete, the long poll is ready to respond immediately to events.

This analysis shows that for the worst case, when the message rate is high, load and latency for Comet long-polling are identical to traditional polling, and for most cases the load and latency are significantly better than traditional polling.
The calculations for these graphs are in this Comet vs Polling spreadsheet. The assumptions made are that all messages are equal in size (150Bytes) and that the message arrival times are randomly but uniformly distributed. A maximum long poll timeout of 240s is assumed. The Y axis of the graphs is logarithmic so larger differences appear smaller.

Continue reading 【转】Comet is Always Better Than Polling

voice srgs语法相关

grxml:使用xml书写srgs的方式
abnf:rfc5234规范,
现在,几乎每一位新编程语言书籍的作者都使用巴科斯范式来定义编程语言的语法规则。
例如sql语法帮助也是用这个来描述的。
然而srgs中的abnf是混合bnf和abnf的语法,例如或|是bnf写法,/被改做为权重, =又是abnf写法,bnf写法是:=

-------------------------------------------abnf双模式示例
#ABNF 1.0 UTF-8;

language en;
mode voice;
root $basicCmd;

public $basicCmd = (dtmf-1 | yes) {y} | (dtmf-2 | no) {n};


------------------------------------------------------------------------

在voice中既然后台具备自然语言处理的能力,就不应该使用tag而应该直接返回所有匹配项。

$object = [the | a] (window | file | menu);
这样的写法用户说了the就会返回the,没说就不会返回the,所以都用[]比较好。
$object = [the | a] [window | file | menu];

--------------------------------------------------------------------------

grxml

item下面可以有ruleref但不能是rule

<rule id="r_3">
        <one-of>
            <item>
                <tag><![CDATA[Yes]]></tag>    //可以
                <ruleref uri="#r_4" />
            </item>
            <item>
                <tag><![CDATA[No]]></tag>
                <ruleref uri="#r_5" />
            </item>
        </one-of>
    </rule>

item在下面放one-of是可以的
<rule id="r_0">
        <one-of>
            <item>
                <tag><![CDATA[__QUERY__]]></tag>
                <item repeat="1-">
                    <one-of>
                        <item>what</item>
                        <item>who</item>
                        <item>where</item>
                        <item>how</item>
                        <item>why</item>
                        <item>whom</item>
                    </one-of>
                </item>
                <item repeat="0-">
                    <one-of>
                        <item>is</item>
                        <item>are</item>
                        <item>were</item>
                        <item>does</item>
                        <item>do</item>
                        <item>did</item>
                        <item>will</item>
                        <item>would</item>
                        <item>shall</item>
                        <item>should</item>
                        <item>may</item>
                        <item>might</item>
                    </one-of>
                </item>
                <item>
                    <ruleref special="GARBAGE" />
                </item>
            </item>
        </one-of>
    </rule>

Continue reading voice srgs语法相关

applet沙箱权限问题

官方解释:

http://download.oracle.com/javase/6/docs/technotes/guides/plugin/developer_guide/security.html

  • All unsigned applets are run under the standard applet security model.
  • If usePolicy is not defined in the java.policy file, then a signed applet has the AllPermission permission only if Java Plug-in can verify the signers, and the user agrees to granting the AllPermission permission when prompted.
  • If usePolicy is defined, then a signed applet has only the permissions defined in java.policy and no prompting occurs.

对于第二点,就是说签了名的一般都是有所有权限的。

但是还需要如下的处理[这个是必要的]
对于签名的applet,

  1. AccessController.doPrivileged(new PrivilegedExceptionAction() { 
  2.    public Object run() throws Exception { 
  3.    //you unsafe code                                          
  4.        return null; 
  5.    } 
  6. }); 


我们知道Java applet在浏览器中运行时默认情况下是不能访问本地资源的,比如读写客户端电脑上的文件。这是Java的安全沙箱机制,简单说就是有一组安全检查规 则,要通过检查之后才能访问特定资源。不过在企业应用中这种安全机制有时候并不是十分必要,这里我们就讨论一下在企业应用中突破沙箱检查的方案。
    当然,很多朋友会说,这太简单了,只需要改一下java.policy就可以了,授予程序对所有权限就可以了,就像下面这样:
     grant {
          permission java.security.AllPermission;
     };
没错,这样确实可以使客户端applet有权限访问任何资源,但是这个方案有个很实际的问题:java.policy是位于每个客户端电脑的jre 目录下的,如果要修改,那么就需要通知每一个使用该系统的用户,并指导他们做相应操作。这对于搞IT的用户来说是小菜一碟,但对一般业务人员来说却是个额 外的工作,这样的发布方式很难被人认可。

    另一个方案——对applet进行签名,用户访问时系统会弹出安全提示框,用户如果信任该程序,点击确认就相当于赋予了这个客户端小程序访问本地资源的权限。这是个很典雅的方案,体现了系统安全和对用户权利的尊重!具体做法大致如下:
    1、编写applet,编译并打成jar包
    2、对jar包签名
        这一步首先要产生证书,利用jdk提供的工具,执行类似下面的命令:
       keytool -genkey -keystore d:\mykeys.store -alias test -validity 300
       根据系统提示执行完这个命令后会生成一个证书库,上例是:mykeys.store,-validity 300是证书有效期为300天的意思,接下来用这个证书库中的证书给jar包签名,仍然是jdk的工具,命令类似下面:
       jarsigner -keystore d:\mykeys.store d:\applet.jar test
    3、把applet.jar发布到应用服务器

    这个看似完美的方案实际也有一点问题,很多时候我们并不希望把客户端程序都打到一个jar包里,那么多个jar包就需要分别签名,每次修改完客户端程序, 都要重新打包和签名,不然就只有applet能访问本地资源。我们不想这么麻烦,甚至我们有时都不希望对客户端代码打包,这时候签名就不好实现了。那么如 何解决这个问题呢,看下面这招。
    既然applet已经被用户授权,那么是否可以在applet里改变安全管理器(SecurityManager)?实验证明是可以的!只需要继承 SecurityManager类,创建自己的安全管理器类,然后覆盖checkPermission方法,允许访问任何资源。在applet的init 方法中调用System.setSecurityManager把安全管理器设置为我们自己的就一切OK了!

    至此,我们彻底突破了沙箱检查,而且客户体验很好,完美的方案!

代码很简单,类似于下面这样即可:[这种解决方法我也加了,没有测试是否必须--好像不起作用,没签名的引用包还是报错]
public class MainApplet extends JApplet {

private class DefaultSecurityManager extends SecurityManager {
@Override
public void checkPermission(Permission perm, Object context) {
}

@Override
public void checkPermission(Permission perm) {
}
}

@Override
public void init() {
super.init();
System.setSecurityManager(new DefaultSecurityManager());
  }
}

总结:
如果有是默认权限之外的代码:
1:需要签名
2:需要在applet中

  1. AccessController.doPrivileged(new PrivilegedExceptionAction() { 
  2.    public Object run() throws Exception { 
  3.    //you unsafe code                                          
  4.        return null; 
  5.    } 
  6. }); 

3:需要用户接受证书

在写skype4java applet时遇到的问题都是关于将包内资源dll加载的问题,winp,skype4java的实现都在applet环境下工作不好,我的解决方法是将其复制到tmp目录下再加载即可。

Continue reading applet沙箱权限问题

html5资源

[标准]
http://dev.w3.org/html5/postmsg/
http://dev.w3.org/html5/websockets/
http://dev.w3.org/html5/eventsource/
[当前实现]
http://en.wikipedia.org/wiki/Comparison_of_layout_engines_%28HTML_5%29#Related_specifications
[game教程]
http://www.brighthub.com/hubfolio/matthew-casperson/blog/archive/2009/06/29/game-development-with-javascript-and-the-canvas-element.aspx
[中文教程]
http://kb.operachina.com/node/190
[cake框架教程]
http://www.brighthub.com/hubfolio/matthew-casperson/blog/archive/2009/08/24/cake-programming-tutrorials.aspx
gif动画转图片
http://share.wglm.net:81/ts/Ulead_GIF_Animator5.0.rar
游戏
https://github.com/oldj/html5-tower-defense
websocket的缺陷
http://blogs.webtide.com/gregw/entry/websocket_chat
1:经常断线
2:不知道是否发送成功
3:keepalive
4:消息重发导致死循环[消息体过大]
替代物

Comet is Always Better Than Polling

-----------------------------------------------------------------------------------------------------------------------------

 

推荐10款非常优秀的HTML5开发工具

2011-10-09 09:37 | 2649次阅读 | 来源:梦想天空的博客 【已有0条评论】发表评论

关键词:HTML5 | 作者:梦想天空 | 收藏这篇资讯

HTML5发展如火如荼,随着各大浏览器对HTML5技术支持的不断完善以及HTML5技术的不断成熟,未来HTML5必将改变我们创建Web应用程序的方式。今天这篇文章向大家推荐10款优秀的HTML5开发工具,帮助你更高效的编写HTML5应用。

1.Initializr

推荐10款非常优秀的 HTML5 开发工具

Initializr是制作HTML5网站最好的入门辅助工具,你可以使用提供的特色模板快速生成网站,也可以自定义,Initializr会为你生成代码简洁的可定制的网页模板。

2.HTML5demos

推荐10款非常优秀的 HTML5 开发工具

想知道你的浏览器是否支持HTML5 Canvas吗?想知道Safari是否可以运行简单的HTML5聊天客户端吗?HTML5demos会告诉你每一个HTML5特性在哪些浏览器中支持。

3.HTML5 Tracker

推荐10款非常优秀的 HTML5 开发工具

想了解HTML5的最新动向吗?使用HTML5 Tracker吧,它可以跟踪HTML5最新修订信息。

4.HTML5 visual cheat sheet

推荐10款非常优秀的 HTML5 开发工具

想要快速超找一个标签或者属性吗?看看这个非常酷的速查手册吧,每个Web开发人员的必备。

5.Switch To HTML5

推荐10款非常优秀的 HTML5 开发工具

Switch To HTML5是一个基础而有效模板生成工具。如果你开始一个新项目,可以到这里获取免费的HTML5网站模板。

6.Cross browser HTML5 forms

推荐10款非常优秀的 HTML5 开发工具

HTML5中的日历,取色板,滑块部件等都是非常棒工具,但是有些浏览器不支持。这个页面将帮助你构建完美的HTML5表单兼容方案。

7.HTML5 Test

推荐10款非常优秀的 HTML5 开发工具

你浏览器准备好迎接HTML5革命了吗?HTML5 Test将告诉你。这个网站会为你当前使用的浏览器生成一份对video、audio、canvas等等特性的支持情况的完整报告。

8.HTML Cheat Sheat

Canvas元素是HTML5最重要的元素之一,它可以在网页中绘制图形,非常强大。这是一个Canvas元素的详细速查手册。

9.Lime JS

推荐10款非常优秀的 HTML5 开发工具

LimeJS是一个HTML5游戏开发框架,用于快速构建运行于触屏设备和桌面浏览器的游戏。非常棒,一定要用用试试。

10.HTML5 Reset

推荐10款非常优秀的 HTML5 开发工具

HTML5 Reset是一组文件,包括HTML、CSS等,用于在开始新项目的时候帮助你节省时间,提供HTML5的空白WordPress模板。

Continue reading html5资源

[转]WebTest比拼Selenium:模拟和真实浏览器上的测试

 

作者 Geoffrey Wiseman 译者 乔梁 发布于 2007年11月5日 上午1时24

Web应用软件的功能测试工具有很多种,但它们最根本的差异在于:某些工具可以驱动一个或多个真正的浏览器以便得到完全真实的环境,比如Selenium,而另一些工具只是模拟Web浏览器的操作,比如Canoo WebTest。Marc Guillemot这两种工具进行了对比,根据他的观点,WebTest以13:5的比分获胜。
Marc就以下方面内容对这两种工具进行了对比和评分:

Canoo WebTest

Selenium

Tied

Reports

Browser Fidelity

Testing Ajax

Speed

Beginner Friendly

Integration into Development Process

Support for Badly Formatted HTML Code

Scalability

Multi-Language Support

Capture JS Errors

Documentation

Predictable Behaviour

XPath Support

Extensibility

Data-Driven Tests

Internationalization Support

Support for Non-HTML Content

Marc认为,这些测试不够快,但“WetTest 的工作不多,所有测试都运行在JVM上”。他也提到Selenium无法捕获Javascript错误导致的测试失败:
只要你的单元测试通过了,你就不在意编辑错误了吗?肯定不是!但事实上,Selenium就是这样的,因为它不能检测到你的应用程序中的javascript错误(除非这些测试直接导致测试失败)。
另外,他也提到Ajax 测试(一般来说,大家都认为这是浏览器模拟器的弱点)是一种纽带:
与一般的想法相反,你并不需要在浏览器中运行你的JavaScript测试来测试AJAX功能。HtmlUnit和WebTest可以完成这样的工作,甚至可以称为完全胜任这样的工作,因为它允许更好地测试页内请求,使不可预知的浏览器行为成为可预知的(参见我前一个帖子)。
另一方面,他相信Selenium可以支持多种语言,“Selenium RC可以与不同的开发语言(Java、Ruby、PHP等等)结合,而WebTest只能与Ant结合使用”,还支持不规范的Html以及真实的浏览器:
HtmlUnit对JavaScript支持已经大幅改善,但还不能(且永远不可能)与真正的浏览器行为一模一样。尽管Selenium也更改了一些Web应用的JavaScript正常执行,但它使用真正的浏览器工作,所以已经和浏览器的标准行为相当接近啦。
作为Canoo WebTest和HtmlUnit的首席开发人员,Marc明显倾向于他所接纳的这种形式的工具,在与他讨论之前,请一定要先读一下他的分析报告:
显然,作为WebTest(和HtmlUnit)的负责人,我的确是有倾向性的。但是,我也有多年开发和维护庞大的功能测试套件的经验。客观一点儿说,我可能在其它方向上过分担心了,应该相信Selenium。当然,我将不断地修正我在Selenium理解上的错误。但请您在开始批评我之前,一定要读一下这篇文章。
已经总结了这些反馈。Vitaly认为,WebTest和Selenium的关系可以看作是苹果和桔子的关系。“Selenium,WebTest(HttpUnit),DBUnit,JUnit和其它测试工具是互补的。有些事用这个工具可能完成,用另外一个工具却不成。”还有些人讨论了录制回放和脚本测试各自的优点,以及测试可维护性。Murali推荐使用PragmaticQA Element
Christian反驳了WebTest对Ajax支持的说法,并提及在他的应用中,“由于HtmlUnit不能解析Dojo的import子句,即使最简单的页面也会抛出异常。”
而Simon认为,对浏览器保真度最重要的一点就是:
象 WebTest这样的工具有点太理论化了,它想证明代码完全正常工作,但是只能在理想环境下,与生产环境相去甚远。真正的用户使用的是IE或 Firefox,而Selenium可以让我们在“真实的”条件下做测试,例如有内存泄漏问题的脆弱的浏览器,和不符合标准的代码。
没有客户使用WebTest使用的引擎,这意味着尽管我们知道它在某种环境上运行得很好,但并不意味着真的没有麻烦。相反,我们的Selenium测试运行在Firefox之上,也运行在IE之上,所以它会捕获跨平台使用中发生的很多问题。
最后,Kent Tong设想了结合两种方法的途径
是否可以开发这样一种中间层,即大家只写一套测试,即可以运行在WebTest上,又可以运行在Selenium之上?这样,大家就可以得到WebTest和Selenium各自带来的好处了。
你用过这些工具吗,或者其它功能测试工具?这会吸引你参与讨论下一代功能测试工具吗?更多的信息,请阅读Canoo WebTestSeleniumTesting下一代功能测试工具
英文原文链接:WebTest vs. Selenium: Real and Simulated Browser Testing

相关厂商内容

Web App应用开发者大会火热报名中(4月27日 北京 免费)!
2011年5月11日-13日第十届中国系统与软件过程改进年会
Adobe Flash Builder 4简体中文正式版高速下载

2 条回复

关注此讨论 回复
真实的环境下测试 发表人 胡 凯 发表于 2007年11月5日 上午8时15分

Re: 真实的环境下测试 发表人 blogbin avatar 发表于 2007年11月16日 上午7时7分

按日期倒序排列

  1. 返回顶部
  2. 真实的环境下测试
  3. 2007年11月5日 上午8时15分 发表人 胡 凯
  4. 在项目中有同时使用JWebUnit和Selenium, 虽然每天都在Selenium缓慢的运行中煎熬, 但是依然推荐使用, 进行这样功能测试的目的之一就是希望在所有目标环境中这部分功能都是可以正常工作的。 也就是在真实的条件下作测试, 在JWebunit中正确通过的功能, 能否在IE6/7, firefox,中正确工作? 所有人大概心里都没底。
  5. JWebUnit的速度很快,但是在运行的过程中开发者缺乏对Web项目的最直观的体验, 而且其使用的JS 引擎对于某些正确的js也会抛出异常,后来不得不关闭JWebUnit的javascript engine.
  6. 事实上JWebunit测试可以用做整个开发流程的Checkin gate, 将覆盖基本功能,容易失败的测试用JWebunit完成,在测试通过后就可以提交,然后进行下一步的工作,同时在CI Server上在多个浏览器中运行较为缓慢的Selenium作为acceptance gate。 这大概是能兼顾速度和“真实”的一种方式。
  7. --
  8. Hu Kai
  9. 回复
  10. 返回顶部
  11. Re: 真实的环境下测试
  12. 2007年11月16日 上午7时7分 发表人 blogbin avatar
  13. 是否可以开发这样一种中间层,即大家只写一套测试,即可以运行在WebTest上,
  14. 又可以运行在Selenium之上?这样,大家就可以得到WebTest和Selenium各自带来的好处
  15. 同感:
  16. 测试脚本的设计,开发和维护的工作量相当大,能够让正常跑起来实属不易。
  17. 不同厂商和组织提供许多测试工具,不过这些测试脚本并没有形成统一的标准和规范。

Continue reading [转]WebTest比拼Selenium:模拟和真实浏览器上的测试

hibernate杂项

使用hibernate自动生成工具时 会自动加catorry
如:
<hibernate-mapping>
    <class name="co.iplatform.management.data.Health" table="tservice_health" catalog=”xxx”>
但是往往你刚开始用的数据库名是暂时的,与产品库不一样,所以发布时要注意改正这些名字。( 如果不一致mysql报错却是什么拒绝访问某表,根本不知道是数据库选错了)
一般的不需要catalog比较好,在数据库连接字符串里指定默认数据库就行了。
数据库表名大小写敏感?反正mysql是这样的aBc != abc
乱码问题,数据库要设置好编码, 连接也需要写好编码 例如 :
jdbc:mysql://localhost:13306/moviebug?useUnicode=true&amp;characterEncoding=UTF-8
还不行,则要查找其他原因

--------------------

native sql

以前查询把查询放在事务里面就可以保证取得最新数据,这次在management console里面就遇到问题,调用native sql后查询的还是旧数据。

hibernate说当调用commit或session.flush时会同步数据,网上说commit是先flush在提交。
不管怎样,flush一定会同步数据,这是最保险的做法。

且查询不一定需要放在事务里面(某些情况除外)。

对于使用了native sql的情况,要注意,hibernate并不知道native sql会对数据产生影响,所以,执行了native sql后要session.flush而且要clear。

-------------------------


Continue reading hibernate杂项

爬数据问题

想截取豆瓣的内容 ,发现以下问题 
一般的 网站都有防止被 iframe包含的脚本 ,所以 用iframe不行
我再试 window.open打开窗口来 加载脚本 ,但是
window的 onload事件 不能 监听,可能是跨域 问题 ,那么就做不下去了
-------------------
>

(function() {
function g_log(msg) {
if (!window.mylog_win) {
 window.mylog_win = window.open('', 'log');
}
var doc = window.mylog_win.document;
doc.write(msg + '<br>');
}
function DoubanTask() {
var URL = 'http://movie.douban.com/subject/';
var INDEX_BEGIN = 1000000;
var INDEX_END = 1999999;
var TRYCOUNT = 3;
var tryicount = 0;
var win = window.open('', 'doubanwin');
var url_index = INDEX_BEGIN;
function log (msg) {
 g_log(msg);
};
function getData() {
 var doc = Ext.get(win.document.body);
 var score = doc.query('strong[property=v:average]')
 if (!score || !score.length) {
  log('score not find,return null.');
  return null;
 }
 score = score[0].innerHTML;
 var vote = doc.query('span[property=v:votes]')
 if (!vote || !vote.length) {
  log('score not find,return null.');
  return null;
 }
 vote = vote[0].innerHTML;
 var name = doc.query('span[property=v:itemreviewed]')
 if (!name || !name.length) {
  log('name not find,return null.');
  return null;
 }
 name = name[0].innerHTML;
 var year = doc.query('span[class=year]')
 if (year && year.length) {
  year = year[0].innerHTML;
 }
 var director = doc.query('a[rel=v:directedBy]')
 if (director && director.length) {
  director = director[0].innerHTML;
 }
 if (year) {
  var i0 = year.indexOf('(');
  if (-1 != i0) {
   year = year.substring(i0 + 1);
  }
  i0 = year.indexOf(')');
  if (-1 != i0) {
   year = year.substring(0, i0);
  }
 }
 return {
  score : score,
  vote : vote,
  name : name,
  year : year,
  director : director
 };
}
function onloadfunc(url) {
 var data = getData();
 if (!data) {
  log('retrive no data in [' + url + '],continue.');
  runtask();
  return;
 }
 data.url = url;
 log('get data:' + Ext.encode(data));
 Ext.Ajax.request({
    url : "mytime.ax",
    params : data,
    success : function() {
     tryicount = 0;
     log('submit ok for url:' + url);
     runtask();
    },
    failure : function() {
     tryicount += 1;
     log('submit fail[' + tryicount + '] for url:' + url);
     if (tryicount > TRYCOUNT) {
      tryicount = 0;
      log('cancel try for:' + url
        + ', move for next none.');
      runtask();
     } else {
      log('continue try for:' + url);
      onloadfunc(url);
     }
    }
   });
}
function runtask() {
 url_index += 1;
 if (url_index >= INDEX_END) {
  log('task complete!');
  return;
 }
 var url = URL + url_index;
 //no use, can't work
 win.document.body.onload = function() {
  onloadfunc(url);
 };
 win.location.href = url;
}
this.run = function() {
 runtask();
};
}
function onload() {
var dbTask = new DoubanTask();
var btnRun1 = Ext.get('btnStart');
btnRun1.on('click', function() {
   dbTask.run();
  });
}
Ext.fly(window).on('load', onload);
})();

-------------------------

>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <title>run.html</title>
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
    
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
    <script type="text/javascript" src="../js/ext-core.js"></script>
    <script type="text/javascript" src="js/main.js"></script>
</head>
<body>
 <table>
  <tr><td>
  <button id="btnStart">Start</button>
       
  <td></tr>
  <tr><td><iframe id="frm1"></iframe><td></tr>
 </table>    
</body>
</html>

-------------------------------

换取思路,可以使用ajax请求由服务端通过httpclient取得数据返回给客户端,再由客户端

写到iframe里面,这样就避开了跨域问题了。但是httpclient爬数据时要注意伪装成浏览器,加上请求头'User-Agent' : 'Mozilla/5.0 (Windows NT 5.1; rv:2.0) Gecko/20100101 Firefox/4.0',其余的就不要加了,加了反而会有问题(莫名其妙的返回)

HtmlUnit基于mozila实现,可以考虑

发现豆瓣提供api晕菜

-------------

Continue reading 爬数据问题

window.unload事件

window.unload事件:
用户刷新,关闭,后退,将地址栏重新打一遍(或者只打个回车)都会触发,但是服务端sendredirect则不会.
如果使用window.location.href=window.location.href也会触发
如果window.location.href=window.location.href在脚本第一行,后面的代码还是会执行的,但是页面文档则不会加载了,就是没有dom了。

Continue reading window.unload事件

jmx初步 控制台检监控技术探索

jmx资源:

ibm J2EE专题:
http://www.ibm.com/developerworks/cn/java/j-jee/j2ee-services.html#J2EEZ296
中的jmx部分
其中
http://www.ibm.com/developerworks/cn/java/j-lo-jse63/
这篇比较重要

Oracle的教程与example源代码
http://download.oracle.com/javase/1.5.0/docs/guide/jmx/tutorial/tutorialTOC.html
http://download.oracle.com/javase/1.5.0/docs/guide/jmx/examples.html
http://download.oracle.com/javase/1.5.0/docs/guide/management/agent.html

在其例子Basic中有个问题,rmiServer不好绑定,其原因是缺少LocateRegistry.createRegistry(connectorPort);这一句
具体见 http://www.iteye.com/topic/358379

基本概念:
MBean 规定了标准 MBean 也要实现一个接口,所有向外界公开的方法都要在这个接口中声明。否则,管理系统就不能从中获得相应的信息。此外,该接口的名字也有一定的规范:即在标准 MBean 类名之后加上“MBean”后缀。若 MBean 的类名叫做 MBeansName 的话,对应的接口就要叫做 MBeansNameMBean。

动态MBean要实现DynamicMBean接口。

MXBean(注意多个X)是OpenBean(1.6以后才有官方文档介绍) 
Open MBean 与其它动态 MBean 的唯一区别在于,前者对其公开接口的参数和返回值有所限制 —— 只能是基本类型或者 javax.management.openmbean包内的 ArrayType、CompositeType、TarbularType 等类型。这主要是考虑到管理系统的分布,很可能远端管理系统甚至 MBServer 层都不具有 MBean 接口中特殊的类。

还有个区别,标准mbean要求接口和实现类在同一个包中,而open bean则没有这个要求。[http://blogs.oracle.com/jmxetc/entry/javax_management_standardmbean_when_and] 

Model Bean
具有持久化,日志等功能,但要看具体容器的支持。


jmx客户端和jmx服务端:
客户端通过RMI连接服务端获取信息。
服务端一般是某个容器或服务器的附加功能,它们依据jmx规范写出容器的管理Mbean。tomcat,mule都实现了。

getPlatformMBeanServer是获得已存在的server,一般是本地虚拟机上的

如果注册在 getPlatformMBeanServer上,则可通过增加JVM参数来增加jmx控制,参见http://kazge.com/archives/516.html

这种方式与创建专门的MBeanServer所不同的是自动会包含Platform MBeans(java.lang/com.sun.management)Logging Management(java.util.logging)这些个MBean,参见

http://download.oracle.com/javase/1.5.0/docs/guide/management/overview.html

访问远程jvm的技术jstad:
http://download.oracle.com/javase/6/docs/technotes/tools/share/jstatd.html
注意里面的申明:可能在以后不支持。
NOTE: This utility is unsupported and may or may not be available in future versions of the JDK. It is not currently available on the Windows 98 and Windows ME platforms.
只能监控,不能操作。
需要制定policy -J-Djava.security.policy 和hostname(nat环境下)-Djava.rmi.server.hostname=
否则会有问题
参见
http://hi.baidu.com/passedbylove/blog/item/b600b2a8b6ebc2bacb130cc5.html
http://hi.baidu.com/luohuazju/blog/item/36ddd6103a51b2f6c3ce79c0.html

visualvm用于监测远程机器:
http://java.net/projects/visualvm/content/jmx_connections.html
但是如果远程jvm没有开放监测端口,可使用设置com.sun.management.jmxremote.*参数的办法,让每个你想检测的程序都开放一个检测端口(这个就不太好了,如果一个平台里面有许多应用,那么开那么多的端口本身就很耗资源。)



服务端注册/创建:

         MBeanServer mbs = MBeanServerFactory.createMBeanServer(); 
         String domain = mbs.getDefaultDomain(); 
         
         MemoryMXBean obean = ManagementFactory.getMemoryMXBean(); 
         ObjectName on = new ObjectName(domain+":type=abc"); //名字只是个key,只要客户端与之对应就找得到 
         mbs.registerMBean(obean, on); 

客户端查找:

MemoryMXBean proxy = JMX.newMXBeanProxy(mbsc, stdMBeanName, MemoryMXBean.class); 
//注意上面多了个X,因为是查找Open MBean,其他类型应该使用newMBeanProxy 

监听服务断开事件

>JMXConnector jmxc =...; jmxc.addConnectionNotificationListener(new NotificationListener(){

Continue reading jmx初步 控制台检监控技术探索

Pagination


Total views.

© 2013 - 2019. All rights reserved.

Powered by Hydejack v6.6.1