paulwong

#

ACTIVITI KICK START

https://github.com/jbarrez/Activiti-KickStart

一个基于ACTIVITI的内容管理系统:
http://code.google.com/p/echoice/source/browse

ACTIVITI中文使用手册:
http://www.georgeinfo.com/file/activiti-doc.pdf

posted @ 2012-04-01 00:43 paulwong 阅读(270) | 评论 (0)编辑 收藏

使用 WS-AtomicTransaction 和 JTA 的分布式事务

http://wenku.baidu.com/view/f3126425ccbff121dd3683b3.html

在现在的企业应用程序的开发中,Web 服务已经越来越普遍。然而,从传统意义上来说,它们还没有达到和所支持的服务相同的水平。当构建 J2EE 应用程序,特别是事务服务的时候,企业依赖于这些服务。本文概述了事务服务是如何在一个使用 Java Transaction API 的 J2EE 环境中的 Web 服务事务的帮助下,与 Web 服务实现无缝连接的。

本文简要地概述了这项新的 Web 服务技术和已被证实的传统的事务技术,解释了它们是如何能够跨分布式的 J2EE 环境甚至跨不同的事务体系结构来实现互操作的。

本文假设您已经对事务服务的概念(例如,ACID properties、提交/回滚、事务划分,等等)的理解达到中级水平。要想了解事务服务的进一步信息,特别是 JTS,请参考文章 Java theory and practice:Understanding JTS —— An introduction to transactions。这篇文章可以在 developerWorks 上找到(请参阅 参考资料)。同样,我也想要推荐一本关于事务的更全面信息的好书,它就是由 Philip Bernstein 和 Eric Newcomer 合著的 Principles of Transaction Processing(请参阅 参考资料


什么是 Java Transaction API(JTA)?

JTA 是事务服务的 J2EE 解决方案。本质上,它是描述事务接口(比如 UserTransaction 接口,开发人员直接使用该接口或者通过 J2EE 容器使用该接口来确保业务逻辑能够可靠地运行)的 J2EE 模型的一部分。

JTA 具有的三个主要的接口分别是 UserTransaction 接口、 TransactionManager 接口和 Transaction 接口。这些接口共享公共的事务操作,例如 commit()rollback() , 但是也包含特殊的事务操作,例如 suspend()resume()enlist() ,它们只出现在特定的接口上,以便在实现中允许一定程度的访问控制。例如, UserTransaction 能够执行事务划分和基本的事务操作,而 TransactionManager 能够执行上下文管理。本文仅仅需要您对 JTA 有一个基本的了解。


JTA 的好处?

JTA 是一个定义明确的事务服务,向 J2EE 应用程序开发人员提供一种可以直接使用的服务。作为选择,一个应用程序也可能这样部署,容器将代替开发人员来管理事务行为。在后一种情况下,开发人员能够全神贯注于他们的应用程序的业务逻辑,同时由 J2EE 容器来负责事务逻辑。

模型明确的事务服务的好处是对于每个单独的事务总是维持四个 ACID 特性。尽管这是一个实现相关的问题,WebSphere Application Server 提供为每个导入的或者导出的事务保护这些 ACID 特性的能力,而不管并发的事务数目是多少。


JTA 的限制?

经历过所有的事务体系结构,想要有效地将一组事务传送给其他并不共享同样模型的事务服务,同时保持原子的工作单元,是非常困难的。在我们的案例中,建模的 JTA 运行在 Java Transaction Service(JTS) 之上,JTS 处理输入和输出事务传送的请求。

因为 JTS 是一种由 CORBA 定义的对象事务服务(OTS)的 Java 实现,它只能够与另一个 OTS 模型连接。因此, 一个事务只能传送给另一个 OTS-兼容的目标,典型地即另一个 J2EE 实现。因为 JTA 和 JTS 规范没有对这些接口的底层实现加以限制 (只要它们符合模型),事务可以安全地在两个 J2EE-兼容的应用程序服务器之间传送,而没有丢失它们的 ACID 特性的风险。然而,J2EE 服务器并不必须处理非 J2EE 调用。

某些 J2EE 服务器可能是例外;例如,WebSphere Application Server 将正确地处理一个与 CORBA 兼容事务相关联的输入的 CORBA 请求,将这个事务传送给线程,然后在它的上下文里执行事务工作。然而,在大多数情况下,当您试图在事务模型之间移动的时候,您不得不超越 JTA 和 JTS,把目光投得更远,在这里 Web 服务出现了。


什么是 Web 服务?

Web 服务是一种能够作为应用程序一部分部署在可访问的服务器上供内部和外部客户使用的对象。Web 服务由它的 Web 服务描述语言(WSDL)来描述。它定义了一个使用基于 XML 调用(典型地使用 SOAP 协议)的 Web 服务的输入和输出参数的用法。例如,客户端可以查看已经由服务器发布的 WSDL,然后构造客户端代码来调用 Web 服务。一旦完成,它就能够通过将 SOAP 消息传递给 Web 服务的一个方法来调用它。在这条 SOAP 消息中包括诸如方法 名称的信息以及任何它所需要的参数。返回值将在另一条 SOAP 消息里被传送回来,再由客户提取出来。


使用 Web 服务的好处?

Web 服务由哪种语言编写而成并不重要,因为 WSDL 没有定义语言或者编程的模型相关的细节(例如,Java 和 J2EE 技术)。这就给了 Web 服务的作者和客户端的作者选择他首选的解决方案 的灵活性。

让我们来比较一下 Web 服务和 Enterprise JavaBean(EJB)组件。EJB 组件要求 RMI-编译的代码,以便使客户端能够访问,所以 它能够像它的代理一样创造本地的存根(stub)对象。因此,这将需要在每一次它们改变的时候,向所有的客户端重新分配存根(stub)。 无论如何,和 Web 服务一起您将使用 WSDL,所以客户端能够构造它们自己的客户端调用代码,在本地类路径上不需要服务器的类来执行调用。这个模型提供了一个非常巧妙的方法调用过程。 EJB,作为 J2EE 模型的一部分,必须使用 Java 客户来调用,最好是一个 J2EE 管理的客户端。另一方面,Web 服务可以被任何客户端代码所调用,这个代码能够构造一个结构良好的 SOAP 请求。因而,举例来说,一个部署在 J2EE 服务 器上的 Web 服务能够使用 C++ 客户来调用。


Web 服务的限制?

因为 Web 服务请求(通过 HTTP 的 SOAP)的性质与其他的方法调用(例如,一个使用通过 IIOP 的 RMI 的 EJB 调用)差别很大,支持执行分布式事务的代码直到最近才可获得。这已经成为在 使用 Web 服务作为分布式事务企业应用程序一部分时,主要的问题。本质上,Web 服务不能运行在 Web 服务调用之前开始的事务上下文 中,也不能将一个事务上下文传送给另一个组件。


那么,问题是什么呢?

如果 Web 服务被用于工业,必须确保它们在事务环境 中运行的时候,以可靠的和可预知的方式工作。直到现在,Web 服务只能够使用独立于其他组件的事务——在 Web 服务的方法范围里划分的 和服从它的底层的事务实现的规则——并且物理上不能离开 Web 服务或者进入另一个 Web 服务。企业应用程序具有始终在企业组件间流动 的事务。这需要成为 Web 服务的标准来确保它们能够被正确地使用,通过利用 Web 服务的功能仅仅忽略在我们的所有严格的企业应用 程序中依赖的和使用的事务支持来避免改变您的编程风格。


那么,解决方案是什么呢?

解决方案就是一种称为 Web 服务事务(WS-Transaction) 的新技术。它能够调整事务的上下文。这个上下文可以被 Web 服务、其他的诸如 EJB 的 J2EE 组件、甚至其他支持 WS-Transaction 的 非 J2EE 事务服务使用。

WS-Transaction 是一个规范。它扩展了 Web 服务协调(WS-Coordination)规范来定义一种支持原子事务的协调。


什么是 WS-Coordination

WS-Coordination 是一个协调框架来使分布的参与者 能够在他们个体行动之上就一个通用的结果达成协议。

本质上,这意味着分布式的参与者(例如,在不同机器上的两个应用程序服务器)将能够使用 WS-Coordination 把每个参与者 的行为集在合一起,进一步地,并且通过确保它们完全同意对于在这个协调上下文里它们各自执行的所有行为均产生单一的结果,来 进一步管理这些行为。否则,则不能以一个受控的方式来完成这些功能。

协调上下文可以被看作是一个标识符,行为执行在这个标识符之下。作一比较,这个概念非常类似于事务上下文。当事务工作完成, 在事务上下文里管理它,当调用这个上下文去确定或会滚时这个工作完成。协调上下文包含的附加信息是一个协调标识符、关于协调类型的 详细资料以及包括端口信息以便协调服务能够被访问的协调协议。在下面定义了这些术语。

 

协调服务,或者 协调器(Coordinator), 进一步由三个服务组成: 激活服务(activation service)注册服务(registration service)协调协议(coordination protocol) 服务。激活服务支持 CreateCoodinationContext 操作来允许新的协调上下文存在。注册服务支持 Register 操作来允许参与者 在协调上下文中执行工作。协调协议服务支持协调协议的使用,这个协议定义了协调器(Coordinator)和参与者之间的行为和通信。

协调类型是一个协调行为的固定的集合,这个集合详细说明了协调协议的集合以及协调器(Coordinator)应该如何驱动完成。 WS-Transaction 规范描述了两个协调类型—— 原子事务(Atomic Transaction)(AT)和 业务协定(Business Agreement)(BA)。 这些协调类型中的每一个都包括协调协议。例如,原子事务(Atomic Transaction)协调类型包括像 two-phase commit protocol(Durable2PC)和 phaseZero protocol(Volatile2PC)这样的协调协议。 您可以希望在支持原子事务的环境中使用这两个协议。

业务协定(Business Agreement)协调类型提供了一种不同的功能类型。它被设计成用于更长的时帧。而不像原子事务,正常地您 与它联系一个非常短的生命期。业务协定协议(Business Agreement protocol)的一个例子就是它自己,被称作业务协定(Business Agreement) 它是一个补偿协议。


WS-Coordination 和 WS-Transaction 之间是什么关系?

WS-Coordination 是基本的框架,使参与者之间活动的分布式结果成为可能。WS-Transaction 定义了协调类型,例如原子事务(Atomic Transaction),协调类型使用 WS-Coordination 框架来定义规则。在协调器(Coordinator)和参与者通信时,它们必须遵循这些规则。两者之间的这个区别很重要。

两个应用程序和一个协调器(Coordinator)之间主要的协调流程如下面的 图 1所示。


图 1. 基本协调流程
  1. App1 向在协调器上的激活服务提出一个请求。
  2. 协调器开始一个新的活动,使用它的 CoordinationContext (协调器的 XML 消息)来对 App1 做出响应。
  3. App1向注册服务提出请求来注册使用协调协议X。
  4. App1 以它期望的方式调用 App2,传递 CoordinationContext 给协调器。
  5. App2 向注册服务提出请求(使用诸如端口信息的参数,它们 可以在 App1 传递的 CoordinationContext 中找到)来注册使用协调协议Y。
  6. App2结束它的工作,将控制返还给 App1,活动结束。
  7. 协调器使用协议 X 类型消息响应 App1
  8. 协调器使用协议 Y 类型消息响应 App2


协调器调解

在一个现实世界的情况中,Web 服务可能是事务的和分布式的,协调器的发起者( App1)将 CoordinationContext 传递给任何它所期望的活动中的参与者( App2)。这个上下文的接收者有两种选择:它们可以使用已经创建好了的协调器( Ca),或者如果它们愿意,也可以在初始的 CoordinationContext 中传递创建的新的协调器。然后,第二种选择将新的协调器( Cb) 作为 App2的代理协调器。它将包括与协调器 Ca相同的活动标识符,但是当 App2向它的协调器 Cb注册 Durable2PC 协议的时候,它的请求直接传送给了协调器 Ca。 类似地,在结束时,准备和提交消息在最终到达 App2(它已经注册过 Durable2PC 协议)之前将从协调器 Ca传递给协调器 Cb

请参阅 WS-Transaction 规范的 4.1 节 AT3.1 Example Atomic Transaction Message Flow,在那里您将看到一个应用程序和调解的协调器之间的 WS-Coordination 流程的非常好的示例(请参阅 参考资料)。


Web 服务事务:原子事务(WS-AtomicTransaction)

WS-AtomicTransaction 是一种对于原子事务的特殊的协调类型,它提供了一组协调协议。这些协调协议是:

  • Completion
  • CompletionWithAck
  • Volatile2PC
  • Durable2PC
  • OutcomeNotification

当协调上下文创建以后,协调类型被指定,但是协调协议直到注册时才被指定。任何参与者可以注册任意数目的协调协议,应该发送和接收 由协议定义的恰当的消息。例如,如果一个参与者在协调器中注册了 Durable2PC 协议,当完成时一条准备消息将被发送给这个参与者,它们将被认为以与正常的事务资源相似的方式投票。想要了解这里每个协议的信息和它们的状态图,请查阅 WS-Transaction 规范, 第 4 节 AT3 Coordination protocols(请参阅 参考资料)。


如何能将 JTA 事务和 WS-AtomicTransaction 一起使用?

因为 JTA 和 JTS 是实现相关的,我将使用的这个示例是 WebSphere Application Server V5.0.2 和 WS-Transaction Tech Preview。这个场景将有两台机器,每个上都运行有应用程序服务器,如 图 2 所示。 应用程序服务器A部署并运行一个 Bean Managed Transaction(BMT)EJB 组件。应用程序服务器B部署并运行一个 Web 服务。 EJB 组件通过使用 JTA 提供的接口 UserTransaction 开始一个事务。它对 XA-compliant database 执行事务工作(步骤 1),然后使用 SOAP/HTTP 向在应用程序服务器B上的 Web 服务发送一个请求(步骤 2)。Web 服务对 XA-compliant database 执行工作(步骤 3),然后返回到 EJB 组件(步骤 4),由它再次使用 UserTransaction 接口来提交事务。所有由 EJB 和 Web 服务对数据库执行的事务都已经被包含在一个活动的范围里,这个活动是由协调器恰好在调用 Web 服务(步骤 2)之前创建的,它已经被提交,同时保存着所有的 ACID 特性,它就好像是单一的工作单元。

让我们来看看下面的两个领域——J2EE 领域和 Web 服务领域。在 J2EE 领域里,使用的事务模型是 JTA。在 Web 服务领域里, 使用的事务模型是 WS-AtomicTransaction。WebSphere Application Server 把一个 Java Web 服务看作是一个 J2EE 对象,因此也就 意味着,Web 服务的实现属于 J2EE 领域,而调用属于 Web 服务领域。在 WebSphere 领域,正确地驱动协议总是正在被使用的模型 (JTA 或者 WS-AtomicTransaction)的责任。

图 2 展示了 在一个事务企业应用程序中包含 Web 服务是多么的容易,同时也展示了对于没有费一行代码麻烦就在导入的事务上下文中运行这个 Web 服务的用户来说,它又是多么的无缝。


图 2. 使用 JTA 事务和 WS-AtomicTransaction 事务

请注意:The EJB 组件正运行在一个受管理的环境中(EJB 容器)并且 Web 服务是符合 JSR 109。

它只能和 JTA 一起工作吗?

WS-Coordination 依靠它的基于XML的调用来 利用它本身是 Web 服务的优势。因为用来调用 WS-Coordination 操作的协议是 SOAP,消息内容是 XML 格式的纯文本。这意味着,当使用 HTTP 传递给 Web 服务时,将不能仅仅通过 SOAP 包本身来确定客户的详细资料,例如编程语言。因此,WS-AtomicTransaction 将能够与任何其他的使用任何支持 WS-AtomicTransaction 的编程语言编码的事务服务相连接。

在近来的一个由 IBM 和 Microsoft 主办的 Web 服务演示上,展示了 WS-AtomicTransaction 的这个跨事务服务和编程语言的互操作性。 图 3 展示了一个示范这项技术的场景。

图 3 中有一个.NET 服务器开始一个非 JTA 事务,向两个 WebSphere 应用程序服务器和另外一个.NET 服务器提出了 Web 服务调用请求。每个应用程序服务器都使用它们的底层事务服务来执行事务工作。每次您能够使用 WS-Transaction 调用一个您将转到的 Web 服务。当发起者完成事务,您使用 WS-Transaction 技术来协调每个参与者,确保它们都已完成,就好像它们是单一的工作单元似的。


图 3. 在 Steve Mills 和 Bill Gates 的 Web 服务演示中的一个 WS-AtomicTransaction 场景的示例拓扑。

总结

在本文中,您已经了解到 WS-Coordination 和 WS-Transaction 的基本概念。到现在为止,Web 服务还不能在分布式环境里使用事务。WS-Transaction 允许 Web 服务执行事务工作,这个事务工作作为更广泛的活动生成组件、应用程序服务器、甚至实现的一部分,正如在 IBM 和 Microsoft Web 服务演示中所展示的。

在 WS-Transaction 的支持下,我们能够可靠地使用 Web 服务作为我们的企业应用程序的一部分,因为它已经为事务支持嵌入到其他的企业组件里。

posted @ 2012-03-30 00:21 paulwong 阅读(919) | 评论 (0)编辑 收藏

分布式事务

一、 事务概述

1、 事务协议

WCF相关的事务协议有三个。

1.1. Lightweight protocol

这是个轻量级的本地事务协议,限制管理在一个AppDomain中的事务。不能跨AppDomain边界传播事务,也不能跨服务边界传播事务。跟其他协议比,Lightweight protocol是最有效率的协议。

1.2. OleTx protocol

这个协议可用于跨AppDomain,进程和机器边界,管理两阶段提交的事务协议。这个跨边界的事务协议使用RPC,是二进制的,windows专有的协议,不能穿越防火墙,也不能用于与非windows系统的互操作。在windows环境下的局域网,OleTx协议是很好的分布式事务的管理协议。

1.3. WS-Atomic Transaction (WSAT) protocol

WSATOleTx协议类似,也可以跨AppDomain,进程和机器边界,管理两阶段提交的事务协议。但WSAT不是微软的专有协议,此协议是微软、IBMBEA等公司共同提出的工业标准。此协议也可用于Intranet中,但是更多的是用于在Internet环境下,或者跟非windows系统进行互操作的分布式事务。

说到WSAT协议这里有必要一下分布式事务的发展。

分布式事务:

分布式事务在企业应用中是很重要的一个方面,微软使用MSDTC作为分布式事务管理器,使用OleTx事务协议进行分布式事务管理,但是OleTx事务协议是微软的专有协议,不是公认标准。在分布式环境中异构系统的交互一定要有个公认同意的分布式事务标准才能在异构的系统中实现分布式事务的协调。

l OGMXA事务规范

1994年,开放组织(Open Group)的 X/Open 分布式事务流程(DTP)模型,它定义了 应用程序如何使用 事务管理程序跨多个 资源管理程序来协调分布式事务。如果事务是通过遵循 XA 的事务管理程序来进行协调的,则任何遵循 XA 规范的资源管理程序都可以参与该事务,因此就可以让不同厂商的事务产品可以共同工作。所有遵循 XA 的事务都是分布式事务。XA 既支持一步提交,也支持两阶段提交。

对象管理组(Object Management Group)的通用对象请求代理体系结构对象事务服务(Common Object Request Broker Architecture Object Transaction Service -- 定义遵循规范的流程如何跨多个流程线程将事务上下文从一个流程传播到另一个流程。这种传播使得即使分布式对象运行于来自不同厂商的容器中,也可以在单个事务中合作。CORBA OTS 规范建立在 XA 规范的基础之上。

l OASISBusiness Transaction ProtocolBTP)标准

2001 年, 一个由各大公司(包括惠普公司(Hewlett-PackardHP)、甲骨文公司(Oracle)及BEA公司)组成的联盟开始着手创建 Organization for Advance Structured Information Systems (OASIS) Business Transaction ProtocolBTP)标准。

BTP 不是专门用于 Web 服务的事务处理协议,它的目的是它也能用于其他的环境中。因而,BTP 定义了事务性的 XML 协议,并且必须在规范中指定所有的服务依赖性。

BTP协议相对比较复杂,并且它把原子性事务和长时间运行的商业事务放在一起进行管理,这样它必须解决各种各样不同的问题。它是通过放松限制来这样做的,这表面上给人感觉灵活度很高,但是很多东西就留给实现者去实现了,导致使用比较复杂。

l OASISWS-Transactions

BTP出现后,其他一些行业大公司,包括 IBMMicrosoft BEA,又发布了它们自己的规范: Web 服务事务处理(WS-Transactions),由三部分组成WS-Coordination(事务协调器)、WS-AtomicTransaction(实现原子事务)、WS-BusinessActivity(实现长时间运行的商业事务)。WS-TransactionsBTP好的方面是它将事务协调器独立出来,另外用两个标准在WS-Transactions基础上分别实现原子事务和长时间运行的事务,这样简化了复杂性。

WS-Transactions是专门用于web services的事务规范。

2005年,WS-Transactions发布了第一个版本,Version 1.0

2007年,WS-Transactions发布了Version 1.1,并被OASIS组织接受为标准,成为WS-*标准的一部分。

WCF支持的可互操作的分布式事务协议只有WS-Transactions,并且只实现了WS-CoordinationWS-AtomicTransactionWS-BusinessActivity没被实现。

1.3.1. WS-Coordination

WS-Coordination它描述了一个可扩展的交流协议框架,该框架对分布式的请求进行其请求协议的判断与处理,处理后再将请求向下方的业务处理模块进行分发。

该 框架最大特点是其能够以系统流程代理的身份来处理请求。当不同的请求,无论是内部的同系统的请求或外部的异构系统的请求,经过该框架处理后,再其原有的特 殊的传输代理层上添加了符合本系统信息流规则的本地协议。也就是本系统允许已经存在的事务、工作流或其他服务的请求隐藏其自身独特的传输协议,并可顺利运 行于异构式的系统环境中。

当前WS-Coordination稳定的版本是1.1,同样是OASIS2007年发布的国际标准。现在1.2版本也在起草过程之中。WS-Coordination规范的具体实现需要开发中在基于XML的配置文件中引入WS-Coordination规范的命名空间,如指定<xsschema>字段的值为ws-addr.xsd。由于是基于XML文件来实现,WS-Coordination规范易于实现,且对日后的扩展支持度高。

通过WS-Coordination的使用,一方面通过附加统一的本地协议,在使用不同通信协议的请求到来时,进行统一的协议处理,加快了请求的处理速度,提高了系统的松耦合性;另一方面WS-Coordination规范所定义的框架加强了系统的异构性,使系统不因请求所使用的协议不同而无法处理,这提升了系统整体的兼容性,加强了系统的综合服务能力。

1.3.2. WS-AtomicTransaction

WS-AtomicTransaction 定义了一组特定的协议,这组协议可以插入 WS-Coordination 模型,以实现传统的两阶段原子事务处理协议。注意到原子的两阶段模型只是就涉及的服务而言的非常重要。提供服务的站点或基础体系结构可能大肆宣传两阶段提交,但是却使用一些其他的企业内部模型,比如补偿模型或版本模型。这种自由使简单的两阶段提交模型对于长期运行的 Internet 计算更有用。

WCF实现了WS-AtomicTransaction协议,事务管理器是由MSDTC实现,也就是说在WCF中可以使用WS-AtomicTransaction协议进行分布式事务的管理,并跟其他实现了WS-AtomicTransaction的异构分布式事务互操作。

1.3.3. WS-BusinessActivity

WS-BusinessActivity 定义了一组特定的协议,这组协议可以插入 WS-Coordination 模型,以实现长期运行的、基于补偿的事务处理协议。

WS-BusinessActivity定义的是long-running事务,所谓long-running事务是指那些企业业务流程,需要跨应用、跨企业来完成某个事务,甚至在事务流程中还需要有手工操作的参与,这类事务的完成时间可能以分计,以小时计,甚至可能以天计,这类事务也被称为SAGA

这类事务如果按照事务的ACID的要求去设计,势必造成系统的可用性大大的降低。试想一个由两台服务器一起参与的事务,服务器A发起事务,服务器B参与事务,B的事务需要人工参与,所以处理时间可能很长。如果按照ACID的原则,要保持事务的隔离性、一致性,服务器A中发起的事务中使用到的事务资源将会被锁定,不允许其他应用访问到事务过程中的中间结果,直到整个事务被提交或者回滚。这就造成事务A中的资源被长时间锁定,系统的可用性将不可接受。

WS-BusinessActivity提供了一种基于补偿的long-running的事务处理模型。还是上面的例子,服务器A的事务如果执行顺利,那么事务A就先行提交,如果事务B也执行顺利,则事务B也提交,整个事务就算完成。但是如果事务B执行失败,事务B本身回滚,这时事务A已经被提交,所以需要执行一个补偿操作,将已经提交的事务A执行的操作作反操作,恢复到未执行前事务A的状态。这样的SAGA事务模型,是牺牲了一定的隔离性和一致性的,但是提高了long-running事务的可用性。

目前的WCF中未实现WS-BusinessActivity,在WCF 4.0 beta2中也为实现,估计在WCF 4.0正式版中也不会实现WS-BusinessActivity协议。

2、 事务管理器

管理事务必须有相应的协议外,还必须有个事务管理器,事务管理器通过相应的事务协议对本机的事务进行管理。如果同一个事务需要跨机器,则每台参与事务的机器的事务管理器之间进行相互协调共同完成一个分布式事务。

2.1. LTM

轻型事务管理器Lightweight Transaction Manager,只能管理本地事务,事务在一个AppDomain内。LTM使用Lightweight protocol管理两阶段提交的事务。LTM只能管理单一的可持久化的资源,如果有两个以上的可持久化资源登记到事务中,LTM将被升级到DTC管理器。

2.2. KTM

Vistawindows2008引入了内核事务管理器Kernel Transaction Manager (KTM)

Windows Vista中还引入了两个主要的事务资源,事务NTFS和事务注册表,称作核心资源kernel resource managers (KRM)KTM可以管理这两类资源。

事务性 NTFS,也称为 TxF,使用TxF可以将文件操作纳入到事务管理中,在事务中的的文件操作将同事务中的其他事务资源一样在事务前后保持一致性。

同样事务性注册表,也称作TxR,注册表的操作也可以纳入到事务管理中。

KTMLTM一样,使用Lightweight protocol管理两阶段提交的事务,只能管理本地事务,事务在一个AppDomain内,只能管理单一的可持久化的资源。

2.3. DTC

DTC可以管理任何跨越执行边界的事务,跨AppDomain,跨进程,跨机器,跨服务。DTC可以使用OleTx 或者WSAT事务协议。

DTC既可以管理本地事务,更重要的是它能够管理跨边界的服务。

在使用WCF的场景下,每台运行WCF服务的机器都默认使用DTCDTC建立一个新事务,并跨机器把事务传播到其他机器,发起事务的机器上的事务为根事务,这个机器上的DTC就要负责这个分布式事务的协调任务,负责启动事务,提交事务,和回滚事务。

事务管理器可使用的事务协议:

Protocal

LTM

KTM

DTC

Lightweight protocol

Yes

Yes

No

OleTx protocol

No

No

Yes

WS-Atomic Transaction

No

No

Yes

3、 事务资源

在事务范围内,可纳入事务管理的资源,即可以在事务正常执行后提交生效,在事务失败可以回滚恢复到事务启动前状态的资源成为事务资源。最常见的事务资源就是常用的数据库操作。但是在vista开始引入了两个核心事务资源:TxF事务文件和TxR事务注册表。

可用的事务资源:

3.1. sql server事务资源

Sql 2005sql 2008的事务资源是新sql serverLTM事务管理器可以管理这类事务。

3.2. 核心事务资源

Vista开始引入的TxF事务文件和TxR事务注册表。可以对文件和注册表进行事务性操作。KTM可以管理这类资源。

3.3. 传统事务资源

SQL Server 2000, Oracle, DB2, MSMQ这类资源是传统的事务资源,这些资源只能由DTC事务管理器进行管理。

事务管理器可管理的事务资源:

Resource

LTM

KTM

DTC

Sql Server事务资源

Yes

No

Yes

核心事务资源

No

Yes

Yes

传统事务资源

No

No

Yes

4、 事务管理器的升级

每个WCF中启动的事务都是先由LTM事务管理器管理,一旦事务中出现现有事务管理器无法管理的资源或情况,WCF会提升事务管理器的级别。分别从LTM升级到KTM,最高级别升级到DTC。事务管理器可以多次升级,事务管理器一旦升级后不能降级。

事务管理器的升级规则:

image

posted @ 2012-03-30 00:20 paulwong 阅读(1550) | 评论 (0)编辑 收藏

开始Spring MVC

建立一个web project,并导入spring 3.x的jar包配置web.xml根据上面的spring mvc流程图,我们知道DispatcherServlet是spring mvc 的一个前端控制器,所以我们当然要去配置它,以便于将请求转给DispatcherServlet处理

  <servlet>
    
<servlet-name>dispatcher</servlet-name>
    
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    
<init-param>
        
<param-name>contextConfigLocation</param-name>
<!-- 如果配置文件位于classpath下,可以这么写: classpath:dispatcher.xml -->
        
<param-value>/WEB-INF/dispatcher.xml</param-value>
    
</init-param>
    
<load-on-startup>1</load-on-startup>
  
</servlet>

  
<servlet-mapping>
    
<servlet-name>dispatcher</servlet-name>
    
<url-pattern>/</url-pattern>
  
</servlet-mapping>

注:由于DispatcherServlet在初始化的过程中需要一个配置文件来生产文件中的各种bean,并生成WebApplicationContext对象,保存到ServletContext中(如果DispatcherServlet有多个,那么每一个DispatcherServlet都对应一个WebApplicationContext),我们可以在Servlet的init-param中配置配置文件的路径,当然如果我们没有配置Init-Param,它会默认到WEB-INF的文件夹中找[servletname]-servlet.xml文件,例如上面如果我们没有配置,则会去寻找dispatcher-servlet.xml这个配置文件。(在init-param中我们可以指定多个配置文件,用逗号分隔也可以使用通配符*)
配置上文中我们指定的所需的dispatcher.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context
="http://www.springframework.org/schema/context"
xmlns:mvc
="http://www.springframework.org/schema/mvc"
xsi:schemaLocation
="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"
>

    
<context:component-scan base-package="com.controls" />
    
<mvc:annotation-driven />
    
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
       
<property name="prefix" value="/WEB-INF/views/"></property>
       
<property name="suffix" value=".jsp"></property>
       
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
    
</bean>
</beans>



配置文件说明:
<context:component-scan base-package="com.controls" />
由于我们使用了基于注解的Controller,所以这里指定了需要被扫描的包路径,如果有多个可以使用逗号分隔
<mvc:annotation-driven />

上面的spring mvc流程图中我们知道DispatcherServlet接管请求后,会由HandlerMapping来执行映射,所以我们需要注册HanlderMapping,比如上面的标签会自动注册比如DefaultAnnotationHandlerMapping(执行请求到Controller的映射)和AnnotationMethodHandlerAdapter(调用controller中的方法)这样的bean,当然这个标签还提供了其他的一些支持(更多介绍请参照spring官方文档第455页)。

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

       
<property name="prefix" value="/WEB-INF/views/"></property>

       
<property name="suffix" value=".jsp"></property>

       
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>

</bean>

上面spring mvc流程图的最后controller处理完毕后会交给一个ViewResolver进行处理,大体上是解析视图逻辑名并经过一定的处理获取一个视图,这里的意思是设置视图用jsp来处理(比如我们设置viewClass为JstlView)来进行处理,就是以forward的形式转发给jsp,这个地址是:/WEB-INF/views/[controller返回值].jsp ,当然视图解析器可以定义多个,(视图解析器不会处理ModelAndView中已经设置了View的请求,因为已经有View来处理了,那当然就不需要它来解析到真正的视图View啦)
编写Controller控制器这里我们使用例子的形式来说明

实现一个控制器类@Controller
@Controller
@RequestMapping(
"/user")
public class UserControl {

}

只要给类加上Controller的注解,并放在被扫描的包中,那么这个类就是一个控制器了,RequestMapping表明匹配的路径,可以写在类或者类的方法上,如果类上面有RequestMapping注解,那么其下面的方法就是相对于类上面注解地址的一个相对路径


定义一个接管请求的方法方法名:无任何要求
--------------------------------------------------------------
参数:(顺序以及个数无任何要求)
HttpServletRequest
HttpServletResponse
PrintWriter 相当于HttpResponse.getWriter()获得的对象
Map 其实是获得了ModelAndView中的Model
BindingResult 绑定数据的处理结果
HttpSession 如果使用此参数,需要注意如果是第一次访问还没有session的话会报错
@PathVariable 用于接收路径变量
@RequestParam 相当于调用request.getParameter(“name”)方法
@CookieValue 获取cookie的值
@RequestHeader 获取header中的值
实体对象 会根据请求的参数名,注入到这个对象对于得属性中,必须提供set方法
等等等等等
--------------------------------------------------------------
返回值:
void
返回值是void,如果接收了PrintWriter 或者 HttpServletResponse 参数,那么返回的ModelAndView就是null,也就是直接将输出流输出到客户端,如果方法没有接收输出参数,后面会默认生成一个视图名

String 视图逻辑名

ModelAndView 是一个视图逻辑名+Map的封装类
其他任意类型 存入ModelAndView中的Model
--------------------------------------------------------------

不管我们的返回类型是什么,返回值会通过处理,最终返回一个ModelAndView或者null
例1:给方法定义一个请求映射并使用路径变量 @RequestMapping("/id/{userid}/name/{username}")

@RequestMapping("/id/{userid}/name/{username}")
public String queryUser(@PathVariable("userid"long userID, @PathVariable("username") String userName, Map<String, User> model) {
       User user 
= new User();
       user.setUserID(userID);
       user.setUserName(userName);
       model.put(
"userInfo", user);
       
return "Home";
    }


@RequestMapping定义路由映射,其中{userid} {username} 是PathVariable(路径变量)
这样我们只需访问 http://localhost:8080/SpringMVC/user/id/10001/name/liudehua 就能进入上面的方法
RequestMapping还可以使用通配符,如: /test/*/name/{name}

例2:接受请求参数@RequestMapping("/save")
@RequestMapping("/save")
public String save(@RequestParam("userName") String userName,@RequestParam("Age"int age) {
       System.out.println(userName);
       System.out.println(age);
       
return "Home";
}


例3:请求参数直接注入到Model@RequestMapping("/save")
@RequestMapping("/save")
public String save(User user) {
       System.out.println(user.getUserID());
       System.out.println(user.getUserName());
       
return "Home";
}

例4:转发与重定向转发: (相当于 request.getRequestDispatcher(“”).forward(request, response))
return “forward:/user/test”;

重定向: (相当于response.redirect(“”))
return “redirect:/user/test”
return “redirect:http://www.google.com.hk”;

例5:根据HttpMethod来过滤请求
@RequestMapping(params="hello=world", method={RequestMethod.GET, RequestMethod.POST}
public String helloworld() {
}
 


例6:根据参数来进行过滤
@RequestMapping(params="hello=world", method={RequestMethod.GET, RequestMethod.POST})  
public String helloworld() {
}
  

必须有个hello的参数并且名称为world,而且只能是get或post请求才会进入此方法

http://www.cnblogs.com/zhaoyang/archive/2012/01/07/2315425.html

posted @ 2012-03-29 19:06 paulwong 阅读(1148) | 评论 (0)编辑 收藏

Joda-Time 简介

假设我希望输出这样一个日期:距离 Y2K 45 天之后的某天在下一个月的当前周的最后一天的日期。坦白地说,我甚至不想使用 Calendar 处理这个问题。使用 JDK 实在太痛苦了,即使是简单的日期计算,比如上面这个计算。正是多年前的这样一个时刻,我第一次领略到 Joda-Time 的强大。使用 Joda,用于计算的代码如清单 3 所示:

DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0, 0);
System.out.println(dateTime.plusDays(
45).plusMonths(1).dayOfWeek() .withMaximumValue().toString("E MM/dd/yyyy HH:mm:ss.SSS");

详见:
http://www.oschina.net/question/12_7643

posted @ 2012-03-27 17:09 paulwong 阅读(289) | 评论 (0)编辑 收藏

业务建模一般步骤和方法

转载自:http://hi.baidu.com/parryblog/blog/item/2d1ae59a72b043bcc9eaf4a0.html

本篇开始之前先扯点闲话,商业应用系统开发经历了三个阶段:
  第一个阶段以计算为中心,分析设计围绕程序的运行效率,算法优劣,存贮优化来进行。90年代的大学课程讲的都是这些。

  第二阶段以数据为中心,分析设计围绕数据流进行,以数据流程来模拟业务流程。这也就是所谓的面向过程的分析模式。

  第三阶段以人为中心,分析设计围绕人的业务需求,使用要求,感受要求进行。这也就是现在的面象对象分析模式。

  使用OO方法建立商业模型必须先定义涉众。商业系统无论多复杂,无论什么行业,其本质无非是人,事,物,规则。人是一切的中心,人做事,做事产生物,规则限制人事物。人驱动系统,事体现过程,物记录结果,规则则是控制。无论OO也好,UML也好,复杂的表面下其实只是一个简单的规则,系统分析员弄明白有什么人,什么人做什么事,什么事产生什么物,中间有什么规则,再把人,事,物之间的关系定义出来,商业建模也就基本完成了。这时候可以说,系统分析员已经完全了解了用户需求,可以进入系统建模阶段了。

  书归正传,上篇笔者归纳了一些典型的涉众类型及他们的普遍期望。接下来,就是要将他们这些期望定义出来。这个过程,就是业务用例获取的过程。笔者可以跟大家分享的经验是通过以下步骤进行,这些步骤并非唯一正确,对于经验不多的系统分析员来说,这些步骤很有指导意义。

  笔者做了一个建模实例,有需要有读者请到笔者的BLOG资源中心下载,实例以上一篇所述网上图书馆需求为蓝本建立了业务用例模型,之后的概念模型、系统模型则抽取了其中的借阅过程作为例子。不记得了可以后头找找。

  建模第一步,从涉众中找出用户。并定义这些用户之间的关系。在ROSE中,应该使用business actor 类型。参考上一篇的需求描述,下载实例

  第二步,找出每个用户要做的事,即业务用例,在ROSE中应使用Business use case类型。请参考《用例的类型与粒度》一文以帮助确定用例的粒度。笔者强烈建议为每一个business actor绘制一个业务用例图,这能很好的体现以人为中心的分析模式,并且不容易漏掉business actor需要做的事。至于以参与者为中心的视图容易漏掉某个业务用例的参与者的担心,可以在第四步中得到消除。下载实例

  第三步,利用业务场景图帮助分析业务流程,在ROSE中,这个阶段最好使用活动图Activity diagram。在这个阶段,业务场景图非常重要,在绘制过程中,系统分析员必须采用第一步中定义的用户名字作为泳道名,使用第二步中定义的业务用例名作为活动名来绘制。必须这么做的原因是,如果你无法把利用已经定义出来的 business actor 和 business use case完备的描绘业务流程,那么一定是前面的定义出问题了,你需要回头审视是否 business actor 和 business use case定义不完善或错误。如果不是所有的business actor 和 business use case 都被用到,要么应该检查业务流程调研时漏了什么,要么应该检查是否定义了一些无用的business actor 和 business use case 。同时,绘制业务场景图也非常有助于选择合适的用例粒度并保持所有的用例都是同一粒度。下载实例

  第四步,绘制用例场景图。与业务场景图不同的是,用例场景图只针对一个用例绘制该用例的执行过程。笔者仍然强烈推荐使用activity diagram。在用例场景图的绘制中,必须使用第一步中定义的业务用户作为泳道。必须这么做的原因是,它能帮助你发现在定义业务用例图时的错误,比如是否漏掉了某个业务用例的潜在使用者。不是每个业务用例都需要绘制场景图,只有两三个步骤的业务用例是不必一定绘制业务用例图的,但仍然需要在业务用例规约文档中写明。下载实例

第五步,从第三步或第四步中绘制的活动图中找到每一步活动将使用到的或产生的结果。这是找到物的过程。找到后,应当建立这些物之间的关系。在ROSE中,这称为业务实体模型。应该使用business entity 类型。下载实例

  第六步,在上述过程中,随时补充词汇表Glossary。将此过程中的所有业务词汇,专业词汇等一切在建模过程中使用到的需要解释的名词。这份文档将成为模型建立人与读者就模型达成一致理解的重要保证。

  第七步,根据上一篇中提到的业主,老板等涉众的期望审视建立好的模型,确定业务范围,决定哪些业务用例在系统建设范围内。那些不打算纳入建设范围内的业务用例有两种情况,一种是该业务用例是被调用一方,那么应该把它改为 boundary 类型,意味着将来它是一个外部接口。另一种是该业务用例主动调用系统内业务用例,那么应该将它改为business actor类型。与普通business actor不同的是,由业务用例转换而成的business actor不是人,而通常是一个外部系统进程,因此应该在被调用的系统内业务用例与它之间增加一个boundary元素,意味着我们的系统将为这样一个外部进程提供一个接口。严格来说,那些需要纳入建设范围的business use case 应当对应的生成一个 business use case realization, 以后的设计工作将归纳到这些实现用例中。但笔者觉得这一步并非很关键的,实际中本人也经常省略这一步,而将协作图,象活动图,类交互图等直接在business usecase下说明。不过本实例中笔者还是按照正规方法来建模的。下载实例

  需要说明的是,上述的步骤并非一次性完成的,在每一个步骤中都可能导致对以前步骤的调整。即使建模已经完成,当遇到变化或发现新问题时,上述步骤应当从头到尾再执行一次。这也是RUP倡导的迭代开发模式。

经过以上的步骤,我们已经建立了一个完整的业务模型。但这决不是建模工作的全部,以上过程只说明了建立一个完整业务模型的过程,不能说这样就建立了一个很好的业务模型。因为上述的过程中并没有提及业务分析过程。分析过程全凭系统分析员的经验,对OO的理解和对行业业务的把握能力,对原始业务模型进行归纳,整理,抽象,重构,以建立一个更高效,合理,扩展性更强的模型。这个过程无法以步骤说明。或许以后笔者会专门针对模型分析写点东西。另外除了模型,还至少需要写业务架构文档、用例规约和补充用例规约三种文档。因为模型虽然可以较好的体现业务架构,但很不好表达业务规则和非业务需求,这些需要在文档中说明。例如用例的前置条件和后置条件就是一种业务规则。读者可以在RUP文档中找到这些文档的模板。
 
http://hi.baidu.com/parryblog/blog/category/%CF%B5%CD%B3%B7%D6%CE%F6
http://hi.baidu.com/parryblog/blog/category/%D0%E8%C7%F3%B7%D6%CE%F6


posted @ 2012-03-26 00:26 paulwong 阅读(623) | 评论 (0)编辑 收藏

Spring MVC 的请求参数获取的几种方法

通过@PathVariabl注解获取路径中传递参数

JAVA
 @RequestMapping(value = "/{id}/{str}")
 
public ModelAndView helloWorld(@PathVariable String id, @PathVariable String str) {
 System.out.println(id);
 System.out.println(str);
 
return new ModelAndView("/helloWorld");
}


用@ModelAttribute注解获取POST请求的FORM表单数据
JSP
<form method="post" action="hao.do">
 a: 
<input id="a" type="text" name="a"/>
 b: 
<input id="b" type="text" name="b"/>
 
<input type="submit" value="Submit" />
</form>


JAVA pojo
 public class Pojo{
 
private String a;
 
private int b;
}


JAVA controller
@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pojo") Pojo pojo) {
 
return "helloWorld";
 }


直接用HttpServletRequest获取
JAVA
@RequestMapping(method = RequestMethod.GET)
public String get(HttpServletRequest request, HttpServletResponse response) {
 System.out.println(request.getParameter(
"a"));
 
return "helloWorld";
}


用注解@RequestParam绑定请求参数a到变量a
当请求参数a不存在时会有异常发生,可以通过设置属性required=false解决,
例如: @RequestParam(value="a", required=false)
JAVA
@RequestMapping(value = "/requestParam", method = RequestMethod.GET)
public String setupForm(@RequestParam("a") String a, ModelMap model) {
 System.out.println(a);
return "helloWorld";}

posted @ 2012-03-23 17:36 paulwong 阅读(51116) | 评论 (2)编辑 收藏

HOST文件安装器

http://sourceforge.net/projects/huhamhirehosts/files/

posted @ 2012-03-21 00:48 paulwong 阅读(195) | 评论 (0)编辑 收藏

Java容器类Collection、List、ArrayList、Vector及map、HashTable、HashMap区别

Collection是List和Set两个接口的基接口
List在Collection之上增加了"有序"
Set在Collection之上增加了"唯一"

而ArrayList是实现List的类...所以他是有序的.
它里边存放的元素在排列上存在一定的先后顺序

而且ArrayList是采用数组存放元素
另一种List LinkedList采用的则是链表。

Collection和Map接口之间的主要区别在于:Collection中存储了一组对象,而Map存储关键字/值对。
在Map对象中,每一个关键字最多有一个关联的值。
Map:不能包括两个相同的键,一个键最多能绑定一个值。null可以作为键,这样的键只有一个;可以有一个或多个键所对应的
值为null。当get()方法返回null值时,即可以表示Map中没有该键,也可以表示该键所对应的值为null。因此,在Map中不能由get()方法来判断Map中是否存在某个键,而应该用containsKey()方法来判断。
继承Map的类有:HashMap,HashTable
HashMap:Map的实现类,缺省情况下是非同步的,可以通过Map Collections.synchronizedMap(Map m)来达到线程同步
HashTable:Dictionary的子类,缺省是线程同步的。不允许关键字或值为null

当元素的顺序很重要时选用TreeMap,当元素不必以特定的顺序进行存储时,使用HashMap。Hashtable的使用不被推荐,因为HashMap提供了所有类似的功能,并且速度更快。当你需要在多线程环境下使用时,HashMap也可以转换为同步的。

为什么要使用集合类
当你事先不知道要存放数据的个数,或者你需要一种比数组下标存取机制更灵活的方法时,你就需要用到集合类。

理解集合类
集合类存放于java.util包中。
集合类存放的都是对象的引用,而非对象本身,出于表达上的便利,我们称集合中的对象就是指集合中对象的引用(reference)。
集合类型主要有3种:set(集)、list(列表)和map(映射)。

(1)集 (Set):口袋
集(set)是最简单的一种集合,它的对象不按特定方式排序,只是简单的把对象加入集合中,就像往口袋里放东西。
对集中成员的访问和操作是通过集中对象的引用进行的,所以集中不能有重复对象。
集也有多种变体,可以实现排序等功能,如TreeSet,它把对象添加到集中的操作将变为按照某种比较规则将其插入到有序的对象序列中。它实现的是SortedSet接口,也就是加入了对象比较的方法。通过对集中的对象迭代,我们可以得到一个升序的对象集合。

(2)列表 (List):列表
列表的主要特征是其对象以线性方式存储,没有特定顺序,只有一个开头和一个结尾,当然,它与根本没有顺序的集是不同的。
列表在数据结构中分别表现为:数组和向量、链表、堆栈、队列。
关于实现列表的集合类,是我们日常工作中经常用到的,将在后边的笔记详细介绍。

(3)映射 (Map):键值对
映射与集或列表有明显区别,映射中每个项都是成对的。映射中存储的每个对象都有一个相关的关键字(Key)对象,关键字决定了对象在映射中的存储位置,检索对象时必须提供相应的关键字,就像在字典中查单词一样。关键字应该是唯一的。
关键字本身并不能决定对象的存储位置,它需要对过一种散列(hashing)技术来处理,产生一个被称作散列码(hash code)的整数值,散列码通常用作一个偏置量,该偏置量是相对于分配给映射的内存区域起始位置的,由此确定关键字/对象对的存储位置。理想情况下,散列处理应该产生给定范围内均匀分布的值,而且每个关键字应得到不同的散列码。

集合类简介
java.util中共有13个类可用于管理集合对象,它们支持集、列表或映射等集合,以下是这些类的简单介绍

集:
HashSet: 使用HashMap的一个集的实现。虽然集定义成无序,但必须存在某种方法能相当高效地找到一个对象。使用一个HashMap对象实现集的存储和检索操作是在固定时间内实现的.
TreeSet: 在集中以升序对对象排序的集的实现。这意味着从一个TreeSet对象获得第一个迭代器将按升序提供对象。TreeSet类使用了一个TreeMap.
列表:
Vector: 实现一个类似数组一样的表,自动增加容量来容纳你所需的元素。使用下标存储和检索对象就象在一个标准的数组中一样。你也可以用一个迭代器从一个Vector中检索对象。Vector是唯一的同步容器类??当两个或多个线程同时访问时也是性能良好的。(同步的含义:即同时只能一个进程访问,其他等待)
Stack: 这个类从Vector派生而来,并且增加了方法实现栈??一种后进先出的存储结构。
LinkedList: 实现一个链表。由这个类定义的链表也可以像栈或队列一样被使用。
ArrayList: 实现一个数组,它的规模可变并且能像链表一样被访问。它提供的功能类似Vector类但不同步。
映射:
HashTable: 实现一个映象,所有的键必须非空。为了能高效的工作,定义键的类必须实现hashcode()方法和equal()方法。这个类是前面java实现的一个继承,并且通常能在实现映象的其他类中更好的使用。
HashMap: 实现一个映象,允许存储空对象,而且允许键是空(由于键必须是唯一的,当然只能有一个)。
WeakHashMap: 实现这样一个映象:通常如果一个键对一个对象而言不再被引用,键/对象对将被舍弃。这与HashMap形成对照,映象中的键维持键/对象对的生命周期,尽管使用映象的程序不再有对键的引用,并且因此不能检索对象。
TreeMap: 实现这样一个映象,对象是按键升序排列的。

下图是集合类所实现的接口之间的关系:
Set和List都是由公共接口Collection扩展而来,所以它们都可以使用一个类型为Collection的变量来引用。这就意味着任何列表或集构成的集合都可以用这种方式引用,只有映射类除外(但也不是完全排除在外,因为可以从映射获得一个列表。)所以说,把一个列表或集传递给方法的标准途径是使用Collection类型的参数。

List接口
List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。
和下面要提到的Set不同,List允许有相同的元素。
除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。
实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。
ArrayList类
ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步。
size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。
每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。ArrayList当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。
和LinkedList一样,ArrayList也是非同步的(unsynchronized)。
Map接口
请注意,Map没有继承Collection接口,Map提供key到value的映射。一个Map中不能包含相同的key,每个key只能映射一个value。Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。
HashMap类
HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key。,但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。
----------------------------------------------------------------------------
1.-------------------->
List是接口,List特性就是有序,会确保以一定的顺序保存元素.
ArrayList是它的实现类,是一个用数组实现的List.
Map是接口,Map特性就是根据一个对象查找对象.
HashMap是它的实现类,HashMap用hash表实现的Map,就是利用对象的hashcode(hashcode()是Object的方法)进行快速(Hash)散列查找.(关于散列查找,可以参看<<数据结构>>)
2.-------------------->
一般情况下,如果没有必要,推荐代码只同List,Map接口打交道.
比如:List list = new ArrayList();
这样做的原因是list就相当于是一个泛型的实现,如果想改变list的类型,只需要:
List list = new LinkedList();//LinkedList也是List的实现类,也是ArrayList的兄弟类
这样,就不需要修改其它代码,这就是接口编程的优雅之处.
另外的例子就是,在类的方法中,如下声明:
private void doMyAction(List list){}
这样这个方法能处理所有实现了List接口的类,一定程度上实现了泛型函数.
3.--------------------->
如果开发的时候觉得ArrayList,HashMap的性能不能满足你的需要,可以通过实现List,Map(或者Collection)来定制你的自定义类

posted @ 2012-03-20 21:40 paulwong 阅读(1430) | 评论 (0)编辑 收藏

业务系统与工作流系统

通常工作流系统是独立的一个系统,必须以业务系统和工作流系统的观点才能比较好的理解业务系统。工作流系统负责节点的流转,即状态的改变。

  1. 业务系统如果增加一个业务对象,须增加一堆的服务方法,工作流系统面向的是流程,增加流程无需增加代码,因此启动流程的第一步,就要业务系统告诉工作流系统要管理哪个流程,即流程ID,然后工作流系统就记录下此流程实例
  2. 工作流系统面向的是流程配置文件,即bpmn20.xml,用TASK表示业务系统中的步骤,如果这一节点为USER TASK,则表示工作流系统会等待业务系统的触发而改变状态,业务系统会向客户端展示页面,收集信息并验证通过后才让工作流系统改变流程实例的状态;如果是自动任务,则工作流系统会自行改变状态,流转到下一节点。
  3. 由于处理USER TASK时,需业务系统自行判断,因此新增业务对象(表单)时,需新增业务代码,有别于OA系统,新增表单时,不用新增代码。
  4. USER TASK中允许配有页面展示的链接,业务系统可以从这里取得链接而返回给客户端。静态网页处理时,只需向客户端传实体HTML文件,由客户端解释成文本内容,动态网页实际上由服务器端生成文本内容再发给客户端。

posted @ 2012-03-20 10:26 paulwong 阅读(436) | 评论 (0)编辑 收藏

仅列出标题
共110页: First 上一页 80 81 82 83 84 85 86 87 88 下一页 Last