paulwong

#

分布式事务

一、 事务概述

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 阅读(1570) | 评论 (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 阅读(1178) | 评论 (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 阅读(301) | 评论 (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 阅读(686) | 评论 (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 阅读(51250) | 评论 (2)编辑 收藏

HOST文件安装器

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

posted @ 2012-03-21 00:48 paulwong 阅读(211) | 评论 (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 阅读(1453) | 评论 (0)编辑 收藏

业务系统与工作流系统

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

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

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

基于注解的SpringMVC+freemarker环境搭建

  1. 首先用IDE建一个web工程。(这个就不详细介绍了)
  2. 引入响应的jar包
  3. web.xml
    <?xml version="1.0" ?>
    <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation
    ="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        version
    ="3.0">
        
    <!--  Spring 服务层的配置文件 -->
        
    <context-param>
            
    <param-name>contextConfigLocation</param-name>
            
    <param-value>classpath:applicationContext.xml</param-value>
        
    </context-param>
        
        
    <!--  Spring 容器启动监听器 -->
        
    <listener>
            
    <listener-class>org.springframework.web.context.ContextLoaderListener
            
    </listener-class>
        
    </listener>

        
    <servlet>
            
    <servlet-name>springmvc</servlet-name>
            
    <servlet-class>org.springframework.web.servlet.DispatcherServlet
            
    </servlet-class>
            
    <load-on-startup>1</load-on-startup>
        
    </servlet>
        
    <!--为DispatcherServlet建立映射 -->
        
    <servlet-mapping>
            
    <servlet-name>springmvc</servlet-name>
            
    <url-pattern>/</url-pattern>
        
    </servlet-mapping>
    </web-app>

  4. SpringMVC另外一个重要的配置文件。
    DispatcherServlet会根绝web.xml中配置的<servlet-name>去找<servlet-name>-servlet.xml的文件来加载spring的一些配置信息。我这里就应该取名叫springmvc-servlet.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"
        xsi:schemaLocation
    ="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-2.5.xsd"
    >
        
        
    <!--对web包中的所有类进行扫描,以完成Bean创建和自动依赖注入的功能 -->
        
    <context:component-scan base-package="com.liba.spring.mvc"/>
        
        
    <!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射   请求映射-->
        
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
        
            
    <!--以下三种视图配置根据需要任选一种即可 -->

        
    <!--  一般的视图配置 -->
        
    <!--<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
            p:prefix="/WEB-INF/view/" p:suffix=".jsp"/>
    -->
        
        
    <!-- 针对freemarker的视图配置 -->
        
    <bean id="viewResolver"
            class
    ="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
            
    <property name="cache" value="true" />
            
    <property name="prefix" value="" />
            
    <property name="suffix" value=".ftl" />
            
    <property name="contentType" value="text/html;charset=UTF-8"></property>
            
    <property name="requestContextAttribute" value="request" />
            
    <property name="exposeSpringMacroHelpers" value="true" />
            
    <property name="exposeRequestAttributes" value="true" />
            
    <property name="exposeSessionAttributes" value="true" />
        
    </bean>
            
            
        
    <!-- View resolvers can also be configured with ResourceBundles or XML files. 
            If you need different view resolving based on Locale, you have to use the 
            resource bundle resolver. 
    -->
        
    <!-- 这个是针对返回视图还是json值的视图配置   来分别处理同步和异步请求 -->
        
    <!--<bean
                class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
                <property name="mediaTypes">
                    <map>
                        <entry key="html" value="text/html" />
                        <entry key="json" value="application/json" />
                    </map>
                </property>
                <property name="favorParameter" value="true" />
                <property name="viewResolvers">
                    <list>
                        <bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
                        <bean id="viewResolver"
                            class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
                            <property name="cache" value="true" />
                            <property name="prefix" value="" />
                            <property name="suffix" value=".ftl" />
                            <property name="contentType" value="text/html;charset=UTF-8"></property>
                            <property name="requestContextAttribute" value="request" />
                            <property name="exposeSpringMacroHelpers" value="true" />
                            <property name="exposeRequestAttributes" value="true" />
                            <property name="exposeSessionAttributes" value="true" />
                        </bean>
                    </list>
                </property>
                <property name="defaultContentType" value="text/html" />
            </bean>
            
    -->
    </beans>

  5. 如果是使用freemarker最为视图模板需要再spring的配置文件applicationContext.xml中加入以下配置
    <bean id="freemarkerConfig"
            class
    ="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
            
    <property name="templateLoaderPath" value="/WEB-INF/view/" />
            
    <property name="freemarkerSettings">
                
    <props>
                    
    <prop key="template_update_delay">0</prop>
                    
    <prop key="default_encoding">UTF-8</prop>
                    
    <prop key="number_format">0.##########</prop>
                    
    <prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
                    
    <prop key="classic_compatible">true</prop>
                    
    <prop key="template_exception_handler">ignore</prop>
                
    </props>
            
    </property>
        
    </bean>

  6. Controller建立
    import javax.servlet.http.HttpServletRequest;

    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.servlet.ModelAndView;

    @Controller
    public class SpringMvcController {

        @RequestMapping(value
    ="/welcome",method={RequestMethod.GET}
        
    public ModelAndView getFirstPage(HttpServletRequest request) {
                    
    //welcom就是视图的名称(welcom.ftl)
            ModelAndView mv = new ModelAndView("welcom");
            mv.addObject(
    "name""My First Spring Mvc");
            
    return mv;
        }

    }
    在url上敲http://localhost:8080/welcome就会到WEB-INF/view/welcom.ftl页面渲染数据
  7. welcom.ftl页面
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <title>Insert title here</title>
    </head>
    <body>
    Hello ${name}
    </body>
    </html>

    页面出来的效果:

    Hello My First Spring Mvc








posted @ 2012-03-19 21:32 paulwong 阅读(25911) | 评论 (3)编辑 收藏

架构师的素质

架构师最基本的素质,总结出两点,1是技术知识广度,2是业务行业深度。


1 架构师是技术领导。
架构师必须要有技术,而且还是领导。架构师要带领自己团队完成自己的任务,完全凭借自己的能力做事情,完全是匹夫之勇,根本不提倡。

2 架构师理解软件流程。
架构师必须了解软件流程,否则无法驱动整个团队前进,如果一个架构师不熟悉开发流程,无法协调产品线相关人员进行高效工作,也无法指导团队成员完成自己的工作。所以来说架构师一般不是空降兵(除非是全新的部门),因为空降兵一般不会熟悉新公司的开发流程,即使是同一个行业的,各个公司的差别还是很大。所以说听说某某去某某公司做首席架构师或者首席科学家,一般是高风险的事情,即使他对这个行业很了解。

3 架构师必须熟悉业务领域。
如果一个架构师不熟悉自己的行业,做的架构就是纸上谈兵,熟悉业务领域的架构师,才能很好的理解需求,做出合适的方案。互联网和网络安全是完全不同的两个方向,即使你熟悉里面的各种具体技术,但是以互联网的架构来做网络安全产品,肯定是100%的失败。
我做PKI的时候,项目最初的使用.net,使用微软的crytoAPI,开发的很顺利。后来来了一位新的架构师,觉得.net不能跨平台,决定?用java,做出产品后,发现找不到arm cpu的jdk,使用平台有限。再次决定使用openssl做,最后这个项目以失败而告终。后来我想过arm cpu都是嵌入式设备用的,根本没有任何嵌入式设备提供CA服务。

4 架构师必须要有广度的知识。
架构师考虑的问题必须全面,必须了解的要广,具体的细节可以不关注,因为细节变化很快。很多具体技术人员出身的架构师,只关注于具体的细节,某些方面做的很好,整体的性能很差。
下面这个项目的成功可以理解为一个笑话。某公司的两个部门都做c程序的,A部门做的平台使用的x86和mips,B部门使用平台是x86和 arm,后来A部门的一个模块要给B部门用,最后发现根本不能运行。最后A部门发现arm平台使用big endian模式,这样A部门的20多名员工,检查代码中所有非零整数,经过数个月苦战,才修改完毕。其实解决方法很简单,因B部门的代码也是首先在 x86做的,做的时候他们考虑了cpu的endian模式。这并不能说B部门架构师很牛,从另一个方面说他的无知。因为板子有跳线,专门切换cpu的是 big endian还是little endian,这样两个部门都可以不修改程序。

5 架构师必须是写程序的高手。
架构师一般都是?发人员出身,一般都是团队的核心。优秀的架构师应该了解团队使用各种技术,有了这些知识,才能和开发人软进行有效沟通。
有一个项目架构使用xml做配置,因为病毒库很庞大,最后导致xml 达30多兆,服务端的java程序使用dom 进行过滤的时候,30兆xml加载很慢,频繁出现out of memory。这个项目后来搁浅。根据以前的经验发现 msxml加载30多M的xml 不过几秒,而且msxml的xpath速度很快,后来专门为此写了JNI处理xml的。

6架构师是优秀的沟通人员。
架构师一定要会忽悠,至少要扯淡。架构师不但要指导本部门员工的工作,也要协调其他部门的资源,还要向用户收集需求,制定规格说明书,重要的把用户的不合理要求砍掉,合理需求遵循自己的思路

posted @ 2012-03-19 02:21 paulwong 阅读(303) | 评论 (0)编辑 收藏

仅列出标题
共116页: First 上一页 86 87 88 89 90 91 92 93 94 下一页 Last