zyskm用梦想丈量人生,用奔跑丈量激情

2011年10月24日 #

分布式模式之Broker模式

转发 http://blog.chinaunix.net/uid-23093301-id-90459.html 问题来源: 创建一个游戏系统,其将运行在互联网的环境中。客户端通过WWW服务或特定的客户端软件连接到游戏服务器,随着流量的增加,系统不断的膨胀,最终后台数据、业务逻辑被分布式的部署。然而相比中心化的系统,复杂度被无可避免的增大了,该如何降低各个组件之间的耦合度。 挑战: 需要保证可伸缩性、可维护性、可更新性,需要将服务划分为各个相对独立的组件,组件被分布式的部署,它们之间通过进程间通信方式实现交互。服务的增加、删除、改变都应该被支持。理想情况,以开发者的角度看,集中化的系统和分布式的系统在中心逻辑上没有什么不同。为实现这个目标: l 可以远程的访问服务,而对于访问者,服务的位置应该是透明的。 l 提供服务的组件可以增加、删除、改变,而且这些在运行期同样应该被支持。 l 访问服务的客户端不应该关心服务的实现细节。 解决方案: 引入一个Broker组件,解耦客户端和服务端。服务端注册自己到Broker,通过暴露接口的方式允许客户端接入服务。客户端是通过Broker发送请求的,Broker转发请求道服务端,并将请求的结果或异常回发给客户端。通过使用Broker模式,应用可以通过发送消息访问远程的服务。 这一架构模式允许动态的改变、添加、删除服务端,从客户端的角度,这些都是透明的。 结构: Broker模式定义了6中类:Client,Server,Client_Proxy,Server_Proxy,Broker,Bridge。 Server: l 责任:处理特定领域的问题,实现服务的细节,注册自己到Broker,处理请求并返回结果或异常。 l 协作类:Server_Proxy,Broker Client: Client是需要访问远程服务的应用程序,为此,Client发送请求到Broker,并从Broker上接收响应或异常。Client和Server只是逻辑上相关而已,实际上Client并不知道Server的确切位置。 l 责任:1. 实现用户端功能,2. 发送请求到Broker,3. 接收相应和异常。 l 协作类:Broker,Client_Proxy Broker: Broker可以被看成消息转发器。Broker也负责一些控制和管理操作。它能够定位服务端的位置,若发生异常,能够将异常捕获传给Client。Broker需要提供注册服务的接口给Server。如果请求来自其他的Broker,本地的Broker需要转发请求并最终将结果或异常回应给相应的远程Broker。Broker提供的服务和name service非常相像(如DNS、LDAP)。 l 责任:1. 注册服务。2. 提供服务API。3. 转发消息。4. 容错处理。5. 与其他Broker的交互。6。 定位服务。 l 协作类:Client_Proxy,Server_Proxy,Bridge Client_Proxy: 连系Client和Broker,这一层保证了通讯的透明性,使Client调用远程服务就像调用本地的服务一样。 l 责任:1. 封装特定的系统调用。2. 封装通讯的参数、控制信息等。 l 协作类:Client,Broker。 Server_Proxy: Server_proxy是与Client_Proxy相对应的,它接受请求,解包消息,解析出参数并调用服务的实现接口。 l 责任:1. 封装特定的系统调用。2. 封装通讯的参数、控制信息等。3. 调用server的服务接口。 l 协作类:Server,Broker。 Bridge: Bridge用来连接各个Broker,一般这个组件是可选的。当系统是发杂的网络组成时,有可能需要这一角色。 l 责任:1. 封装特定的网络特性。2. 传递Broker之间的通讯。 l 协作类:Broker。 应用场景一: 直接通讯方式。Client和Server相互理解他们之间的通讯协议。Broker主要完成Client和Server之间的握手。之后所有的消息、异常都是由Client与Server直接交互。(想象DNS)。简单对象交互如图: 应用场景二: l Broker启动,完成自身的初始化,之后进入事件循环,等待消息到来。 l Server启动,首先执行自身的初始化,然后注册自己到Broker。 l Broker接收Server的注册请求,将其加入到可使用服务的列表,并回应Ack给Server。 l Server接收Ack,进入事件监听循环,等待消息到来。 l Client调用远程服务对象的方法,Client_Proxy封装消息请其发送给Broker。 l Broker查询可使用的Server,将请求转发给Server。 l Server_Proxy解析消息,分离出参数和控制信息,并调用特定的Server实现接口。Server处理完的结果通过Server_proxy封装成消息转发到Server。 l Broker将相应消息转发给正确的Client_Proxy,Client受到响应继续其他逻辑。 简单对象交互如图: 应用场景三: l Broker A接收到请求,交由Server处理,但是发现该Server位于其他的网络节点。 l Broker A将请求转发给Bridge A,Bridge A将请求进行必要的格式化,传送给Bridge B。 l Bridge B将请求进行必要的格式化,转化成Broker B可以理解的格式,并转发给Broker B。Broker B执行场景二中的过程,处理的结果按如上逆序返回。 简单对象交互如图: 部署示意图: 总结: u 优点: 1. 服务的位置透明性。 2. 组件的可变性及扩展性。由于Server是注册到Broker上的,所以Server可以动态的增加、删除、改变。 3. Broker之间可交互。 4. 可重用性。 5. 由于组件的耦合度较小,调试和测试的工作也是可控的。 u 缺点: 1. 效率;增加了一层Broker的消息转发,效率有所降低。 2. 容错能力必须要特别考虑。 3. 调试和测试的工作加大。

posted @ 2015-10-26 10:32 zyskm 阅读(250) | 评论 (0)编辑 收藏

专家思维

大师的非凡能力来源于何处?思维方式是关键。科学证据告诉人们,没有天生的大师,只有炼就的专家。只要拥有专家的思维,你就能成为大师! 1909年的一天。多张象棋桌围成了一个圈,一个男子在圈内慢慢踱步。他的双眼不断扫描周围的棋局,每隔两三秒钟就会下一步棋。而在圈外,数十位象棋迷不停地搔头、苦想对策。这个人是谁?为什么他能以一人之力抗衡数十人的智慧?他就是国际象棋界的传奇人物,古巴象棋大师卡帕布兰卡(José Raúl Capablanca)。比赛结果毫无悬念,卡帕布兰卡28局全胜。这只是他巡回表演赛中的一站,在整个巡回表演赛中,卡帕布兰卡赢了168局。 为什么眨眼间他就能作出最正确的决定?面临巨大的压力,他能提前计算几步?卡帕布兰卡轻描淡写地说:“我只提前看一步,但总是最正确的一步。” 这句话再简单不过,却开创了心理学研究的新纪元:象棋大师优于新手的地方就在于那电光火石间的思考。这种快速的、由知识引导的知觉,有时叫做“领悟”。在其他领域,专家们同样具有“领悟”的本领。一次比赛完毕,象棋大师能记住自己走过的每一步棋;对于一段音乐,哪怕只听过一遍,资深音乐家也能写出乐章的曲谱。无论多么困难,象棋大师也能在瞬间想到最妙的棋着;不管多么复杂,经验丰富的专业内科医生有时只须瞥上病人几眼,就能作出准确的诊断。 专家们的非凡技艺从何而来?源于天赋,还是得益于强化训练?通过对象棋大师的研究,心理学家找到了答案。一个世纪的探索积累了大量研究成果,新的理论应运而生,人脑处理信息(信息的组织与提取)之谜也由此破解。这项研究的意义还不仅在于此,人类的教育事业也将从中受益:象棋棋手提高棋艺的技巧,可否用于提高学生们的阅读、写作和计算能力呢? 象棋是最好的研究对象 人类何时开始拥有专业技术?这也许要从祖先们的狩猎说起。对于他们而言,狩猎技术是维系生命的重要工具,不掌握它就难以生存。经验丰富的猎人不仅知道狮子在哪里出没,而且还能推断出狮子的行踪。从孩提时代开始,他们就得跟随长辈练习追踪技术。随着年龄的增长,追踪技术也日益娴熟。“技术的熟练程度随着年龄的增长而增长,35岁左右达到技术的巅峰,”美国加利福尼亚大学富勒顿分校的人类学家约翰?博克(John Bock)说道。练习追踪技术要花费很多时间,可能比培养优秀的脑外科医生还要费事。 相对于新手,如果在技术上没有绝对优势,那就难称专家,只不过是多了一张唬人的文凭。这种披着专家外衣的人比比皆是。过去20年的研究结果表明,所谓的专业炒股者并不比业余者赚的钱多;知名品酒家对酒类的鉴别能力并不比馋酒的老农强;高学历的精神病医生并不比低文凭的同行出色……即使真的存在专业技术,如教学、工商管理,都很难去衡量,更别提如何去阐释。 不过,棋艺却可以度量、可以分解、可以接受试验研究,并且十分直观,尤其在比赛时,任何人都能随时观看。正是基于以上原因,认知科学家如获至宝,将象棋作为研究思维理论的最佳试验对象。于是象棋被称作“认知科学的果蝇”。 对象棋手棋艺的度量,已经走在了其他任何比赛、运动或竞技活动的前面。运用统计学公式,对棋手曾获得的所有成绩进行分析,就可以得到棋手的实力等级。然后根据棋手的等级与对手的实力,即可准确地推算出棋手的获胜几率。如果A棋手的等级分高于B棋手200点,那么在比赛中,A战胜B的平均几率为75%。不管棋手是顶级的还是普通的,这种预测都很准确。例如,俄罗斯特级象棋大师加里?卡斯帕罗夫(Garry Kasparov),他的等级分是2812点,而荷兰象棋大师扬?蒂曼(Jan Timman)的等级分是2616点。如果二者对弈,那么卡斯帕罗夫就有75%的胜算。同样,中等水平的棋手(1200点)与另一个1000点的棋手对弈,前者亦有75%的胜算。选手的等级分代表着他们的真正实力,以选手的等级为标准,心理学家就可以客观地评估他们的专业技术,动态追踪他们整个象棋生涯,而不会受到选手名气的影响。 为什么认知科学家没有选择台球或桥牌作为研究模型,而偏偏选择象棋呢?可能是因为象棋比赛最考验人的智慧。正如德国诗人歌德所言,象棋是“智慧的试金石”。象棋大师的技艺出神入化,令人叹为观止,人们将他们的能力归因于他们“拥有魔力”的大脑。这种魔力在下盲棋时体现得淋漓尽致。法国心理学家阿尔弗雷德?比奈(Alfred Binet)是首个智力测验的发明人之一。1894年,他曾请象棋大师描述他们下棋的过程。起初,他认为棋盘就像照片一样存在于象棋大师的大脑中,但是他很快断定,大师们大脑中的图像还要抽象得多。他们整体把握棋子的位置关系而不注重具体细节,就像只关心马而不关心马的鬃毛一样。 通过把握比赛的即时细节以及回想走过的棋步,盲棋大师能将脑海中的棋局补充完整。假设大师忘记了卒的准确位置,该怎么办呢?他立即开始回想开局时的套路,因为在开局时,套路相对固定,而且已经烂熟于胸,因此很容易找到卒曾经所在的位置。他也可以回忆走过的棋步,通过推理来找到卒的位置――“前两步我没能抓住他的相,所以当时一定有卒在挡路……”他不必纠缠细节不放,利用组织完善的连接系统,可以重获任何想要的细节。 如果大师们的魔力――超凡的计算、计划能力都是以复杂的知识结构为基础,那么就可以肯定,专业技术多半来源于刻苦训练,而非上天的恩赐。荷兰心理学家阿德里安?德赫罗特(Adriaan de Groot)是一位象棋大师。1938年,荷兰举行了一场国际象棋锦标赛,他利用主场之便,对普通棋手、专业棋手与世界顶级大师进行比较后,进一步巩固了上述观点。他曾使用的一种方法就是请棋手观看节选自比赛的棋局,然后说出自己的想法。他发现,尽管专业棋手的分析能力要比普通棋手强,但是当他们的实力提升至大师级时,反而不会去思索更多的下法。因为在高手的心中,只会留下最妙的棋着――正如卡帕布兰卡声称的那样。 近来研究表明,德赫罗特的发现只展示了象棋大师的部分实力。在一场对弈中,如果大量而精确的计算无法避免时,大师们就会拿出真功夫,深入研究各种可能的棋步走法。这种能力,会让普通棋手望尘莫及。同样,知识渊博的物理学家遭遇难题时,也会比他的学生想出更多的解决办法。然而在上述两种情况下,专家依靠的不是与生俱来的强大的分析能力,而是多年来逐渐建立起来的知识结构。面对困难的棋局,一个实力平平的棋手可能会耗费大半个小时去计算、提前看许多步,然而总是错过最正确的一步。相反,一个大师级的棋手根本不用有意识地去分析,立即就能看到精妙入微的一步。 德赫罗特还让参加试验的棋手在短时间内审视棋局,然后凭记忆重建棋局。在这样的试验条件下,任何棋手的实力都会暴露无遗。就算用长达30秒钟的时间去回忆棋局,新手能记起的细节也是支离破碎的。而象棋大师,即使只瞟上几眼,也能轻松重建棋局。这种差别源于一种特殊记忆,也就是对棋局的特异性记忆。特殊记忆是训练的结果,因为在一般性的记忆测试中,大师的表现并不比其他人好。 同样的现象还能从桥牌牌手(多场牌局后,仍记得出过的牌)、计算机程序设计师(能重组大量的计算机编码)和音乐家(能记住大段大段的乐章)身上看到。在特殊领域,对主题事务的记忆能力,是衡量专业技术水平的重要标准。 一个不常见的案例也能证明,知识结构才是专家们战无不胜的法宝。一个叫D.H(姓名不全)的业余棋手,经过9年的训练,终于在1987年成为了加拿大一流的象棋大师。美国佛罗里达州立大学的心理学教授尼尔?蔡内斯(Neil Charness)指出,尽管这个棋手的实力已经今非昔比,但是他对棋局的分析范围并不比从前广泛,反而是日益精深的棋局知识和相关策略帮助他连连告捷。 非凡能力来自何方 在上世纪60年代,美国卡耐基-梅隆大学的心理学家赫伯特?西蒙(Herbert Simon,1978年诺贝尔奖得主)和威廉?蔡斯(William Chase),试图通过研究专家的记忆局限性来更好地洞察专家的记忆能力。按照德赫罗特的研究思路,他们请各个级别的棋手重建曾被人动过的棋局。不过这盘棋局不是大师对弈后的残局,而是一盘乱摆的棋局。在重建这盘随机棋局时,棋手间的差距并不明显。 因此,象棋运动中的特异性记忆不只取决于象棋这项运动,还取决于棋局的类型。这些实验验证了早期的研究结果,有力地证明了能力的非通用性,不同的领域需要不同的能力。早在一个世纪前,美国心理学家爱德华?桑代克(Edward Thorndike)就首先提出了上述理论。当时他指出,拉丁语说得好不等于英语水平高,几何证明也不能教会人们在日常生活中运用逻辑思维。 象棋大师要处理的信息,数量极其庞大,似乎已经超越了人类记忆的极限。为了解释他们这种超凡的能力,西蒙引入了模块理论。1956年,美国普林斯顿大学的心理学家乔治?米勒(George Miller)曾发表过一篇著名的论文――《非凡的数字7±2》。米勒在论文中指出,人的记忆有一定的限度,每次只能处理5~9条信息。西蒙强调说,通过把不同层次的信息构建成一个一个模块,大师就能突破记忆的极限。通过这种方法,他们会去捕捉5~9个模块,而不是5~9个具体细节。 以“Mary had a little lamb”(玛丽有一只小羊羔)这句诗为例。诗里的信息模块数取决于读者对诗歌与英语的熟悉程度。对于以英语为母语的人,这句诗是一个非常大的模块――著名诗歌的一部分;对于懂英语却不懂诗歌的人,这就是一句话――一个完整的模块;对于记得单词却不明白含义的人,这句话是5个模块(单词);而对于认得字母,却不认识单词的人,这句诗就是18个模块(字母)! 在象棋新手和象棋大师之间就能清楚地看到这种差别。假如有一个摆着20个棋子的棋局放在面前,新手和大师会怎么处理其中的信息呢?新手满眼都是棋格,而棋子又有多种摆法,因此他获取的信息模块远多于20个。那么大师呢?他会将棋局整体化,然后把整个棋局分割成5~6个模块,这样记起来不就轻松多了!根据获取一个新的记忆模块所花掉的时间,以及普通棋手成长为大师级选手所需要的时间,西蒙估算出了象棋大师的大脑中存储的信息模块数:5万~10万个!就像我们听几个字就能背出一首古诗一样,象棋大师只要看一眼棋局,就能从记忆中提取出相应的信息模块。 但是模块理论还有缺陷。对一些记忆现象,例如当大师们精力分散时,他们的表现并没有受到明显影响,模块理论就无法给出合理的解释。佛罗里达州立大学的K?安德斯?埃里克森(K. Anders Ericsson)与蔡内斯认为,可能还存在另外一种机制,使得专家可以把长时记忆当作暂存区使用。埃里克森说:“训练有素的棋手在不看棋盘的情况下,能以几乎正常的水平下棋,要用模块理论来解释这样的事例,几乎不可能。因为你必须先了解棋局,然后才能在记忆中把它翻出来。”这一处理过程需要改变已有的信息模块,就像倒背 “Mary had a little lamb”,虽然可以做到,但是很难,而且还会错误不断。然而在下盲棋的时候,象棋大师仍然可以精准快速地下棋,让对手无所适从。 埃里克森还引证了内科医生的学习过程。医生们先把信息变为长时记忆,当需要使用这些信息来诊断疾病时,再把它从记忆中提取出来。埃里克森还列举了一个最普通、最常见的例子――阅读。1995年,他在研究中发现,越是熟练的读者越不容易受到干扰。就算阅读被打断,熟练的读者也能在几秒钟的时间内恢复原有的阅读速度。研究人员用长时工作记忆来解释这一现象。这一说法似乎自相矛盾,因为长时记忆与工作记忆是两个相互对立的概念。不过在2001年,德国康斯坦茨大学进行的大脑成像研究却为这一说法提供了依据。研究结果表明,较之新手,专业棋手的长时记忆显然更容易激活。 上世纪90年代末期,西蒙曾提出过一种竞争理论。英国伦敦布鲁内尔大学的费尔南德?戈贝特(Fernand Gobet)对它推崇备至。竞争理论实际上是模块理论的延伸,它引入了“模板”的概念,也就是一种极其典型并包含了大约12只棋子的大型布局。模板拥有许多插口,大师可以插入卒或者相这样的变量。再以诗句“Mary had a little lamb”为例,如果某个词的韵律与诗句中的词等同,那么就可以用这个词来替换诗中的词。例如,用“Larry”替代“Mary”,用“pool”来替代“school”等等。任何知道原始模块的人,都能在瞬间插入另一个词。 天才是怎样“炼”成的 要想在大脑中建立复杂的知识结构,就得不断努力。西蒙提出了“十年规则”,他认为要掌握任何技艺,十年的艰辛历程是无法避免的。即便是数学天才高斯,音乐奇才莫扎特,象棋神童菲舍尔,也得去拼搏、去奋斗,也许他们所付出的努力是常人难以想象的。 近年来,象棋天才似乎不断涌现,但这都归因于计算机的强大功能。计算机能让孩子们研究海量的大师级比赛,频繁地与大师级程序对抗,于是在较短的时间内,他们就能积累丰富的实战经验。1958年,15岁的菲舍尔获得了象棋大师的称号,当时这一消息震惊了全世界。而目前的记录保持者、乌克兰的谢尔盖?卡尔亚金(Sergey Karjakin)获得大师称号时,仅有12岁零7个月! 埃里克森认为,光是练习远远不够,还需要全身心投入,不断挑战极限、超越自我。就像业余爱好者,他们可能会用大量的时间来练习下棋、打高尔夫球、演奏乐器,却始终达不到专业水平;然而一个经过正规训练的学生,却能在较短的时间内超过他们。这是一个很有趣的现象,说明练习和比赛对棋手的帮助似乎不如踏踏实实地学习。训练和比赛的主要价值在于,新手可以从中发现自己的缺陷,从而在以后逐渐弥补。 在学习初期,新手往往兴趣浓厚,钻研劲儿十足。他们刚开始学习打高尔夫球或者开车时,技术的进步速度可用“神速”二字来形容。但是技术一旦攀升到一定的阶段,例如跟上了高尔夫球友的节奏,或者考取了驾照,大多数人就松懈了。于是,他们变得懒散,技术也被荒废。相反,训练专家总是让人不停地思考,因此参与学习的人就会自觉自律地去钻研、不断提高技术,从而缩小与高手之间的差距。 人类在进步,衡量专业水平的技术标准也在不断提高。现在的高中生能在4分钟内跑完一英里(约合1.6公里);学音乐的学生敢于演奏曾经只有名家才敢尝试的曲子。如果说上述比较还不能让人信服,那么我们再来看看象棋上的证据。英国人约翰?纳恩(John Nunn)既是数学家,又是象棋大师。他利用计算机,比较了1911年和1993年举行的两届国际象棋锦标赛。结果发现,现代棋手出错的几率要小很多,换言之,他们比前辈们下得更准确。纳恩还研究了1911年的一个棋手下过的所有棋局。在当时,这个棋手算是一个中等级别的选手。按照今天的标准,他的等级分不会多于2100点,离大师级标准还有一大段距离。与普通棋手相比,百年前的大师仍然实力强劲,不过与今天的大师相比,可能就有一定的差距。 在卡帕布兰卡的那个时代,计算机、象棋数据库都还没有出现,他们只能靠自己解决一切问题,正如巴赫、莫扎特和贝多芬。如果说今天的大师在技术上已经超越了曾经名满天下的先辈们,然而在创造力方面他们却难以望其项背。今天,刚毕业的物理学博士掌握的物理知识,恐怕连牛顿也要自叹弗如,但是在这些博士中,有谁能像当年的牛顿一样发现万有引力定律? 说到这里,很多怀疑论者的耐心可能会荡然无存。他们肯定会说,要步入卡耐基殿堂,除了练习、练习、再练习之外,还要付出更多的东西。虽然相信天资的重要性,尤其是专家和他们的学生对此深信不疑,然而奇怪的是,没有任何证据来支持这一观点。2002年,戈贝特曾做过一项研究。研究中,他用图形记忆测验衡量各级别棋手的视觉空间智能。结果发现,棋艺的高低与视觉空间智能的强弱根本没有联系。还有研究人员发现,职业裁判预见赛马结果的能力与他们的数学能力也没有什么关系。 ... ...

posted @ 2014-10-16 15:32 zyskm 阅读(245) | 评论 (0)编辑 收藏

信息熵

     摘要: 熵是信息理论中非常重要的一个概念,用来度量信息,在实践中大量使用。
信息检索最重要的概念TF/IDF(term frequency/inverse document frequency)就是基于信息熵理论。搜索引擎、新闻分类、文本相似度计算都使用这个概念。  阅读全文

posted @ 2014-06-12 14:45 zyskm 阅读(1837) | 评论 (6)编辑 收藏

Chomsky文法

看Chomsky的书是因为在编译原理课程中多次提到这个人,这是个变态天才,神一般的存在,而且还是活的。
Chomsky的语言学理论观点在语言学、心理学和哲学领域都产生了广泛而深刻的影响。Chomsky的哲学思想是一个贯穿了唯实论、自然主义和心智主义的连贯的、完整的体系。这一体系的核心是内在语言理论。但是这一理论观点与传统观点分歧很大 ,因此遭受到哲学界的强烈攻击。Chomsky正是在这些争论的过程中不断地发现问题并对自己的理论和观点进行修改和补充 ,从而使其哲学系统乃至语言学理论系统更趋完善。哲学问题咱不关心这么无聊的问题留给哲学家们去扯。

理论方法
Chomsky语言学的理论方法概况起来讲,是自然科学中形式主义的演绎方法,用Chomsky自己的话讲,叫伽利略研究风格(Galileo Style),像伽利略为宇宙建立抽象的数学模型一样,构建有关语言知识的抽象数学模型,相信类似数学一样的形式主义的演绎推理模型具有自足自明的真理性。Chomsky的语言研究所追求的是从世界各种语言五花八门的句子样式中抽象出几个简单的句法规则。

Chomsky的句法结构一书中把语言学看成跟自然科学中的其他科学一样,可以从假设出发,进行推演并形式化。换句话说,非经验主义是可能的。《句法结构》有一半篇幅用于英语语法的形式化。非经验主义和形式化是转换生成语法的首要标志。
 
把句法关系作为语言结构的中心并以此说明语句的生成是这场革命的又一表现。为了描写和解释语言现象,Chomsky在《句法结构》中论证了语法的生成能力,认为应该把语法看成是能生成无限句子的有限规则系统。
 
它以"核心句"为基础,通过转换规则描写和分析不同句式之间的内在联系。该书分析了以"马尔可夫过程"为基础的通讯理论,认为它只能生成有限状态的语法,而这种"有限状态的语法"不能生成象英语这种语言里含有不连续结构的所有合乎语法的句子。基于此,乔姆斯基提出了转换语法模式,认为它才能生成所有合乎语法的句子而不会生成不合乎语法的句子。转换语法模式由短语结构规则、转换规则、语素音位规则三套规则构成。
 
短语结构规则有三种:合并、递归、推导式,其基本形式是x→y 。→读作"改写",这个公式就是将x改写成y。短语结构规则生成的是"核心语符列",不经过转换直接由这种语符列得出的基本句型叫"核心句"。
 
转换规则包括:移位、删略、添加。最后运用语素音位规则得出实际说出的句子。这三套规则中,最引人注目的是转换规则,因为短语结构规则和语素音位规则实际上继承了描写语言学的"直接成分分析"和语素音位的分析,转换是一种创新,它使语法具有更强的解释力。
 
《句法结构》把语义排除在语法之外,这一时期的理论框架不包括语义部分。乔姆斯基认为,语法理论不应该建立在语义的基础上,而应该用某种严格的、客观的方法去代替对于模糊的语义的依赖。不过这一理论在后来的发展中做了重大的修正。

Chomsky 定义的四种形式语言文法中, 0 型文法又称为 ( A )文法; 1 型文法又称为 ( C ) 文法; 2 型语言可由 ( G ) 识别。
A .短语结构文法 B 前后文无关文法 C 前后文有关文法 D 正规文法
E 图灵机 F 有限自动机 G 下推自动机
文法是用来定义语言的一个模型,常用的文法体系为Chomsky文法体系。
 
文法定义
 
文法G(Grammar)是一个四原组,G=(N,T,P,S),N(Non-terminator)是非终结符集合,T(Terminator)是终结符集合,P(Production)是产生式集合,S(Start)是起始符
 
其中:
 
N 交 T = 空集
 
P 是形式为 α -> β 的产生式
 
   α ∈  (N∪T)*N+(N∪T)*,也就是说α中必须有一个非终结符
 
   β ∈  (N∪T)* ,也就是说β可以是空串
 
S∈N
 
 
 
分类
 
0型文法(短语文法或无限制文法),识别0语言的机器叫做图灵机

  定义:P中产生式a-->b,其中a属于V正闭包且至少含有一个非终结符,b属于V星闭包

  注:任何0型文法都是可递归可枚举的

    对0型文法作某些限制,可以得到其他文法的定义

1型文法 又称上下文有关文法。生成式形式为 α->β, 且 |α| < |β| 并且不存在 A->ε
 
2型文法 又称上下文无关文法。生成式形式为 A->α,即左边必须只有一个非终结符
 
3型文法 又称正则文法。
 
             生成式 A->wB或A->w,称为右线性文法
 
             生成式 A->Bw或A->w,称为左线性文法
 
0型文法 对生成式没有任何限制的文法称为0型文法。从0到3都是包含的关系,但是有特例,包含  A->ε 产生式的2,3型文法不属于1型文法。
 
四种文法产生的语言分别称为 上下文有关语言,上下文无关语言,正则语言,无限制性语言。
 
 
 
2型语言的表示法
 
2型语言是很重要的一种语言,除了用四元组的方法表示,此处再介绍两种表示方法。
 
当人们要解释或者讨论程序设计语言本身时,经常又需要一种语言,被讨论的语言叫做对象语言,即某种程序设计语言,讨论对象语言的语言称为元语言,即元语言是描述语言的语言。BNF范式通常被作为讨论某种程序设计语言语法的元语言,而语法图是与BNF范式的描述能力等价的另一种文法表示形式,因其直观性而经常采用。
 
(1)巴科斯范式(Backus Normal Form,BNF)
 
2型文法生成式左端只有一个非终结符,所以可以把左端相同的生成式合并在一起,右端用|隔开,用::=代替->,所有非终结符用<>括起来,这是Backus为了描述AIGOL语言首次提出并使用的。
 
用BNF描述十进制整数的生成语法:
 
<无符号整数> ::= <数字>|<数字><无符号整数>
 
<数字> ::= 0|1|2|3|4|5|6|7|8|9
 
(2)语法图
 
语法图有四种基本形式
 
(3)推导树
 
2型文法还经常用推导树表示

posted @ 2013-06-24 11:25 zyskm 阅读(2546) | 评论 (0)编辑 收藏

通过antlr语法文件学习java---strictfp

  节选自java.g
modifiers 
    :
    (    annotation
    |   'public'
    |   'protected'
    |   'private'
    |   'static'
    |   'abstract'
    |   'final'
    |   'native'
    |   'synchronized'
    |   'transient'
    |   'volatile'
    |   'strictfp'
    )*
    ;Strictfp —— Java 关键字。
  strictfp, 即 strict float point (精确浮点)。
  strictfp 关键字可应用于类、接口或方法。使用 strictfp 关键字声明一个方法时,该方法中所有的float和double表达式都严格遵守FP-strict的限制,符合IEEE-754规范。当对一个类或接口使用 strictfp 关键字时,该类中的所有代码,包括嵌套类型中的初始设定值和代码,都将严格地进行计算。严格约束意味着所有表达式的结果都必须是 IEEE 754 算法对操作数预期的结果,以单精度和双精度格式表示。
  如果你想让你的浮点运算更加精确,而且不会因为不同的硬件平台所执行的结果不一致的话,可以用关键字strictfp.

posted @ 2013-06-09 10:27 zyskm 阅读(1961) | 评论 (0)编辑 收藏

java静态导入

import语句可以导入一个类或某个包中的所有类

import static语句导入一个类中的某个静态成员(方法或属性)或所有静态成员

语法举例:

import static java.lang.Math.sin;

import static java.lang.Math.*;

例子:


//导入Math类中的所有static方法和属性。 
//这样我们在使用这些方法和属性时就不必写类名。 
import static java.lang.Math.*;//import static java.lang.Math;//这样写报错  
public class StaticImport { 
       public static void main(String[] args) { 
//            System.out.println(Math.max(3, 5));//没有使用静态导入 
//            System.out.println(Math.abs(1-9));//没有使用静态导入 
              System.out.println(max(3, 5)); 
              System.out.println(abs(1-9)); 
       }

注意:1默认包无法用静态导入。

2如果导入的类中有重复的方法和属性则需要写出类名,否则编译时无法通过。

 
}

posted @ 2013-06-09 10:23 zyskm 阅读(2031) | 评论 (0)编辑 收藏

dbcompare---数据库结构比较工具

概述:
在设计开发过程中经常会出现开发库与测试库不一致,测试库与生产库不一致,每次手工比对是个辛苦的活。
以前用java写过一个数据库结构比较工具,最近腾出功夫来学习了一下python,用python重写了一下,已经提交到了github和sourceforage.
版本控制使用github
https://github.com/zhengys/dbcompare.git
sourceforage上边放了exe文件(用pyinstaller打包的程序发现在部分win7上不能正常工作,又用py2exe打包了一个64位版本的,已经上传sourceforage  , 感谢itshu的反馈)
http://sourceforge.net/projects/databasecompare/files/
通过这个工具可以做到简单明了的看出区别。
对于数据库和设计文档不一致的情况,目前只能是先根据文档生成数据库,再和原来的库做比对。未来考虑增加powerdesinger和数据库的间直接比较。
目前只支持oracle,mysql,sqlserver,要是用的人多了再增加其它类型的数据库。

使用:
功能类似文本比较工具,分别输入数据库连接信息,在结果页面显示比对结果。
操作很简单看图就知道怎么用了。
如图:


打包说明
一开始用py2exe打包,发现在winxp下用不了
改用pyinstaller打包,360会误认为是木马拦截,文件夹形式打包,比较占地方,压缩后也得36MB.
可根据源码自行打包。


posted @ 2013-05-14 23:49 zyskm 阅读(4380) | 评论 (3)编辑 收藏

SOCKS5协议的原理和应用(转载)

首先解释一下为什么它被称之为SOCKS。其实该协议设计之初是为了让有权限的用户可以穿过过防火墙的限制,使得高权限用户可以访问一般用户不能访问的外部资源。当时设计者考虑到几乎所有使用TCP/IP通信的应用软件都使用socket(套接字,实际上是一组应用程序接口)完成底层的数据通信。为了方便软件开发者使用该协议,协议设计者就刻意对应了几组socket编程最经典的操作,并且将协议定名为SOCKS。


最先被广泛使用的SOCKS协议是其第四版本,就是SOCKS4。IE和一些其他应用程序直接用“Socks”表示SOCKS4协议。该版本支持TCP的connect(作为客户端连接)和listen(打开一个监听端口),不支持UDP协议。SOCKS4A对SOCKS4作了一点增强,即允许客户端将域名发送给SOCKS服务器,让SOCKS服务器进行域名解析。


SOCKS5是第五版,相对第四版作了大幅度的增强。首先,它增加了对UDP协议的支持;其次,它可以支持多种用户身份验证方式和通信加密方式;最后,修改了SOCKS服务器进行域名解析的方法,使其更加优雅。经过这次脱胎换骨的升级,SOCKS5于1996年被IETF确认为标准通信协议,RFC编号为1928。经过10余年的时间,大量的网络应用程序都支持SOCKS5代理。


SOCKS5虽然可以支持多种用户身份验证方式,但是应用程序真正实现的一般也只有两种:不验证和用户名密码验证。所以大多数应用程序SOCKS5代理设置也只有用户名/密码这一种可选验证方法。另外,尽管从SOCKS4开始,就支持打开TCP监听端口,但是直到SOCKS5,也只允许这个端口接收一个客户端连接。因此网络服务提供者(如http服务器)不能使用SOCKS。实际上,很多SOCKS服务器的实现也不支持打开TCP监听端口。


由于SOCKS5实际上仍然对应了socket的经典操作,所以有人利用这一点编写了一种通用软件,可以让不支持SOCKS5协议的应用软件也能通过SOCKS5服务器进行网络通信,而应用软件则对此一无所知。这类软件最著名的莫过于SocksCap32了,它是Permeo公司(其前身是NEC北美公司的一个部门,而SOCKS最初就是NEC北美公司的工程师开发并维护的)早期推出的一款产品。用户可以免费使用其试用版。试用版和正式版相比,没有功能上的限制,只有使用时间的限制。但是到目前为止,Permeo总是会在老版本到期之前推出一个延后了期限的“新”版本,所以用户实际上可以免费使用。SocksCap32是利用API钩子,截获应用软件对socket函数的调用来实现对SOCKS5客户端的模拟。尽管SocksCap32很有名,但是由于推出的时间较早,对很多现代应用软件时常表现的力不从心,所以Permeo又提供了Permeo
Security
Driver(以下称为PSD)。这款产品使用了驱动技术从底层直接截获应用软件的socket通信,因此几乎可以为所有应用软件提供SOCKS5客户端的支持。PSD不提供试用版,但是可以找到其早期版本的注册码。


虽然说设计SOCKS协议的初衷是在保证网络隔离的情况下,提高部分人员的网络访问权限,但是国内似乎很少有组织机构这样使用。一般情况下,大家都会使用更新的网络安全技术来达到相同的目的。但是由于SocksCap32和PSD这类软件,人们找到了SOCKS协议新的用途——突破网络通信限制,这和该协议的初衷实际上正好相反。比如某些网游的部分服务器设置为只接收部分地区的IP地址的连接。为了突破这种限制,可以找一个该地区的SOCKS5代理服务器,然后用PSD接管网游客户端,通过SOCKS5代理服务器连接游戏服务器。这样游戏服务器就会认为该客户端位于本地区,从而允许进行游戏。还有一种情况是:防火墙仅允许部分端口(如http的80端口)通信,那么可以利用SOCKS5协议和一个打开80端口监听的SOCKS5服务器连接,从而可以连接公网上其他端口的服务器。利用一些额外的技术手段,甚至可以骗过内部的http代理服务器,这时在使用内网http代理上网的环境下也可以不受限制的使用网络服务,这称之为SOCKS
over HTTP。通通通([url]www.tongtongtong.com[/url])是老牌SOCKS over
HTTP代理提供商,实现了所有的SOCKS5的连接功能,且有多组国内外服务器。信天游([url]www.xtyproxy.com[/url]),则是最近刚刚出现的代理服务提供商,功能和通通通相比还有差距,但是目前完全免费。当然,使用代理服务器后,将不可避免的出现通信延迟,所以应该尽量选择同网络(指网通/
电信),距离近的服务器。

sock5代理的工作程序是:

1.需要向代理方服务器发出请求信息。
2.代理方应答
3.需要代理方接到应答后发送向代理方发送目的ip和端口
4.代理方与目的连接
5.代理方将需要代理方发出的信息传到目的方,将目的方发出的信息传到需要代理方。代理完成。
由于网上的信息传输都是运用tcp或udp进行的,所以使用socks5代理可以办到网上所能办到的一切,而且不舆目的方会查到你的ip,既安全又方
便
sock5支持UDP和TCP,但两种代理是有区别的,以下分类说明
如何用代理TCP协议
1.向服务器的1080端口建立tcp连接。
2.向服务器发送
05 01 00 (此为16进制码,以下同)
3.如果接到 05 00 则是可以代理
4.发送 05 01 00 01 + 目的地址(4字节) +
目的端口(2字节),目的地址和端口都是16进制码(不是字符串!!)。 例202.103.190.27 -7201 则发送的信息为:05 01 00 01 CA
67 BE 1B 1C 21 (CA=202 67=103 BE=190 1B=27
1C21=7201)
5.接受服务器返回的自身地址和端口,连接完成
6.以后操作和直接与目的方进行TCP连接相同。
如何用代理UDP连接
1.向服务器的1080端口建立udp连接
2.向服务器发送
05 01 00
3.如果接到 05 00 则是可以代理
4.发送 05 03 00 01 00 00 00 00 +
本地UDP端口(2字节)
5.服务器返回 05 00 00 01 +服务器地址+端口
6.需要申请方发送 00 00 00 01
+目的地址IP(4字节)+目的端口 +所要发送的信息
7.当有数据报返回时 向需要代理方发出00 00 00 01 +来源地址IP(4字节)+来源端口
+接受的信息
注:此为不需要密码的代理协议,只是socks5的一部分,完整协议请RFC1928

posted @ 2013-03-01 14:18 zyskm 阅读(9795) | 评论 (0)编辑 收藏

linux 怎么完全卸载mysql数据库

在linux下开发,mysql数据库是经常用到的,对于初学者来说,在linux怎么安装卸载mysql数据库,也许可能比较痛苦,这里简单介绍下,怎么卸载msql数据库。

a)查看系统中是否以rpm包安装的mysql

  1. [root@linux ~]# rpm -qa | grep -i mysql 
  2. MySQL-server-5.1.49-1.glibc23 
  3. MySQL-client-5.1.49-1.glibc23 
卸载MySQL-server-5.1.49-1.glibc23和MySQL-client-5.1.49-1.glibc23
  1. [root@linux ~]# rpm -e MySQL-client-5.1.49-1.glibc23 
  2. [root@linux ~]# rpm -e MySQL-server-5.1.49-1.glibc23 
b)查看有没有mysql服务

 

  1. [root@linux ~]# chkconfig --list | grep -i mysql 
  2. mysql           0:off   1:off   2:on    3:on    4:on    5:on    6:off 
删除mysql服务
  1. [root@linux ~]# chkconfig --del mysql 
c)删除分散mysql文件夹
  1. [root@linux ~]# whereis mysql 
  2. mysql: /usr/lib/mysql /usr/share/mysql 
分别删除
  1. [root@linux lib]# rm -rf /usr/lib/mysql/ 
  2. [root@linux lib]# rm -rf /usr/share/mysql 

通过以上几步,mysql应该已经完全卸载干净了
原文地址:http://blog.csdn.net/love__coder/article/details/6894566

posted @ 2012-11-29 17:13 zyskm 阅读(22104) | 评论 (0)编辑 收藏

linux 安装应用程序

一、 解析Linux应用软件安装包:

     通常Linux应用软件的安装包有三种:

     1) tar包,如software-1.2.3-1.tar.gz。它是使用UNIX系统的打包工具tar打包的。
     2) rpm包,如software-1.2.3-1.i386.rpm。它是Redhat Linux提供的一种包封装格式。
     3) dpkg包,如software-1.2.3-1.deb。它是Debain Linux提供的一种包封装格式。
      而且,大多数Linux应用软件包的命名也有一定的规律,它遵循:
     名称-版本-修正版-类型
     例如:
     1) software-1.2.3-1.tar.gz 意味着:
     软件名称:software
     版本号:1.2.3
     修正版本:1
      类型:tar.gz,说明是一个tar包。
     2) sfotware-1.2.3-1.i386.rpm
     软件名称:software
     版本号:1.2.3
     修正版本:1
     可用平台:i386,适用于Intel 80x86平台。
     类型:rpm,说明是一个rpm包。
     注:由于rpm格式的通常是已编译的程序,所以需指明平台。在后面会详细说明。
     而software-1.2.3-1.deb就不用再说了吧!大家自己练习一下。
   二、 了解包里的内容:
     一个Linux应用程序的软件包中可以包含两种不同的内容:
     1) 一种就是可执行文件,也就是解开包后就可以直接运行的。在Windows中所 有的软件包都是这种类型。安装完这个程序后,你就可以使用,但你看不到源程序。而且下载时要注意这个软件是否是你所使用的平台,否则将无法正常安装。
     2) 另一种则是源程序,也就解开包后,你还需要使用编译器将其编译成为可执行文件。这在Windows系统中是几乎没有的,因为Windows的思想是不开放源程序的。
     通常,用tar打包的,都是源程序;而用rpm、dpkg打包的则常是可执行程序。一般来说,自己动手编译源程序能够更具灵活性,但也容易遇到各种问题和困难。而相对来说,下载那些可执行程序包,反而是更容易完成软件的安装,当然那样灵活性就差多了。所以一般一个软件总会提供多种打包格式的安装程序的。你可以根据自己的情况来选择。
   三、 搞定使用tar打包的应用软件
     1. 安装:
     整个安装过程可以分为以下几步:
     1) 取得应用软件:通过下载、购买光盘的方法获得;
     2)解压缩文件:一般tar包,都会再做一次压缩,如gzip、bz2等,所以你需要先解压。如果是最常见的gz格式,则可以执行:“tar –xvzf 软件包名”,就可以一步完成解压与解包工作。如果不是,则先用解压软件,再执行“tar –xvf 解压后的tar包”进行解包;
     3) 阅读附带的INSTALL文件、README文件;
     4) 执行“./configure”命令为编译做好准备;
     5) 执行“make”命令进行软件编译;
     6) 执行“make install”完成安装;
     7) 执行“make clean”删除安装时产生的临时文件。
     好了,到此大功告成。我们就可以运行应用程序了。但这时,有的读者就会问,我怎么执行呢?这也是一个Linux特色的问题。其实,一般来说, Linux的应用软件的可执行文件会存放在/usr/local/bin目录下!不过这并不是“放四海皆准”的真理,最可靠的还是看这个软件的 INSTALL和README文件,一般都会有说明。
     2. 卸载:
     通常软件的开发者很少考虑到如何卸载自己的软件,而tar又仅是完成打包的工作,所以并没有提供良好的卸载方法。
     那么是不是说就不能够卸载呢!其实也不是,有两个软件能够解决这个问题,那就是Kinstall和Kife,它们是tar包安装、卸载的黄金搭档。它们的使用方法,笔者会另行文介绍。在此就不加赘述了。
   四、 搞定使用rpm打包的应用软件
     rpm可谓是Redhat公司的一大贡献,它使Linux的软件安装工作变得更加简单容易。
     1. 安装:
     我只需简单的一句话,就可以说完。执行:
   rpm –ivh rpm软件包名
     更高级的,请见下表:
   rpm参数 参数说明
   -i 安装软件
   -t 测试安装,不是真的安装
   -p 显示安装进度
   -f 忽略任何错误
   -U 升级安装
   -v 检测套件是否正确安装
     这些参数可以同时采用。更多的内容可以参考RPM的命令帮助。
     2. 卸载:
     我同样只需简单的一句话,就可以说完。执行:
    rpm –e 软件名
     不过要注意的是,后面使用的是软件名,而不是软件包名。例如,要安装software-1.2.3-1.i386.rpm这个包时,应执行:
    rpm –ivh software-1.2.3-1.i386.rpm
     而当卸载时,则应执行:
    rpm –e software。
     另外,在Linux中还提供了象GnoRPM、kpackage等图形化的RPM工具,使得整个过程会更加简单。这些软件的具体应用,笔者会另行文介绍。

  五、 搞定使用deb打包的应用程序
     这是Debian Linux提供的一个包管理器,它与RPM十分类似。但由于RPM出现得更早,所以在各种版本的Linux都常见到。而debian的包管理器dpkg则只出现在Debina Linux中,其它Linux版本一般都没有。我们在此就简单地说明一下:
     1. 安装
    dpkg –i deb软件包名
      如:dpkg –i software-1.2.3-1.deb
     2. 卸载
    dpkg –e 软件名
     如:dpkg –e software

posted @ 2012-11-29 15:53 zyskm 阅读(392) | 评论 (0)编辑 收藏

linux find

Linux中find常见用法示例·find    path    -option    [    -print ]    [ -exec    -ok    command ]    {} \;
            #-print 将查找到的文件输出到标准输出
#-exec    command    {} \;       -----将查到的文件执行command操作,{} 和 \;之间有空格
#-ok 和-exec相同,只不过在操作前要询用户            ====================================================            -name    filename               #查找名为filename的文件
-perm                         #按执行权限来查找
-user     username              #按文件属主来查找
-group groupname              #按组来查找
-mtime    -n +n                 #按文件更改时间来查找文件,-n指n天以内,+n指n天以前
-atime     -n +n                #按文件访问时间来查GIN: 0px">-perm                          #按执行权限来查找
-user     username              #按文件属主来查找
-group groupname              #按组来查找
-mtime    -n +n                 #按文件更改时间来查找文件,-n指n天以内,+n指n天以前
-atime     -n +n                #按文件访问时间来查找文件,-n指n天以内,+n指n天以前
-ctime     -n +n                #按文件创建时间来查找文件,-n指n天以内,+n指n天以前
-nogroup                      #查无有效属组的文件,即文件的属组在/etc/groups中不存在
-nouser                       #查无有效属主的文件,即文件的属主在/etc/passwd中不存
-newer    f1 !f2                找文件,-n指n天以内,+n指n天以前
-ctime     -n +n                #按文件创建时间来查找文件,-n指n天以内,+n指n天以前
-nogroup                      #查无有效属组的文件,即文件的属组在/etc/groups中不存在
-nouser                       #查无有效属主的文件,即文件的属主在/etc/passwd中不存
-newer    f1 !f2                #查更改时间比f1新但比f2旧的文件
-type      b/d/c/p/l/f          #查是块设备、目录、字符设备、管道、符号链接、普通文件
-size       n[c]                #查长度为n块[或n字节]的文件
-depth                        #使查找在进入子目录前先行查找完本目录
-fstype                       #查更改时间比f1新但比f2旧的文件
-mount                        #查文件时不跨越文件系统mount点
-follow                       #如果遇到符号链接文件,就跟踪链接所指的文件
-cpio                         #对匹配的文件使用cpio命令,将他们备份到磁带设备中
-prune                        #忽略某个目录            ====================================================
$find    ~    -name    "*.txt"    -print      #在$HOME中查.txt文件并显示
$find    .     -name    "*.txt"    -print

            $find    .     -name    "[A-Z]*"    -pri26nbsp;     #对匹配的文件使用cpio命令,将他们备份到磁带设备中
-prune                                #忽略某个目录            $find    .     -name    "[A-Z]*"    -print    #查以大写字母开头的文件
$find    /etc    -name    "host*"    -print #查以host开头的文件
$find    .    -name    "[a-z][a-z][0--9][0--9].txt"     -print    #查以两个小写字母和两个数字开头的txt文件
$find .    -perm    755    -print
            $find    .    -perm -007    -exec ls -l {} \;    #查所有用户都可读写执行的文件同-perm 777
$find    . -type d    -print   打印目录结构
$find    .  !    -type    d    -print  打印非目录文件find /usr/include -name '*.h' -exec grep AF_INEF6 {} \; 因grep无法递归搜索子目录,故可以和find相结合使用。 在/usr/include 所有子目录中的.h文件中找字串AF_INEF6
$find    .    -type l    -print            $find    .    -size    +1000000c    -print         #查长度大于1Mb的文件
$find    .    -size    100c          -print        # 查长度为100c的文件
$find    .    -size    +10    -print               #查长度超过期作废10块的文件(1块=512字节)            $cd /
            $find    etc    home    apps     -depth    -print    | cpio    -ivcdC65536    -o    /dev/rmt0
            $find    /etc -name "passwd*"    -exec grep    "cnscn"    {}    \;    #看是否存在cnscn用户
$find . -name "yao*"    | xargs file
            $find    . -name "yao*"    |    xargs    echo     "" > /tmp/core.log
            $find    . -name "yao*"    | xargs    chmod    o-w            ======================================================            find    -name april*                        在当前目录下查找以april开始的文件
find    -name    april*    fprint file          在当前目录下查找以april开始的文件,并把结果输出到file中
find    -name ap* -o -name may*    查找以ap或may开头的文件
find    /mnt    -name tom.txt    -ftype vfat    在/mnt下查找名称为tom.txt且文件系统类型为vfat的文件
find    /mnt    -name t.txt ! -ftype vfat     在/mnt下查找名称为tom.txt且文件系统类型不为vfat的文件
find    /tmp    -name wa* -type l             在/tmp下查找名为wa开头且类型为符号链接的文件
find    /home    -mtime    -2                   在/home下查最近两天内改动过的文件
find /home     -atime -1                    查1天之内被存取过的文件
find /home -mmin     +60                    在/home下查60分钟前改动过的文件
find /home    -amin    +30                    查最近30分钟前被存取过的文件
find /home    -newer    tmp.txt               在/home下查更新时间比tmp.txt近的文件或目录
find /home    -anewer    tmp.txt              在/home下查存取时间比tmp.txt近的文件或目录
find    /home    -used    -2                    列出文件或目录被改动过之后,在2日内被存取过的文件或目录
find    /home    -user cnscn                  列出/home目录内属于用户cnscn的文件或目录
find    /home    -uid    +501                   列出/home目录内用户的识别码大于501的文件或目录
find    /home    -group    cnscn                列出/home内组为cnscn的文件或目录
find    /home    -gid 501                     列出/home内组id为501的文件或目录
find    /home    -nouser                      列出/home内不属于本地用户的文件或目录
find    /home    -nogroup                     列出/home内不属于本地组的文件或目录
find    /home     -name tmp.txt     -maxdepth    4    列出/home内的tmp.txt 查时深度最多为3层
find    /home    -name tmp.txt    -mindepth    3    从第2层开始查
find    /home    -empty                       查找大小为0的文件或空目录
find    /home    -size    +512k                 查大于512k的文件
find    /home    -size    -512k                 查小于512k的文件
find    /home    -links    +2                   查硬连接数大于2的文件或目录
find    /home    -perm    0700                  查权限为700的文件或目录
find    /tmp    -name tmp.txt    -exec cat {} \;
            find    /tmp    -name    tmp.txt    -ok    rm {} \;            find     /    -amin     -10         # 查找在系统中最后10分钟访问的文件
find     /    -atime    -2           # 查找在系统中最后48小时访问的文件
find     /    -empty                # 查找在系统中为空的文件或者文件夹
find     /    -group    cat          # 查找在系统中属于 groupcat的文件
find     /    -mmin    -5           # 查找在系统中最后5分钟里修改过的文件
find     /    -mtime    -1          #查找在系统中最后24小时里修改过的文件
find     /    -nouser               #查找在系统中属于作废用户的文件
find     /    -user     fred         #查找在系统中属于FRED这个用户的文件

            查当前目录下的所有普通文件
--------------------------------------------------------------------------------            # find . -type f -exec ls -l {} \;
-rw-r--r--      1 root       root          34928 2003-02-25    ./conf/httpd.conf
-rw-r--r--      1 root       root          12959 2003-02-25    ./conf/magic
-rw-r--r--      1 root       root            180 2003-02-25    ./conf.d/README
查当前目录下的所有普通文件,并在- e x e c选项中使用ls -l命令将它们列出           
=================================================
在/ l o g s目录中查找更改时间在5日以前的文件并删除它们:
$ find logs -type f -mtime +5 -exec    -ok    rm {} \;           
            =================================================
查询当天修改过的文件
[root@book class]# find    ./    -mtime    -1    -type f    -exec    ls -l    {} \;           
            =================================================
查询文件并询问是否要显示
[root@book class]# find    ./    -mtime    -1    -type f    -ok    ls -l    {} \; 
            < ls ... ./classDB.inc.php > ? y
-rw-r--r--      1 cnscn      cnscn         13709    1月 12 12:22 ./classDB.inc.php
            [root@book class]# find    ./    -mtime    -1    -type f    -ok    ls -l    {} \; 
            < ls ... ./classDB.inc.php > ? n
            [root@book class]#            =================================================
查询并交给awk去处理
[root@book class]# who    |    awk    '{print $1"\t"$2}'
            cnscn     pts/0            =================================================
            awk---grep---sed            [root@book class]# df    -k |    awk '{print $1}' |    grep    -v    'none' |    sed    s"/\/dev\///g"
文件系统
sda2
            sda1
            [root@book class]# df    -k |    awk '{print $1}' |    grep    -v    'none'
文件系统
/dev/sda2
            /dev/sda1


            1)在/tmp中查找所有的*.h,并在这些文件中查找“SYSCALL_VECTOR",最后打印出所有包含"SYSCALL_VECTOR"的文件名            A) find    /tmp    -name    "*.h"    | xargs    -n50    grep SYSCALL_VECTOR
            B) grep    SYSCALL_VECTOR    /tmp/*.h | cut     -d':'    -f1| uniq > filename
            C) find    /tmp    -name "*.h"    -exec grep "SYSCALL_VECTOR"    {}    \; -print           
            2)find / -name filename -exec rm -rf {} \;
                 find / -name filename -ok rm -rf {} \;           
            3)比如要查找磁盘中大于3M的文件:
find . -size +3000k -exec ls -ld {} ;           
            4)将find出来的东西拷到另一个地方
find *.c -exec cp '{}' /tmp ';'            如果有特殊文件,可以用cpio,也可以用这样的语法:
find dir -name filename -print | cpio -pdv newdir           
            6)查找2004-11-30 16:36:37时更改过的文件
# A=`find ./ -name "*php"` |    ls -l --full-time $A 2>/dev/null | grep "2004-11-30 16:36:37           

二、linux下find命令的用法

1. 基本用法:
      find / -name 文件名                 find ver1.d ver2.d -name '*.c' -print    查找ver1.d,ver2.d *.c文件并打印     find . -type d -print 从当前目录查找,仅查找目录,找到后,打印路径名。可用于打印目录结构。
2. 无错误查找:
      find / -name access_log 2 >/dev/null
            3. 按尺寸查找:
      find / -size 1500c (查找1,500字节大小的文件,c表示字节)
      find / -size +1500c (查找大于1,500字节大小的文件,+表示大于)   
                  find / -size +1500c (查找小于1,500字节大小的文件,-表示小于)   
4. 按时间:
      find / -amin n 最后n分钟
      find / -atime n 最后n天
      find / -cmin n 最后n分钟改变状态
      find / -ctime n 最后n天改变状态
5. 其它:
      find / -empty 空白文件、空白文件夹、没有子目录的文件夹
      find / -false 查找系统中总是错误的文件
      find / -fstype type 找存在于指定文件系统的文件,如type为ext2
                  find / -gid n 组id为n的文件
      find / -group gname 组名为gname的文件
      find / -depth n 在某层指定目录中优先查找文件内容
      find / -maxdepth levels 在某个层次目录中按递减方式查找
6. 逻辑
      -and 条件与 -or 条件或
7. 查找字符串
      find . -name '*.html' -exec grep 'mailto:'{}

posted @ 2012-11-29 15:45 zyskm 阅读(278) | 评论 (0)编辑 收藏

linux上ln命令详细说明

ln是linux中又一个非常重要命令,它的功能是为某一个文件在另外一个位置建立一个同不的链接,这个命令最常用的参数是-s,具体用法是:ln –s 源文件 目标文件。
  当我们需要在不同的目录,用到相同的文件时,我们不需要在每一个需要的目录下都放一个必须相同的文件,我们只要在某个固定的目录,放上该文件,然后在 其它的目录下用ln命令链接(link)它就可以,不必重复的占用磁盘空间。例如:ln –s /bin/less /usr/local/bin/less
  -s 是代号(symbolic)的意思。
  这里有两点要注意:第一,ln命令会保持每一处链接文件的同步性,也就是说,不论你改动了哪一处,其它的文件都会发生相同的变化;第二,ln的链接又 软链接和硬链接两种,软链接就是ln –s ** **,它只会在你选定的位置上生成一个文件的镜像,不会占用磁盘空间,硬链接ln ** **,没有参数-s, 它会在你选定的位置上生成一个和源文件大小相同的文件,无论是软链接还是硬链接,文件都保持同步变化。
  如果你用ls察看一个目录时,发现有的文件后面有一个@的符号,那就是一个用ln命令生成的文件,用ls –l命令去察看,就可以看到显示的link的路径了。
  指令详细说明
  指令名称 : ln
  使用权限 : 所有使用者
  使用方式 : ln [options] source dist,其中 option 的格式为 :
  [-bdfinsvF] [-S backup-suffix] [-V {numbered,existing,simple}]
  [--help] [--version] [--]
  说明 : Linux/Unix 档案系统中,有所谓的连结(link),我们可以将其视为档案的别名,而连结又可分为两种 : 硬连结(hard link)与软连结(symbolic link),硬连结的意思是一个档案可以有多个名称,而软连结的方式则是产生一个特殊的档案,该档案的内容是指向另一个档案的位置。硬连结是存在同一个档 案系统中,而软连结却可以跨越不同的档案系统。
  ln source dist 是产生一个连结(dist)到 source,至于使用硬连结或软链结则由参数决定。
  不论是硬连结或软链结都不会将原本的档案复制一份,只会占用非常少量的磁碟空间。
  -f : 链结时先将与 dist 同档名的档案删除
  -d : 允许系统管理者硬链结自己的目录
  -i : 在删除与 dist 同档名的档案时先进行询问
  -n : 在进行软连结时,将 dist 视为一般的档案
  -s : 进行软链结(symbolic link)
  -v : 在连结之前显示其档名
  -b : 将在链结时会被覆写或删除的档案进行备份
  -S SUFFIX : 将备份的档案都加上 SUFFIX 的字尾
  -V METHOD : 指定备份的方式
  --help : 显示辅助说明
  --version : 显示版本
  范例 :
  将档案 yy 产生一个 symbolic link : zz
  ln -s yy zz
  将档案 yy 产生一个 hard link : zz
  ln yy xx

posted @ 2012-11-29 14:31 zyskm 阅读(190) | 评论 (0)编辑 收藏

Linux的变量

1.Linux的变量种类

  按变量的生存周期来划分,Linux变量可分为两类:
  1.1 永久的:需要修改配置文件,变量永久生效。

  1.2 临时的:使用export命令声明即可,变量在关闭shell时失效。

Linux 的变量可分为两类:环境变量和本地变量
 
环境变量,或者称为全局变量,存在与所有的shell 中,在你登陆系统的时候就已经有了相应的系统定义的环境变量了。Linux 的环境变量具有继承性,即子shell 会继承父shell 的环境变量。
 
本地变量,当前shell 中的变量,很显然本地变量中肯定包含环境变量。Linux 的本地变量的非环境变量不具备继承性。
 
Linux 中环境变量的文件
 
    当你进入系统的时候,linux 就会为你读入系统的环境变量,这些环境变量存放在什么地方,那就是环境变量的文件中。Linux 中有很多记载环境变量的文件,它们被系统读入是按照一定的顺序的。
 
1.    /etc/profile :
 
此文件为系统的环境变量,它为每个用户设置环境信息,当用户第一次登录时,该文件被执行。

  2.设置变量的三种方法

  2.1 在/etc/profile文件中添加变量【对所有用户生效(永久的)】

  用VI在文件/etc/profile文件中增加变量,该变量将会对Linux下所有用户有效,并且是“永久的”。

  例如:编辑/etc/profile文件,添加CLASSPATH变量

  # vi /etc/profile

  export CLASSPATH=./JAVA_HOME/lib;$JAVA_HOME/jre/lib

  注:修改文件后要想马上生效还要运行# source /etc/profile不然只能在下次重进此用户时生效。

  2.2 在用户目录下的.bash_profile文件中增加变量【对单一用户生效(永久的)】

  用VI在用户目录下的.bash_profile文件中增加变量,改变量仅会对当前用户有效,并且是“永久的”。

  例如:编辑guok用户目录(/home/guok)下的.bash_profile

  $ vi /home/guok/.bash.profile

  添加如下内容:

  export CLASSPATH=./JAVA_HOME/lib;$JAVA_HOME/jre/lib

  注:修改文件后要想马上生效还要运行$ source /home/guok/.bash_profile不然只能在下次重进此用户时生效。

  2.3 直接运行export命令定义变量【只对当前shell(BASH)有效(临时的)】

  在shell的命令行下直接使用[export 变量名=变量值]
定义变量,该变量只在当前的shell(BASH)或其子shell(BASH)下是有效的,shell关闭了,变量也就失效了,再打开新shell时就没有这个变量,需要使用的话还需要重新定义。

  3.环境变量的查看

  3.1 使用echo命令查看单个环境变量。例如:

  echo $PATH

  3.2 使用env查看所有环境变量。例如:

  env

  3.3 使用set查看所有本地定义的环境变量。

  unset可以删除指定的环境变量。

  4.常用的环境变量

  PATH 决定了shell将到哪些目录中寻找命令或程序

  HOME 当前用户主目录

  HISTSIZE 历史记录数

  LOGNAME 当前用户的登录名

  HOSTNAME 指主机的名称

  SHELL   当前用户Shell类型

  LANGUGE  语言相关的环境变量,多语言可以修改此环境变量

  MAIL   当前用户的邮件存放目录

  PS1   基本提示符,对于root用户是#,对于普通用户是$

posted @ 2012-11-29 14:11 zyskm 阅读(437) | 评论 (0)编辑 收藏

linux chmod,chown

指令名称 : chmod
使用权限 : 所有使用者
 
使用方式 : chmod [-cfvR] [--help] [--version] mode file...
 
说明 : Linux/Unix 的档案存取权限分为三级 : 档案拥有者、群组、其他。利用 chmod 可以控制档案如何被他人所存取。
只能文件属主或特权用户才能使用该功能来改变文件存取模式。mode可以是数字形式或以who opcode permission形式表示。who是可选的,默认是a(所有用户)。只能选择一个opcode(操作码)。可指定多个mode,以逗号分开。

options:

-c,--changes
只输出被改变文件的信息

-f,--silent,--quiet
当chmod不能改变文件模式时,不通知文件的用户

--help
输出帮助信息。

-R,--recursive
可递归遍历子目录,把修改应到目录下所有文件和子目录

--reference=filename
参照filename的权限来设置权限

-v,--verbose
无论修改是否成功,输出每个文件的信息

--version
输出版本信息。

who

u
用户

g

o
其它

a
所有用户(默认)

opcode

+
增加权限

-
删除权限

=
重新分配权限

permission

r

w

x
执行

s
设置用户(或组)的ID号

t
设置粘着位(sticky bit),防止文件或目录被非属主删除

u
用户的当前权限

g
组的当前权限

o
其他用户的当前权限

作为选择,我们多数用三位八进制数字的形式来表示权限,第一位指定属主的权限,第二位指定组权限,第三位指定其他用户的权限,每位通过4(读)、2(写)、1(执行)三种数值的和来确定权限。如6(4+2)代表有读写权,7(4+2+1)有读、写和执行的权限。

还可设置第四位,它位于三位权限序列的前面,第四位数字取值是4,2,1,代表意思如下:

4,执行时设置用户ID,用于授权给基于文件属主的进程,而不是给创建此进程的用户。

2,执行时设置用户组ID,用于授权给基于文件所在组的进程,而不是基于创建此进程的用户。

1,设置粘着位。

实例:

$ chmod u+x file                      给file的属主增加执行权限
$ chmod 751 file                      给file的属主分配读、写、执行(7)的权限,给file的所在组分配读、执行(5)的权限,给其他用户分配执行(1)的权限
$ chmod u=rwx,g=rx,o=x file      上例的另一种形式
$ chmod =r file                     为所有用户分配读权限
$ chmod 444 file                   同上例
$ chmod a-wx,a+r   file          同上例
$ chmod -R u+r directory           递归地给directory目录下所有文件和子目录的属主分配读的权限
$ chmod 4755                            设置用ID,给属主分配读、写和执行权限,给组和其他用户分配读、执行的权限。


指令名称 : chown
 使用权限 : root
 
使用方式 : chown[-cfhvR] [--help] [--version] user[:group] file...
 
说明 : Linux/Unix 是多人多工作业系统,所有的档案皆有拥有者。利用 chown 可以将档案的拥有者加以改变。一般来说,这个指令只有是由系统管理者(root)所使用,一般使用者没有权限可以改变别人的档案拥有者,也没有权限可以自己的档案拥有者改设为别人。只有系统管理者(root)才有这样的权限。
 

posted @ 2012-11-29 14:02 zyskm 阅读(297) | 评论 (0)编辑 收藏

eclipse中xsd的验证问题cvc-complex-type error with xsd

基于spring开发了个自定义标签,功能测试正常,在myeclipse中提示编译错误:
Multiple annotations found at this line:
    - cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'fw:annotation-handler'.
    - schema_reference.4: Failed to read schema document 'http://www.300.cn/schema/annotation-handler.xsd', because 1) could not find the
     document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
这个问题在以前改动struts配置文件的时候也出现过。在引入一些第三方jar容易出现这个问题。
虽然不影响使用,但是看着挺讨厌的,找了一下解决方法。
菜单-->windows-->prefreneces 找到XML Catalog,在User Specified Entries添加xsd文件
有两个地方要注意:
1.Key type设置为Schema location;
2.key 设置虚拟xsd地址,即
xsi:schemaLocation=" http://www.springframework.org/schema/task
                         http://www.springframework.org/schema/task/spring-task-3.0.xsd“
名称对后边的这一个。

posted @ 2012-06-27 11:09 zyskm 阅读(2857) | 评论 (0)编辑 收藏

java不是那么风光了

自从搬到东边住以后就很少去海淀图书城了,因为想参加11月的软考,端午去海图找本考试大纲。
前几年去海图的时候,java方面的图书都放在最显眼的地方,能占好几排书架,现在已经被andriod、ios取代。找了一圈才在一个不起眼的角落找到java系列图书。c/c++这样的书倒不见减少,比印象中还有增加。
从书市上看java最风光的时候已经过去了,一直做java方面的开发,对这方面的变化不敏感,还是卖书的对市场感受更直接。
各领风骚好几年。

posted @ 2012-06-26 09:50 zyskm 阅读(1405) | 评论 (4)编辑 收藏

问题分析与决策(兰德)

这几天抽空看了本《问题分析与决策》,兰德公司出版的,就是那个预言中国将出兵朝鲜的公司。挺好的一本书,不知道为什么中文版的特别少,找了半天。
老外做研究的风格,很少那种大而无当的空话,对问题分析的过程和分析者的心理活动做了大量研究工作。
我做过一段时间的系统分析工作,书中有些观点让人看起来心有戚戚焉,还有部分观点是自己没想到的,读后很是能解惑。

做些简单摘录

很多人采用的处理问题与决策的办法,根本没有多大用处,甚至完全没有用处。

引言
兰德提出这种问题分析方法的思路,从一个公司的某一个问题着手,追溯到解决这一问题的程序,仔细剖视每一步骤中的思想过程。
根据这些研究得出了很多概念和方法,认为问题分析与决策时管理上的行为,必须自觉和有系统的去做。
而且必要的话,还应该记录下来。

分析问题是一项依照逻辑体系而进行的程序,首先是确定问题,然后是经过分析以及寻求原因,最后做决定。
每个阶段包括若干基本的概念,其中一项基本概念是,一个问题乃是一件事“应该怎么样”和“事实上是怎么样的”两者之间的偏差。
另一项概念是,这种偏差是由于某一种“变化”二造成的。除非先把这一变化准确的予以确定,否则一切纠正这一偏差的措施都只是揣测而已。

概念与方法
问题分析的两个主要概念:
1.每个问题都是标准的预期效果所发生的偏差;
2.某种变化是造成这一问题的根本原因。

分析问题的七项基本概念
1.有标准;
2.问题就是情况与标准之间的偏差
3.偏差要准确的认定
4.分析问题的独特性,受影响和没受影响部分各有什么特点,区分开来;
5.只考虑与特殊变化有关的情况,通过界定问题范围找出原因。
6.造成偏差的原因是从分析问题时发现的变化中推导出来的 。
7.最可能造成偏差的原因,是能解释界定范围内一切事实的那一项原因。

如何界定一个问题

1.什么;2时间;3.地点4.幅度
如何寻求特点与变化
任何问题发生的原因,乃是一种变化;这种变化的影响是有限度的,只在某些地方有影响,在其他地方没有影响。
这种变化,只存在于特定的范围之内,或者只发生与那些可以区分出问题的“是”的一面某些因素上。
因此,要追究什么样的变化会发生某一种影响,最有效的方法是只寻求那些仅存在于界定问题时所发现的各项特点的变化。
我们要找出来把事物区分开来的因素,分析问题的人必须从事物的不同点去思考。
(么东西出了问题,不是什么出了问题,减小范围)
发生变化的线索就在,区分“是”与“不是”的特点中。
能看出特点与变化的能力是智慧的主要表现之一,在问题分析上是非常重要的。
一个问题的形成可能受许多因素的影响,但是真正动摇了事态均衡而引发问题的却只有一种变化。
事先不界定问题和研求特点,一发现某项变化立即断定这就是问题的原因所在是很危险的。


决策分析
1.订立决策的目标;
2.依据重要性将目标分类;
3.拟定可供选择的措施;
4.把各种可行的办法与目标加以对照衡量;
5.选择最好的办法作为暂时决策;
6.研究决策是否会有不良影响;
7.同时采取防止不良后果的措施。

posted @ 2012-06-20 10:59 zyskm 阅读(1730) | 评论 (0)编辑 收藏

工作流的价值

之前做过一版工作流引擎,自己开发的。这段时间又以jbpm为内核做了一版流程系统,有些思考就记录下来。
有一句话说的好,如果你手里有一把锤子你就看什么都像钉子。做流程系统的时候也遇到这类现象,因为对流程系统的不熟悉,在开发过程中就想到处都用工作流来处理问题。
其实引入一个新的东西,一定要先搞明白的它的适用场景,有什么价值。把握了这点后结合具体场景,就能很好的使用,而不会乱用。
一、工作流适用场景
以下两种情况需要引入流程系统
1.分散系统整合(企业应用集成)
2.简化业务系统的开发;
工作流的价值
1.业务流程独立化;
2.优化改进流程更容易;
3.提供统一的监控页面。
Ⅰ 、相对于分散系统,提供了统一的操作和监控页面。对用户更友好,过程可监控,业务规则更明确。
1.业务流程独立化,业务规则不仅仅存在与工作人员的头脑中。
2.提供了统一的监控界面,实现业务过程可监控;
3.有明确的规则,可以监控运行情况,为流程的优化提供了便利;
4.对用户更友好;
Ⅱ 、相对于传统业务系统方式
1.业务流程独立化,业务规则不会淹没于业务系统代码中。避免业务系统开发完成后再次改动成本高的情况。
2.提供了统一的监控界面,实现业务过程可监控;原业务系统提供的报表对环节执行时间可能信息不足,一般只是简单反应状态变化。
3.有明确的规则,可以监控运行情况,为流程的优化提供了便利;
4.对于工作人员来讲,这些改进其实是透明的,从用户体验的角度没有什么变化。
 所以对原业务系统的用户来讲,变化不大。引入流程系统更多的是为了监控和优化流程的方便,是从管理的角度考虑问题。
从流程系统提供的待办事项列表进行操作,还是从业务系统的功能菜单进行操作,哪个更友好是UE设计的问题,跟流程系统无关。
业务系统功能菜单的划分可能相对于待办事项列表更直观、定位更准确。(见下图红色箭头对两种方式的表示)
考虑到业务流程的复杂性,对于企业信息化系统引入流程系统可以便于优化流程,对于成熟的业务系统如财务软件引入流程系统完全没有必要。
 
补充说明:
1.当前任务列表方式,需要用户不停的查看有没有新任务到来;优点是在一个页面可以看到全部待办事项。
2.业务系统功能菜单方式,需要用户不停的查询工作进展并作出处理。优点是任务类型划分更明确;
二、业务系统接入方式
1.在jsp页面增加环节信息(环节编号,流程编号...);
2.业务系统aciton不变;
3.在业务系统action完成操作后,流程拦截器处理流程变化并记录到数据库;
4.流程监控页面和待办事项列表,不断从流程数据库查询。
5.对于专业性比价强的的状态值还是在业务系统维护,避免流程系统压力过大。在需要监控改进的业务点交由流程系统调度,其它部分还是由业务系统处理。


--------------------------------------
下边是对struts项目接入流程系统的一个分析
1.业务系统jsp,action调用关系

2.采用拦截器在业务系统action执行完成后,进行流程驱动,并在下一个jsp页面注入流程信息。


主要逻辑都在beforeResult()方法中。
3.数据结构

数据结构说明:
1.对于通用的流程数据可以在beforeResult()方法自动嵌入,为考虑交互效果在jsp自行设置流程信息;
2.jsp页面流程数据应该包括:
1.nodeName
节点名称,环节在流程定义中的名称;
2.transitionNames
流向名称列表,需要作出选择的列表。
3.entityId
实体id,用于查询流程实例ID。
3.在action执行完成后驱动流程所需要的数据:
1.definitionId
流程定义,说明是新启动一个流程。
2.nodeName
节点名称,根据流程实例ID和节点名称查询任务ID,每个节点只能是单任务的,否则jsp页面无法提供taskId.
3.transitionName
流向名称,根据流向选择流程下一步跳转的节点。串行节点不用transitionName 可为空。
4.entityId
实体id,查询流程实例ID用。
4.对与工作流无关的action实行过滤,不做处理
两种过滤方式:
1.在action方法加注解;
2.在数据结构中增加数据项标记。
5.对与工作流无关的jsp页面,不使用工作流tag即可。
 
-----------------------------
上边是我一开始的想法,后来和同事讨论后又做了些调整。编辑web文字比较麻烦,就不合在一起了。
1.对执行业务操作的action和进入jsp页面的初始化action进行分类;

2.参数传递过程补充说明

一个分为三步
倒着说
第三步,功能页面jsp在提交参数时需附加(节点名称、流向名称、工单编号),流程引擎才能驱动流程;
第二步,要能够向第三步提供数据,jsp页面必须包含(节点名称、流向名称列表、工单编号),这些数据有两个来源:1.收到在jsp页面写入;2.从第一步接收。
第一步,有同事建议,提供节点和资源路径的关系表,通过资源路径查找节点名称。减少流程系统对业务系统的侵入。
 
 ----------------------------------
上传的时候图片丢了,重新补一下。
 

posted @ 2012-06-19 16:01 zyskm 阅读(1198) | 评论 (0)编辑 收藏

Restful架构

 今天抽空整理些有关rest方面的理论。主要参考了几篇网上的文章,做了些整理,原文见附录。

一、起源

越来越多的人开始意识到,网站即软件,而且是一种新型的软件。
这种"互联网软件"采用客户端/服务器模式,建立在分布式体系上,通过互联网通信,具有高延时(high latency)、高并发等特点。
网站开发,完全可以采用软件开发的模式。但是传统上,软件和网络是两个不同的领域,很少有交集;软件开发主要针对单机环境,网络则主要研究系统之间的通信。互联网的兴起,使得这两个领域开始融合,现在我们必须考虑,如何开发在互联网环境中使用的软件。
RESTful架构,就是一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
 

二、名称

Fielding将他对互联网软件的架构原则,定名为REST,即Representational State Transfer的缩写。我对这个词组的翻译是"表现层状态转化"。

如果一个架构符合REST原则,就称它为RESTful架构。

要理解RESTful架构,最好的方法就是去理解Representational State Transfer这个词组到底是什么意思,它的每一个词代表了什么涵义。如果你把这个名称搞懂了,也就不难体会REST是一种什么样的设计。

三、资源(Resources)

REST的名称"表现层状态转化"中,省略了主语。"表现层"其实指的是"资源"(Resources)的"表现层"。

所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。你可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。

所谓"上网",就是与互联网上一系列的"资源"互动,调用它的URI。

四、表现层(Representation)

"资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表现层"(Representation)。

比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现。

URI只代表资源的实体,不代表它的形式。严格地说,有些网址最后的".html"后缀名是不必要的,因为这个后缀名表示格式,属于"表现层"范畴,而URI应该只代表"资源"的位置。它的具体表现形式,应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对"表现层"的描述。

五、状态转化(State Transfer)

访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。

互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer)。而这种转化是建立在表现层之上的,所以就是"表现层状态转化"。

客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。

六、综述

综合上面的解释,我们总结一下什么是RESTful架构:

  (1)每一个URI代表一种资源;

  (2)客户端和服务器之间,传递这种资源的某种表现层;

  (3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。

 

REST关键原则

一个简单扼要的定义:REST定义了应该如何正确地使用Web标准,例如HTTP和URI。如果你在设计应用程序时能坚持REST原则,那就预示着你将会得到一个使用了优质Web架构(这将让你受益)的系统。总之,五条关键原则列举如下:

  • 为所有“事物”定义ID
  • 将所有事物链接在一起
  • 使用标准方法
  • 资源多重表述
  • 无状态通信

 

为所有“事物”定义ID

在这里我使用了“事物”来代替更正式准确的术语“资源”,因为一条如此简单的原则,不应该被淹没在术语当中。思考一下人们构建的系统,通常会找到一系列值得被标识的关键抽象。每个事物都应该是可标识的,都应该拥有一个明显的ID——在Web中,代表ID的统一概念是:URI。URI构成了一个全局命名空间,使用URI标识你的关键资源意味着它们获得了一个唯一、全局的ID。


值得被URI标识的事物——资源——要比数据库记录抽象的多。标识所有值得标识的事物,领会这个观念可以进一步引导你创造出在传统的应用程序设计中不常见的资源:一个流程或者流程步骤、一次销售、一次谈判、一份报价请求——这都是应该被标识的事物的示例。

将所有事物链接在一起

接下来要讨论的原则有一个有点令人害怕的正式描述:“超媒体被当作应用状态引擎(Hypermedia as the engine of application state)”,有时简写为HATEOAS。(严格地说,这不是我说的。)这个描述的核心是超媒体概念,换句话说:是链接的思想。链接是我们在HTML中常见的概念,但是它的用处绝不局限于此(用于人们网络浏览)。


使用标准方法

在前两个原则的讨论中暗含着一个假设:接收URI的应用程序可以通过URI明确地一些有意义的事情。如果你在公共汽车上看到一个URI,你可以将它输入浏览器的地址栏中并回车——但是你的浏览器如何知道需要对这个URI做些什么呢?

它知道如何去处理URI的原因在于所有的资源都支持同样的接口,一套同样的方法(只要你乐意,也可以称为操作)集合。在HTTP中这被叫做动词(verb),除了两个大家熟知的(GET和POST)之外,标准方法集合中还包含PUT、DELETE、HEAD和OPTIONS。这些方法的含义连同行为许诺都一起定义在HTTP规范之中。


资源多重表述

在实践中,资源多重表述还有着其它重要的好处:如果你为你的资源提供HTML和XML两种表述方式,那这些资源不仅可以被你的应用所用,还可以被任意标准Web浏览器所用——也就是说,你的应用信息可以被所有会使用Web的人获取到。

无状态通信

首先,需要着重强调的是,虽然REST包含无状态性(statelessness)的观念,但这并不是说暴露功能的应用不能有状态——
事实上,在大部分情况下这会导致整个做法没有任何用处。REST要求状态要么被放入资源状态中,要么保存在客户端上。
或者换句话说,服务器端不能保持除了单次请求之外的,任何与其通信的客户端的通信状态。这样做的最直接的理由就是可伸缩性—— 如果服务器需要保持客户端状态,那么大量的客户端交互会严重影响服务器的内存可用空间(footprint)。(注意,要做到无状态通信往往需要需要一些重新设计——不能简单地将一些session状态绑缚在URI上,然后就宣称这个应用是RESTful。)

但除此以外,其它方面可能显得更为重要:无状态约束使服务器的变化对客户端是不可见的,因为在两次连续的请求中,客户端并不依赖于同一台服务器。一个客户端从某台服务器上收到一份包含链接的文档,当它要做一些处理时,这台服务器宕掉了,可能是硬盘坏掉而被拿去修理,可能是软件需要升级重启——如果这个客户端访问了从这台服务器接收的链接,它不会察觉到后台的服务器已经改变了。

 

REST风格的一个“化身”便是HTTP(以及一套相关的一套标准,比如URI)。

附录:
1.深入浅出REST http://www.infoq.com/cn/articles/rest-introduction
2.理解Restful 架构 http://www.ruanyifeng.com/blog/2011/09/restful.html
3.Rest和soap比较 http://www.infoq.com/cn/articles/rest-soap-when-to-use-each
4.Rest和Rpc比较 http://xinklabi.iteye.com/blog/807220

 

posted @ 2012-06-19 15:44 zyskm 阅读(3114) | 评论 (3)编辑 收藏

spring Scheduled 设置(转载)

定时程序时间格式,原文见http://blog.csdn.net/remote_roamer/article/details/6573173

一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素。

按顺序依次为

秒(0~59)

分钟(0~59)

小时(0~23)

天(月)(0~31,但是你需要考虑你月的天数)

月(0~11)

天(星期)(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT)

7.年份(1970-2099)

其中每个元素可以是一个值(如6),一个连续区间(9-12),一个间隔时间(8-18/4)(/表示每隔4小时),一个列表(1,3,5),通配符。由于"月份中的日期"和"星期中的日期"这两个元素互斥的,必须要对其中一个设置?.

0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
0 0/30 9-17 * * ?   朝九晚五工作时间内每半小时
0 0 12 ? * WED 表示每个星期三中午12点
"0 0 12 * * ?" 每天中午12点触发 
"0 15 10 ? * *" 每天上午10:15触发 
"0 15 10 * * ?" 每天上午10:15触发 
"0 15 10 * * ? *" 每天上午10:15触发 
"0 15 10 * * ? 2005" 2005年的每天上午10:15触发 
"0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发 
"0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发 
"0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 
"0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发 
"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发 
"0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发 
"0 15 10 15 * ?" 每月15日上午10:15触发 
"0 15 10 L * ?" 每月最后一日的上午10:15触发 
"0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发 
"0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发 
"0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发

有些子表达式能包含一些范围或列表

例如:子表达式(天(星期) )可以为 “MON-FRI”,“MON,WED,FRI”,“MON-WED,SAT”

“*”字符代表所有可能的值

因此,“*”在子表达式( )里表示每个月的含义,“*”在子表达式(天(星期) )表示星期的每一天

 

“/”字符用来指定数值的增量

例如:在子表达式(分钟)里的“0/15”表示从第0分钟开始,每15分钟

         在子表达式(分钟)里的“3/20”表示从第3分钟开始,每20分钟(它和“3,23,43”)的含义一样


“?”字符仅被用于天(月)和天(星期)两个子表达式,表示不指定值

当2个子表达式其中之一被指定了值以后,为了避免冲突,需要将另一个子表达式的值设为“?”

 

“L” 字符仅被用于天(月)和天(星期)两个子表达式,它是单词“last”的缩写

但是它在两个子表达式里的含义是不同的。

在天(月)子表达式中,“L”表示一个月的最后一天

在天(星期)自表达式中,“L”表示一个星期的最后一天,也就是SAT

如果在“L”前有具体的内容,它就具有其他的含义了

例如:“6L”表示这个月的倒数第6天,“FRIL”表示这个月的最一个星期五

注意:在使用“L”参数时,不要指定列表或范围,因为这会导致问题

 

 

字段   允许值   允许的特殊字符
  0-59   , - * /
  0-59   , - * /
小时   0-23   , - * /
日期   1-31   , - * ? / L W C
月份   1-12 或者 JAN-DEC   , - * /
星期   1-7 或者 SUN-SAT   , - * ? / L C #
年(可选)   留空, 1970-2099   , - * /

posted @ 2012-04-16 14:21 zyskm 阅读(5878) | 评论 (2)编辑 收藏

spring3系列 二、Spring配置项解释说明

这篇也是转载,改了中间部分内。

在基于注解方式配置
Spring的配置文件中,你可能会见到<context:annotation-config/>这样一条配置,他的作用是式地向 Spring 容器注册

AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor

PersistenceAnnotationBeanPostProcessor 以及 RequiredAnnotationBeanPostProcessor  4 BeanPostProcessor

注册这4 BeanPostProcessor的作用,就是为了你的系统能够识别相应的注解。

例如:

如果你想使用@Autowired注解,那么就必须事先在 Spring 容器中声明 AutowiredAnnotationBeanPostProcessor Bean。传统声明方式如下:

  1. <bean class="org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor "/> 

如果想使用@ Resource @ PostConstruct@ PreDestroy等注解就必须声明CommonAnnotationBeanPostProcessor

如果想使用@PersistenceContext注解,就必须声明PersistenceAnnotationBeanPostProcessorBean

如果想使用 @Required的注解,就必须声明RequiredAnnotationBeanPostProcessorBean。同样,传统的声明方式如下:

  1. <bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/> 

一般来说,这些注解我们还是比较常用,尤其是Antowired的注解,在自动注入的时候更是经常使用,所以如果总是需要按照传统的方式一条一条配置显得有些繁琐和没有必要,于是spring给我们提供<context:annotation-config/>的简化配置方式,自动帮你完成声明。

   不过,呵呵,我们使用注解一般都会配置扫描包路径选项

  1. <context:component-scan base-package=”XX.XX”/> 

    该配置项其实也包含了自动注入上述processor的功能,因此当使用 <context:component-scan/> 后,就可以将 <context:annotation-config/> 移除了。

本文转载:http://mushiqianmeng.blog.51cto.com/3970029/723880

posted @ 2012-04-13 15:14 zyskm 阅读(2565) | 评论 (4)编辑 收藏

spring3系列 一、框架结构

有一段时间没有关注spring了,spring2.5就蛮够用的,spring3出来后一直没怎么关注。
这几天抽空关注一下。干咱这行的还是要紧跟时代变化啊。
下边这些内容是转载51cto的一篇文章。

1、项目结构与构建变化

解压后的立即发现,Spring 3.0的项目结构已经发现了巨大变化:

1、Spring3采用多项目结构源码组织,不再是以前的单一方式,共26个项目,差不多每个项目对于一个分发的jar包,不过有些项目是空的,或者是为了构建而设。

2、不再提供完整打包文件spring.jar,而是20个jar(或称bundle),一方面应该也是向osgi靠拢。

Spring 3.0的readme中说道:

Note that this release does not contain a 'spring.jar' file anymore, in contrast to previous Spring generations. Furthermore, the jar file names follow bundle repository conventions now.

(51CTO编辑快译:与之前的Spring版本相反,此次发布不再包括spring.jar文件了。新版本中的jar文件命名由bundle版本库的规则所决定。)

3、采用Ivy为主构建方式,当然仍然有Maven,项目结构由Maven管理。另外没有打包全部的依赖包了,整个下载包比2.5的小了近一半

4、Spring3已经完全采用Java5/6开发和编译构建,因此应该是不再支持Java1.4及更早版本了

2、框架结构的变化

框架结构的架构图也进一步演变了,不再是原来那个简单的方块图:

Spring 3结构图 

Spring3架构图

跟原来的相比,DAO、ORM、JEE等模块被划归到了一起,成为“数据访问/集成”部分,Web层突出了自己的MVC(Servlet)和Portlet,核心容器增加了表达式语言。另外,对测试的支持也放到了整个架构中来了。所以整个框架重新划分成了五部分。

因此,典型的全应用场景也相应变化,并提示使用自家的Tomcat:

使用自家的Tomcat 

posted @ 2012-04-13 15:11 zyskm 阅读(2052) | 评论 (0)编辑 收藏

eclipse library

关于eclipse的一些应用,开发过程中用到了就随手记下。
1.Web App Libraries and Eclipse Build Path
在eclipse下创建web项目,在build path下会对应包含Web App Libraries 动态加载项目下/WebContent/WEB-INF/lib所有的jar文件。
好处是在项目增加或删除jar包时不用总是修改build path配置文件,从cvs同步代码的时候保持这部分不变。
2.system library
有些jar在开发的时候要用到,但是部署的时候不用部署到服务器。
比如:jsp-api.jar,servelet.jar,这些文件在tomcat jboss 下已经包含,重复部署的话会引起错误。
我以前的做法是在anr build.xml文件中打包生成war时删除对应的jar包。
刚发现还有这么一种用法,在eclipse添加system library把jar添加到该库下就不会部署到服务器。
如图:主要tomcat-jar 一定要设置成system library

posted @ 2012-04-09 14:41 zyskm 阅读(1926) | 评论 (0)编辑 收藏

在创业公司工作四年,如何赚百万(转载--中国企业家网)

关于在创业公司工作的话题,以前跟同事讨论过,刚看到这么一篇,转载一下。

有人在Quora问了这个问题:What startup could make me a millionaire in four years if I got hired as an emplyee today?

Symbolic Analytics的创始人Brandon Smietana在下面做了很长的回答,内容很精彩,不过请勿对号入座:

大多数创业公司的退出(exit),都是通过M&A(并购),而不是通过IPO(首次公开募股),现在大多数的M&A价格都低于3000万美元,最典型的价格是1500万美元,现在我们来假设一个最乐观的退出案例,从其中的数据中算出,我作为创始人和CEO,能够拿多少钱;从而计算出,你,作为一个员工可能赚得的利益。

(一)

假定案例

1)我拿到1000万的投资。

2)投资人拥有公司50%的股权(乐观估计)。

3)我将公司以3000万的价格出售。

4)我拥有30%的外流通股(Outstanding Share) ,非常乐观的估计。

投资人还拥有优先股,通过并购,他们首先把自己投入的钱收回来,然后再参与省下的股权收益分红。

1)在3000万的退出中,投资人首先拿回他们投入的1000万,剩下2000万。

2)然后,优先股股东吃掉省下2000万的50%的利益分红,于是他们拿走另外1000万。

3)现在,整个脱售的现金只剩下1000万,分享这份利益的关系者包括大众股东,公司员工,创始人和管理团队。

我,作为创始人和CEO,享有最多的普通股股权,价值这1000万美元的大概600万。省下的400万利益归属其他所有的普通股股东(包括所有的公司员工)

最典型的早期员工,在利益分红中能拿到的资产不足CEO的1/30,因此,一位非常重要的早期员工,能够从脱售中取得20万美元的利益。

现在,让我设想得不那么乐观,相对实际一点。70%进入A轮融资的创业者,除了工资,其他什么利益都无法从公司获得。因此作为一名员工,

1)有70%的可能,如果你在A轮融资的时候加入创业公司,你的普通股是没有价值的。

2)与A轮以前的早期员工相比,A轮以后的员工通过股权或者期权能拿到的利益要少很多。

3)在A轮融资以后,新员工能够拿到的最好的股权大概在0.3%左右。

4)无论什么样的员工,他们的股权都会在管理层更换或者新一轮融资中被稀释。

(二)

如果我进入的公司是”下一个Facebook”呢?

硅谷在过去的十年里发生了惊天动地的变化。这些变化,同时作用并且影响着IT员工们能从公司那里获取的利益。

如果你在1998年以前(包含1998年)加入了一家在将来很成功的创业公司,那你一定已经赚了很多钱。但是,如果你加入的是Facebook,你所能获取的利益价值可能就无法跟前者媲美了。那么,那些加入“下一个Facebook“的哥们儿,希望可能就更小了,以下是原因:

谷歌的早期员工在加入时,谷歌的估值还很低。

1)谷歌的估值,一路从4000万涨到了2000亿。

2)那些最早加入谷歌的清洁工,从谷歌获得价值1000美元的股权,在2008年也价值400万美元。

3)一个获得了5万美元股权的工程师,他的股权在2008年价值1亿美元。

4)谷歌的大厨也获得了价值2800万的股权。

有四点原因说明,谷歌的员工为何能够金融上收益如此好:

1)他们在公司处于很低估值的时候获得股票期权。

2)从A轮融资到现在,谷歌的估值涨了4000倍。

3)公司员工以人为的超低协议价格获得购买期权(大概只相当于每股股价的1/10还要低),因为当时IRS(美国国税局)的409(a)条款还不存在呢。

4)由于协议价格足够低,因此员工在行权时,缴纳的是资本利得税15%(Capital Gain Tax),而不是收入税50%(Income Tax treatment)。

当谷歌发行股票给他的员工时:

1)公司处于低估值阶段,而非后来的顶峰估值阶段。

2)那时,美国国税局还没有执行409(a)条款,409(a)条款明确规定了员工期权的估值。

在十年以前,创业公司都会以低于估值的协议价格发给员工期权,以吸引有识之士。员工因此有可能通过公司IPO而一夜致富,他们行权的协议价格大概之相当于估值价的1/10。

而到今天,这么做就是不合法的了。现在,公司的主管们,依据83(b)条款,依然有权通过限制性股票(restricted stock)获得低估股票(undervalued stock);但是,现在获得将理性期权(Incentive Stock Options)的员工,就必须遵循IRS的的409(a)条款。同时,现在的员工,在行权时更可能缴纳50%的收入税,而不是15%的资本利得税。

随着更高的早期估值,现在的员工已经不太有可能有现金能够行权,而且也不太有可能缴纳资本利得税,一般都缴纳收入税。409(a)条款通过明确规定,也防止了员工行权价像十年前那么低。现在,一个创业公司的员工,如果行使价值200万美元的ISO期权(国际标准期权),在缴纳了加州税或者德州税之后,仍然可能面临50%的收入税。

一般情况下:创始人和主管们获得的是依据83(b)条款的限制性股票(Restricted Stock),并且缴纳的是15%的资本利得税,员工则更可能时取得福利期权(Incentive Options), 税率相对更高。

因此,作为一名员工,即便有一天你的公司被卖了,你也可能要缴纳50%的收入税。

200万瞬间就只剩100万,而现在,旧金山的房价是300万。

(三)创业公司估值之于员工的影响

以前所有关于谷歌员工胜出的理由,现在都有可能不复存在了。

新的创业公司,如Facebook,获得很高的早期估值,因此,早期员工能获得的利益相比以前的创业公司,就少很多了。

更重要的是,现在只有越来越少的大型IPO,取而代之的是越来越多的小型M&A。

图片一: 1992年 — 2009年 风险投资也IPO和M&A交易的比例

大多数公司并没有谷歌和Facebook那样做得很好。即便在Facebook,也只有一小部分员工积累财富。

Zuckerberg在Facebook的股权大致相当于Facebook所有非主管的员工股权的总和(24%vs30%).。前50个Facebook的非主管员工所获得的股权,差不多相当于后面25000个员工的总和。

股权就是金字塔,越升一级,差俱就越大。

在一个以3000万被并购的公司退出案例里(见上),一个很成功的M&A退出。公司的CEO也差不多只能赚600万美元。

(四)创业领域与员工回报的关系

有很多创业公司扎根在大众互联网领域(Customer Internet Space), 但是这个领域的投资回报率也最低。就拿Facebook举例(最成功的消费者互联网公司之一),它从每一个月度活跃用户那里只能产生3美元/年的利益。

很少的大众互联网公司能够通过广告获得盈利,像Ad.ly, Digg, Myspace, Twitter,还有很多其他的公司都很难达到大规模盈利,即便是用户量非常庞大。

一个大众互联网公司,如果每个月的活跃用户数有50万,依照Facebook的盈利推算,一年的盈利也只有150万美元。因此,不要把大众互联网当做救命稻草。

现如今,B2B/SaaS模式,以及生物技术市场,仍然能够在市场上攫取上亿的资金,但是,很少有人能有能力和经验在这个市场里把公司做起来。但是,在这领域,却有比大众互联网市场更多的盈利机会。

最有盈利空间的市场,最难发现创业公司。特别是,金融领域每年攫取的利润占全美公司利益的70%,但是,在硅谷却很难发现金融创业公司,即便有,也基本是大众金融服务。

Protip: 从数据和理论上看,如果你是A轮以后加入大众互联网公司的员工一枚,你的股权几乎就不值钱了。


posted @ 2012-03-06 14:58 zyskm 阅读(167) | 评论 (0)编辑 收藏

Hadoop Map/Reduce 学习

Hadoop最近很火,到处都能看到,查了一下资料大概先了解一下其运行原理。
google在05年公开了Map/Reduce论文,MapReduce在处理巨量数据方面有明显优势。
google公司一个技术大牛jefffery Dean提出的这个算法,随后很多小牛纷纷实现了Mapreduce,Hadoop是它的java实现,MapReduce概念直接推动了云计算概念的火爆。
没有优秀算法云是没法搞的。

这篇文章对Map/Reduce原理讲的很清楚。
http://www.chinacloud.cn/download/Tech/MapReduceOverview.pdf

这个是Apache关系Hadoop的文档,安装、开发示例都有。
http://hadoop.apache.org/common/docs/r0.19.2/cn/mapred_tutorial.html

posted @ 2012-03-02 15:05 zyskm 阅读(1934) | 评论 (0)编辑 收藏

企业信息化理论阅读笔记

因为一直在做企业信息化方面的开发,有必要了解一下相关的理论。
同事推荐的几本书。
霍顿(F.W.Horton)的信息资源管理(IRM)理论
威廉。德雷尔的数据管理(DA)理论
詹姆斯马丁的信息工程方法论(IEM)
看了之后有些吃惊,很多概念和理论都是上世纪80年代,还有60年代就提出的概念,做了这么久的开发居然没听说过,在规划方面没有一定的理论指导,都是些野路子方法。
还有许多平时用到的概念和方法找到了渊源,原来是这哥们或那哥们提出,老外的版权意识就是强对几十年前提出的理论都会整理出哪个观点是哪个人提出的。
不然很多方法一直觉得理所当然是那么用的,看过这些资料才知道理论提出的背景,除了这种理论解决哪些问题还有哪些方法,各有什么优缺点。
信息工程理论总结起来,就是以数据规划为基础,自定向下规划。并提供了一系列的技术用于自下向上的设计方法。对企业信息化中比较重要的业务流程有很大的篇幅。
目前的收获是,1.在系统规划方面有了完整的理论指导;2.了解了规划、分析、设计阶段会有哪些技术,哪些已掌握的技术需要加强、哪些技术需要学习。

老外的书翻译过来的在中文版看着费劲,找了本国内编译出版的,写得不错。
信息工程与总体规划概述。
本书讨论计算机信息系统总体规划的方法论,重点是总体数据规划。
第一章是本文的综述,目的是使读者尽快了解信息工程概念和总体数据规划方法的大意,因此是全书的提纲。
第二章到第四章是信息工程产生的背景和方法论的分析。这三章按三个主题展开:数据处理危机与转折;信息工程的原理、方法与工具;信息工程与结构化方法。

第五章到第十章比较全面深入地介绍总体数据规划的一整套方法,是本书的主体。编者根据近几年参与中大型企业计算机信息系统总体规划设计工作的实践,深感探讨先进科学的方法论的极端重要性,特别是总体数据规划的内容、方法,以及与后续开发工作的衔接等问题,更是迫切需要解决的。为此,我们较全面地翻译介绍了詹姆斯·马丁所倡导的一整套方法,供有兴趣的读者参考,从而尽快形成适合我国国情的总体规划方法论。

第一章
从需求分析开始的传统生命周期开发方法论
数据结构和数据是相对稳定的,而数据的处理过程则是经常变化的。总体数据规划方法。
软件工程仅仅是关于计算机软件的规范说明、设计和编制程序的学科,实际上信息工程的一个组成部分。
信息工程的基本原理和前提是:
1.数据位于数据处理的中心。
2.数据是稳定的,处理是多变的。数据类型是不变的。
只有建立的稳定的数据结构,才能是行政管理或者业务管理上的变化为计算机信息系统所适应,这正是面向数据系统所具有的灵活性,面向过程系统往往不能适应管理上的变化需求。
3.用户必须真正参与开发工作。Design with,not design for.

第二章
信息工程的组成部分
自定向下规划和自下向上设计方法论
重点分为三个部分:
企业模型、实体关系分析和数据模型的建立(即主题数据库的规划),以及数据分布规划。

总体数据规划简介
四类数据库环境
1.数据文件;
2.应用数据库
3.主题数据库
4.信息检索系统
规划方法
1.进行业务分析建立企业模型
2.进行实体分析建立主题数据库模型
3.进行数据分布分析

第三章
信息工程概貌
1.关于全面开放的规划
2.关于业务分析
3.关于数据分析,数据可以表达成与使用无关
4.关于自动化工具

信息工程的基本组成
1.企业模型,企业模型的开发是在战略数据规划期间进行的。
2.借助实体关系分析,建立信息资源规划。这是自顶向下的数据类型分析,这些数据是必须被保存起来的,还要分析他们之间是如何联系的。
3.数据模型的建立,产生详细的数据库逻辑设计
导致信息工程产生的一个重要认识,是组织中存在的数据可以描述成与这些数据如何使用无关的形式,而且数据需要建立起一定的结构。这一点较面向对象的思想很接近,可以把数据模型任务是数据对象。

信息工程的建设基础
战略的数据规划工作

信息工程方法论
1.关于企业信息化战略规划的方法
2.关于信息系统设计实现的方法
3.关于自动化开发工具

第四章结构化方法与信息工程
信息工程是在进行战略需求规划,信息需求规划,总体数据规划和数据分布规划的基础上,使用结构化设计和结构化编程的方法。
结构化系统分析
数据流图
结构化系统设计
信息工程是面向数据的方法,结构化方法是面向过程的方法。前者可以使用未来,后者只能使用过去和现在。

战略需求规划
战略需求规划是信息工程的基础工作,不仅要对现有需求规划,还要对未来需求规划。
1.加强用户之间的沟通合作。
2.加强高层领导者之间的沟通并为之提供支持。
3.提高资源需求预测和分配的准确性。
4.提供内部mis的可行点。
5.提出新颖而高质量的应用系统。

信息需求规划
信息需求:
1.事务处理工作的管理信息需求;
2.高层领导者的管理信息需求;
3.企业发展和改革发展方面的信息需求;
传统的软件工程和数据库技术尽管有分析设计方法,但缺乏自顶向下的规划,不能适应大型复杂系统的建设。信息工程强调总体规划,形成了一套自顶向下规划与自下向上设计的完成的方法学,为大型复杂系统的建设提供了保障。

第五章总体数据规划的组织
战略规划
1.战略业务规划
2.战略信息技术规划
3.战略数据规划
战略数据规划,即总体数据规划是信息工程规划工作的核心和基础,需要研究它的组织方法。
战略规划的目的是使信息系统的各部分能共同工作。
对战略规划的详细程度要有恰当的理解。

第六章 企业模型
..........................
今天看了五章的内容,休息一下。
忙完手头工作继续学习,2012-2-28
总体数据规划的第一步是进行业务分析,建立企业模型。(编者按:目前电信行业都已经建立起了完善的企业模型,其他行业还没看到)
企业模型是对企业结构和业务活动 本质的、概况的认识。
用职能区域--业务过程--业务活动 这样的层次结构来描述。
1.研制一个表示企业各职能区域的模型;
2.扩展上述模型,使它能表现企业的各项业务过程;
3.继续扩展上述模型,使它能够表现企业的各项业务活动。
依靠企业高层,分析企业的现行业务和长远目标,按照企业内部的各种业务的逻辑关系,将他们划分为不同的只能区域,弄清各职能区域包括的全部业务过程,再将各个业务过程细分为一些业务活动。
建立分析企业模型的过程,是对现行业务系统再认识的过程。

职能区域
职能范围、业务范围,是指一些主要的业务活动区域,如销售、市场、财务、认识、生产。
职能模型,职能区域图表

业务过程
企业模型的二级结构是业务过程的识别、命名、定义。这项工作主要由分析人员来完成。
1.业务过程与组织结构
2.识别业务过程的参考模式
    产品、服务和资源四阶段生命周期
    计划,获得,保管,处置(编者按:原书有一张图表,这里就不列出来了),模式的每一阶段都有一些业务过程的类型。
3.业务过程与负责人
4.经验

业务活动
每个业务过程中都存在一定数量的业务活动

业务活动分析
1.功能分解的程度
2.凝聚性活动,1.产生清晰可识别的结果,2.有清楚的边界,3.是一个执行单元,4.自封闭的,独立于其他活动。
3.冗余活动和功能组合,

企业模型的建立过程
可以理解为逻辑模型

企业模型的特点
完整性、适用性、永久性

关键成功因素
3~6个决定成功与否的因素
1.关键成功因素的确定
关键成功因素应该成为最高层管理人员管理控制企业系统的基础,对一个行业来讲关键成功因素差不多是相同的。
如食品公司:广告效果,货物分发,产品革新
2.关键成功因素的审查

第七章主题数据库
独立于应用的数据
数据库环境的原则
1.企业的数据应该得到直接管理,与使用的职能分开;
2.数据描述不应由使用数据的应用包含,而应当由独立的数据管理员设计;
3.数据应该独立于现有机器资源;
4.使用统一的工具和设施管理资源;
5.有适当的安全和保密控制;
6.高层管理人员要参与数据库的总体规划和决策。

面向过程的系统分析方法
面向数据的系统分析方法

主题数据库与组织内各类人、事、物相关,而不是与传统的应用相关。
总的来说这部分没什么干货,就是对前面方法论的细化和再次说明。
这本书侧重于方法论和理论概念。在规划部分有具体的指导,在具体分析和设计技术上着墨不多。

第八章实体活动分析
第九章数据分布规划
第十章规划与开发建议
这两天比较忙,后边章先顾不上看了。
第八章和第九章应该跟软件工程里的内容是一致的,原来项目开发时经常要用到。第十章讨论BSP方法,要了解一下。

posted @ 2012-03-02 10:59 zyskm 阅读(2354) | 评论 (2)编辑 收藏

工作流流程合并

        因为项目需要做了一个简单的工作流引擎,用于集成订单管理(IOM)的生产调度。之前的文章有提到。原想着有这样一个引擎来进行生产调度,设计好业务流程后就可以面朝大海,春暖花开。在还生产系统对接的时候发现有一部分还是人工处理更好,毕竟不是所有的流程都能那么细致合理。
下面是我们的解决方案,图片是从wps里另存出来的,不知道咋就变成黑底了。
1.1 问题描述

工作流引擎处理流程调度部分的内容。客户下订单之后,协调各生产部门进行工作

最理想化的情况是对客户发起的每一种操作都定义一组流程,在流程执行的过程中每种状下态当有新的操作进来也相应定义一组流程,但这样一来流程设计工作极其繁琐,容易出错,不利于降低管理难度减轻管理工作量。

一个折中的方案是对执行中的流程进行流程合并。选择对一部分操作不创建新流程,给用户提示信息,由用户觉得如何进行手工操作。

1.2 问题分析

1.2.1 概念定义

生产平台生产平台是由人和机器构成的,能将一定输入转化为特定输出的有机整体对应于工厂中的生产车间概念。

生产线生产是与相关的一个部门或一组操作对应的组织。类似于项目组的概念,是依据生产流程对生产能力的一种划分方式。

产品:产品是指中企动力运用营销手段,将业务或业务组合附加上销售对象、销售地域、资费计划、销售渠道、服务水平及配套资源属性后的产物,是向客户最终交付的、客户可以购买的产品单元组合实例。

产品单元产品单元是业务在生产系统的具体表现

产品单元与生产线之间是多对多的关系。如果一个产品单元需要跨多个生产线,引擎需要调度产品单元在不同生产线的生产过程。

流程组:流程组指由一系列操作流程组成的流程集合,有流程间的先后顺序。流程组在此是由产品和操作类型共同决定的。

流程:流程是一系列操作环节的集合。环节间有并行和串行的关系。流程在此处是由平台和操作类型决定的。

环节:环节是一系列操作的集合。环节此处定义是由一个人的一个或多个可并行的操作决定的。

任务:任务是可执行的最小单位。任务具有原子性,是环节的组成部分。一般一个任务完成一个事务。

一个环节包含多个任务,一个流程包含多个环节,一个流程组包含多个流程。

1.2.2 问题描述

以一件定制服装的过程为例,只是为了说明问题对流程做了简化。见下图

定制服装生产流程:
      

最简化的情况,客户在提交了定制服装生产的要求后便不再干预,生产线就按流程走就可以了。

但是客户可能会在生产的各个环节提出变更要求,已经制作完成了客户要求加个兜,已经质检完成了客户要求加个纽扣,已经包装好了客户要求领子样式改改。

如果把每一种可能都定义一组流程,就这个简化流程全部列出来也够贴一面墙了。所以我们采取了一种折中的方案,在大多数情况下正在生产时客户要求有变化,通过一个描述性的工单告诉生产线负责人暂停生产、并由负责人来决定回退到那个环节重新进行。

如果都包装好了客户还要改,那就暂停当前流程,走和客户打官司的流程了,这种情况下需要一个流程。

本方案通过对生产中的流程进行合并,减少流程定义的工作量和复杂程性度。

1.3 问题解决

1.3.1 工单

1.3.1.1 逻辑模型

订单生成工单的过程,称为合单

订单工单关系

工单属性

现在所描述的都是对同一个订购实例所下各种订单的合单处理情况。

1.订购实例第一次下订单,根据订单生成工单和工单明细。

2.订购实例第二次下订单

a) 之前生成的工单已经竣工,生成新工单和新工单明细。

b) 之前生成的工单还未生产,废弃该工单,生成新工单和新工单明细

c) 之前生成的工单生产中,废弃该工单,继续沿用原工单编号,合并生成新工单和新工单明细。新工单状态为生产中。

在工单明细表增加字段“产品单元变更标识”,如果产品单元对应的属性内容在两次订单中没有变化,引擎不暂定产品单元触发的流程。

1.3.2 流程实例化

1.3.2.1 逻辑模型

流程定义模型见下图,概念定义部分对名词有描述。

流程定义

流程实例化

在业务支撑系统经常使用的一个概念,实例化。

用户购买一个产品后,就产生一个产品的实例化,区别于别的客户购买的同类产品,称为订购实例。

定义一组流程用来处理产品生产过程,具体到某个订购实例的生产过程的实例化,就有了流程组实例、流程实例、环节实例和任务实例。

1.3.2.2 流程定义过程

有了流程定义的模型,我们就是可以设计或者叫定义产品的生产流程。

完成一件复杂的工作,总是需要一个步骤一个步骤的完成,每个步骤称为一个环节,在这个环节下可能需要做几个事情,每个要做的事情称为一个任务。

1.根据生产部门划分生产线

2.根据生产线+操作,定义流程,把流程中的任务根据负责人划分为不同的环节。

3.按照产品涉及的流程划分为不同的流程组。

1.3.2.3 流程实例化

1.实例化约束

a) 一个订购实例当前只有一个运行中的流程组实例;

b) 流程合并前先暂停,避免和引擎并发竞争。

2.实例化过程

a) 接收工单,检查订购实例当前是否有流程组实例在运行中;

i. 无,实例化一个新的流程组实例

ii. 检查是否属于同一个流程组定义

1. 是同一个流程组,进行流程合并。

2. 不是同一个流程组,暂不实例化,待下一次轮询再处理。

流程合并细节见《流程合并详细设计》

1.3.3 流程引擎

1.3.3.1 模型状态

1.已实例化

2.已分配(负责人)

3.执行中

4.暂停

5.已完成


流程启动后按顺序执行,当要回到上一步骤时,监控页面支持回退和回滚两种操作。

回退,当前执行中/暂停的环节设置为已分配,上一环节由已完成设置为执行中。

回滚,对任务可以执行其反任务。

1.3.3.2 功能描述

1.引擎轮询程序,检查处于执行中状态的环节,如果环节下所有关键任务都已完成则环节进入已完成状态,下一环节进入执行中状态。

2.环节实例化后处于已实例化状态,用户在任务分配页面指定环节负责人,环节处于已分配状态,上一环节完成后由引擎设置本环节进入执行中状态。

3.鉴于引擎对执行中的环节进行调度工作,实例化程序和页面监控程序在对执行中的环节操作时,需先暂停环节。

4.监控页面支持对流程、环节的回退,支持对任务的回滚。

posted @ 2012-02-20 10:21 zyskm 阅读(2196) | 评论 (3)编辑 收藏

工作流理论资料

之前做了一个简单的工作流引擎,干完了活做点理论总结。
项目见工作流应用---理论基础篇工作流应用---概念、模型
这个工作流引擎主要是根据项目需求和网上看到的一些文章提到的概念做出来的,估计比较野路子,想着把概念和名词向大师靠拢。
过了年刚来不忙,这几天抽空看了两本工作流方面的书,《工作流管理技术基础》和《工作流管理:模型、方法和系统》,讲的比较细致、对基础概念讲的很清楚,就是书老了点。
书中对XPDL标准做了详细描述,对新出的BPEL没有涉及。
我自己项目中用到的概念和大师们基本一致,大方向不错,看来网上找到的那几篇文章挺靠谱的,当时应该随手整理出来。
工作流引擎做的比较简单,没有使用主流的petri技术,只支持项目需求更负责的需求就够呛了,回头有空再改一版。看了书才发现有这么多种模型实现方法早都有人研究很多年了。
这两本书在超星网站都能找到电子版。

IPO模型,过程中的每一个活动都由输入(I)、处理(P)、输出(O)三部分组成。
理论来自《科学管理》提出的科学管理原则:
一个组织的工作可以描述为一系列的任务,每个任务都是工人们具体、严谨的活动过程,管理就是在一定的计划下让这些任务以最优的方式进行。

常用的工作流模型:
1.基于活动网络的过程模型
    组成模型的元素包括过程、活动、模块、控制连接弧、数据连接弧和条件。
    以活动作为构成过程的基本单元,以连接弧体现过程逻辑,可以灵活的实现企业经营过程的建模,我做的那个基本上采用的就是这种模型。
    过程:为完成目标而定义的一系列步骤;
    活动:过程中的步骤;
    模块:跟过程的概念类似;区别在于是否可以多次重复使用
    控制链接弧:定义两个活动间的执行顺序
    数据连接弧:定义两个活动间的信息流
    条件:定义过程执行中的约束
            定义在控制连接弧上的条件:转移条件
            活动可以执行和活动被执行:开始条件、结束条件。
    优点:
        从系统分析的角度来看,有利于通过过程模型提取功能视图和信息视图、便于深入分析
        从系统实现的角度来看,控制流管理和数据流管理分离,是不同性质的流管理独立。
2.事件驱动的过程链模型
    兼顾模型描述能力强和模型易读两个方面。
    业务事件、业务功能、控制流、逻辑操作符、信息对象、组织单元
3.基于语言行为理论的工作流模型
    IPO模型对于观察信息和物流的流动过程比较合适,但不利于不同角色间的委托和承担行为。
    语言行为理论则侧重与解决,数据、物、人协作中IPO模型对人直接协作描述不足的情况。
    听上去不错,实际中没有看到用这种模型的,google了一下相关资料,还只是一个理论在软件领域用来进行协作过程建模的很少。
    简单了解一下先,等大师们研究明白了咱再学习。
4.基于petri网的工作流模型 
    这个东西看着挺复杂的,不过好多人都说是好东西,研究一下先。
    找了两本有关petri的书,都太理论化看不懂。还是《工作流管理:模型、方法和系统》讲得比较通俗。
    petri基本概念很好理解,不同于过程化分析,更接近面向对象的思想。看起来我在这个项目中采用的分析方法更接近与petri,原来俺们朴素的想法跟大师很接近哦。
     一般的面向对象分析更侧重与静态结构,在动态模型部分描述的都不够清楚。petri在动态过程方面感觉很细致有效。据说还是经过严格熟悉验证的分析方法,不过那些公式没看懂,太费劲。分析时用petri分析建模方法就可以了。
    .....

posted @ 2012-01-31 16:56 zyskm 阅读(2084) | 评论 (1)编辑 收藏

工作流应用---概念、模型

上一篇讲了工作流的主要概念和用途。
知道了要依靠工作流引擎来推动流程向前。
这一篇讲一个具体实现的例子,比较简单,对于复杂的流程关系定义处理不了,上下文参数构建也不支持,这些依赖具体的业务领域模型处理了。
好在工作流基本的概念是有了,对于复杂的应用可以借鉴成熟的产品,知道工作流是怎么回事了其他产品也就容易上手了。
工作流概念这一块,目前也没个统一规范,就自己搞了一套,没采用那些推荐标准太复杂用不上。

要开发一个工作流引擎出来,跟其他开发没有不同,概念、需求、建模。
一、搞清楚都要用到哪些概念
二、能够提供哪些功能、准备用例
三、建模
    1.静态模型
        依据关键流程的用例推导概念、明确概念定义、支持概念所要用到的数据结构
    2.动态模型
        定义各功能模块操作,并检查是否覆盖所有关键用例。

实际例子,懒得敲那么多字了,直接上图
1.用例,用来确定系统边界


2.主要概念,及概念见关系

3.流程生命周期定义
        说明一下,分配状态和运行状态是两个维度的东西,为了省事就定义在一起了。


4.系统架构
描述引擎的内部构成、引擎与外围系统的关系。

posted @ 2011-12-30 17:11 zyskm 阅读(1410) | 评论 (0)编辑 收藏

工作流应用---理论基础篇

这段时间因为项目需要做了一小的工作流引擎,总结一下经验。
大概会分为这么几个阶段来介绍。
1.理论基础
2.实现技术
3.实际开发的一个例子。
如图:

一、理论基础
     只是简单的讨论原理,详细数学理论不再这里讨论,会在附录里列出来,有兴趣的同学自行查看。
    1.概念
      为了实现业务过程自动化提出的概念。
以前去政府部门办过事大家都有体会,那个迷茫啊困惑啊,很多连个办事指南都没有。
办一件小事要盖十几个章,材料交上去后你根本不知道现在到了哪个部门,审核通过了没人通知你,没通过的话少什么资料也不告诉你,告诉你也不是一次都说,跑一趟说一点。通过了这个部门审核下一步应该去哪也没人告诉你。
这个时候有个对机关门清的人,知道哪里水深水浅,领着你办下来该有多好,该请客请客该送礼送礼,少跑很多冤枉路,还能随时查询状态。
这就是工作流引擎要做的事情。  
    2.发展历史
 工作流技术起源于二十世纪七十年代中期办公自动化领域的研究,由于当时计算机尚未普及,网络技术水平还很低以及理论基础匮乏,这项新技术并未取得成功。
老外也是被扯皮扯怕了试图改进。
    3.作用目标
工作流将作为一个公共基础子系统服务于整个平台产品的人力工作流和业务工作流环节。
通过将工作活动分解成定义良好的任务、角色、规则和过程来进行执行和监控,达到提高生产组织水平和工作效率的目的。
人多了事情多了,扯皮的情况也就多了。为了避免扯皮建立一个协调中心,提供办事指南,负责进度管理,公共信息维护。
处理这种有复杂流程的事情目前有两种解决思路:
1.针对业务领域开发一个系统,一个模块处理完成一件事件后根据情况来决定下一步跳到哪个模块,带点什么参数。适应于流程比较固定的业务,像财务系统虽然很复杂,但是各种处理规则都清清楚楚明明白白,也不会随便变动。
2.工作流方式,讲流程跳转规则由工作流引擎统一维护,每个具体执行任务的模块只管干自己的活,干完了告诉一声引擎,由引擎通知下一个模块。目前只能处理相对简单的一些工作流程,OA公文流转,IOM生产系统调度这类规则不是很复杂,流程上下文较简单的情况。
对于特别复杂的流程,开发量反而比定制业务系统还要多。工作流理论需要再有一次提升才能解决这个问题。
    4.体系特点
          可维护性和可扩展性
            与业务系统实际关联低偶合
            可以扩充表达式引擎,与界面绑定由界面引擎决定
            可以适应与审核等人力流程,也可以适用在无人干预的商业自动化流程
          安全性
          易用性
    5.模型表示
        用例模型
            应用用例
            扩展用例
       分析模型
            架构性重要分析元素
            架构性重要用例实现
       设计模型
               组件结构
                部署结构
    6.定义语言
    7.参考资料

posted @ 2011-12-27 15:09 zyskm 阅读(1646) | 评论 (2)编辑 收藏

How tomcat works阅读笔记

这几天抽空把How tomcat works看了一遍。

这本书写得很好,把tomcat这么一个牛B的大家伙拆成一堆零件,然后告诉你怎么组装,真是做到了掰开了揉碎了讲。
简单记一下
第一章讲web服务器,如何接受和响应http请求,还举了个sokcet的例子。算是入门,从很底层的技术讲起。
第二章讲servlet容器,javax.servlet.Servle接口,接受到http请求后如何查找servlet,执行servlet。
第三章讲连接器的概念,前两章看下来你会觉得把http请求接受响应跟容器放在一起太乱了,这章就讲如何把http操作提出来作为一个连接器。
第四章讲tomcat默认连接器,http协议操作讲得很详细,不过我没怎么看哈,用的时候直接把tomcat这段代码拿过来就是了。
第五章讲容器,在第三章的基础上对容器进行分层分类,事情复杂了就分成几部分,“治众如治寡,分数是也”这个我们都知道。
    tomcat讲容器分成这几个概念:
Engine:表示整个Catalina的servlet引擎
Host:表示一个拥有数个上下文的虚拟主机
Context:表示一个Web应用,一个context包含一个或多个wrapper
Wrapper:表示一个独立的servlet

类型复杂了,要做的事情也复杂了。
不仅仅是执行service()方法,还要前边执行一堆,后边再来一堆。引入了流水线任务Pipelining Tasks的概念,在流水线上可以执行多个Valve(有翻译成阀),类似于拦截器的概念。

第六章讲生命周期,人多了要讲究个步调统一,引入了Lifecycle接口的概念,方法包括启动之前干什么、启动之后干什么、启动后把子容器也启动了。
包括引入监听接口,都是些java常见实现方式,没什么特殊。

第七章讲日志系统,没看。
第八章讲加载器,可以参考tomcat类加载器及jar包冲突问题分析 http://www.blogjava.net/zyskm/archive/2011/12/06/365653.html 就不重复了。
第九章讲session管理,没什么特别的。
第十章讲安全,没看。
第十一章讲StandardWrapper,在第五章的基础上重点分析了wrapper的运作机制。
其余章节目前工作中用不到,有空再看了。

作者:zyskm
http://www.blogjava.net/zyskm

posted @ 2011-12-06 16:25 zyskm 阅读(3149) | 评论 (7)编辑 收藏

tomcat类加载器及jar包冲突问题分析

开发过程中遇到过这样一个情况,在本地tomcat下开发调试正常,打包到测试环境的jboss下所有页面都变成空白页。
项目日志和jboss日志没有一点异常信息,费了半天劲把jboss所有日志全部打出来,发现是el.jar这个包里有空指针调用。
检查一下,项目WEB-INF\lib里有这个包呀,那应该是跟什么地方的jar包版本冲突了猜想,继续找,在jboss-4.0.5.GA\server\default\lib下找到了对应包,比较了一下版本果然版本不一样。
把项目下的el-api.jar,jsp-api.jar,servlet-api.jar删除,重新启动,问题解决。
接着有同事提出,同样在tomcat下开发也出现这种情况,经检查是他本地tomcat版本跟大家的不一致。开发环境这地方没做到很好的统一。

这样问题是解决了,但是有一点就想不明白了,按照java的类加载委托机制,推测应该是先从jboss-4.0.5.GA\server\default\lib加载,如果加载不到的话再用当前类加载器加载WEB-INF\lib下的jar包,所有如果jboss下有jar包WEB-INF\lib下的应该不起作用,也有不会有冲突了。
难到情况不是这样的?

一直想着找tomcat源码分析一下来着,拖了好久。赶上这两天不忙,就把apache-tomcat-6.0.33-src源文件弄了一份,debug看看到底怎样。
tomcat的类加载器结构和其他java项目是一致的。见图一


图一
其类图见图二

图二
elipse debug截图倒过来看跟这个就一样了。
Tomcat 通过Lifecycle接口来实现容器生命周期的统一管理,跟类加载器关系不大,这里就不讨论了。
通过这样大容器启动的时候启动子容器,逐级加载。其结构关系跟server.xml描述的基本一致,详细可以参考我的上一篇文章

Tomcat6结构分析
http://www.blogjava.net/zyskm/archive/2011/10/24/361870.html

(这个编辑工具不太会用,样式难看点,凑合看了)
每个容器都有自己的类加载器,在默认情况下都是StandardClassLoader的实例。
委托机制也和标准的java实现没什么两样。

接着往下看项目对应的类加载
StandardContext.start();调用WebappLoader.start()开始加载项目,WebappLoader又通过创建一个WebappClassLoader实例进行类加载。
WebappClassLoader.loadClass()实现依然波澜不惊,规规矩矩的先从缓存找,找不到调用findClass()进行加载。
果然这里实现有点不同,是先自己找,找不到再委托上级查找。和java默认的加载方式不同。
见源代码,只留下原理部分,日志和调试信息都去掉了。

public Class findClass(String name) throws ClassNotFoundException {
        
// 先自己加载类,找不到则请求parent来加载,注意这点和java默认的委托模式不同
        Class clazz = null;
        
try {
            
if ((clazz == null)) {
                    clazz 
= findClassInternal(name);
            }

            
if ((clazz == null&& hasExternalRepositories && !searchExternalFirst) {
                    clazz 
= super.findClass(name);
            }

            
if (clazz == null{
                
throw new ClassNotFoundException(name);
            }

        }
 catch (ClassNotFoundException e) {
            
if (log.isTraceEnabled())
                log.trace(
"    --> Passing on ClassNotFoundException");
            
throw e;
        }

        
return (clazz);
}

据此可以认为,在web项目WEB-INF\lib下的jar包优先级高于jboss,tomcat 下的lib.
两处版本不一致的话会导致程序异常。
比较省事的办法是WEB-INF\lib下不再保留重复的jar包,实在闲着没事的话可以自己写个类加载器替换tomcat下WebappClassLoader改变加载顺序。
但是还可能有隐患,WebappClassLoader权限较低,它加载的类只能访问web应用下的资源,如果servlet-api.jar等包用到其他资源时可能出现异常。
这个没实际测过,只是推测。但是catalina要提供对整个容器的支持,servlet-api实现对http协议的封装转换用到外部资源的可能性很大。


图三 类加载器结构图

总结:
sevlet-api.jar,jsp-api.jar,el-api.jar这类容器提供的jar包web项目下没必要再保留一份了,容易出现版本不一致。

附录:
查看tomcat源码的时候可以看看how tomcat works这本书,很不错,虽然老了点。

作者:zyskm
http://www.blogjava.net/zyskm

posted @ 2011-12-06 13:43 zyskm 阅读(10675) | 评论 (3)编辑 收藏

spring声明性事务常见问题分析(续)

上一篇说明了一种spring事务配置方式,这次补上另一种。
见配置文件:
<!-- 事务拦截 -->
    
<tx:advice id="txAdvice" transaction-manager="transactionManager">
        
<tx:attributes>
            
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
            
<tx:method name="find*" propagation="REQUIRED" read-only="true" />
            
<tx:method name="search*" propagation="REQUIRED" read-only="true" />
            
<tx:method name="save*" propagation="REQUIRED" />
            
<tx:method name="modify*" propagation="REQUIRED" />
            
<tx:method name="send*" propagation="REQUIRED" />
            
<tx:method name="revoke*" propagation="REQUIRED" />
            
<tx:method name="del*" propagation="REQUIRED" />
            
<tx:method name="logging*" propagation="NOT_SUPPORTED" read-only="true" />
            
<tx:method name="*" propagation="SUPPORTS" read-only="true"  />
        
</tx:attributes>
    
</tx:advice>
    
<aop:config>
        
<aop:pointcut id="projectServiceOperation" expression="execution(* cn.ceopen.bss..*.service..*(..))" />
        
<aop:advisor pointcut-ref="projectServiceOperation" advice-ref="txAdvice" />
    
</aop:config>

重点说明两点:
1.<aop:pointcut id="projectServiceOperation" expression="execution(* cn.ceopen.bss..*.service..*(..))" />
表示你要进行事务控制的类名。详细资料可以查下 aspectj语法。
配置完成一定要实际测试一下,我配置过 expression="execution(* cn.ceopen.bss..*.service.*(..))" 少了一个点,导致事务不起作用。
导致项目很长一段时间事务方面没经过严格测试。
2.
Spring的AOP事务管理默认是针对unchecked exception回滚。
也就是默认对RuntimeException()异常极其子类进行事务回滚。
在项目中定义公共的RuntimeException异常,避免每个开发人员随意抛出异常。
不然的话没新定义一个异常,就要修改tx:method rollback-for 太麻烦了。

总结:
1.对事务配置进行检查,对复杂嵌套的事务逻辑必要的时候debug到spring源码中确认。
2.定义统一异常类型
3.同一个类调用自身方法,子方法的事务配置不起作用。解决方法见上一篇文章。
http://www.blogjava.net/zyskm/archive/2011/11/11/363535.html

作者: zyskm
本文地址:
http://www.blogjava.net/zyskm/archive/2011/11/30/365225.html

posted @ 2011-11-30 17:35 zyskm 阅读(3276) | 评论 (0)编辑 收藏

客户端缓存和服务器端缓存

在开发中缓存是经常要用到的,什么东西都一遍遍的找数据库问,数据库表示压力很大。
缓存方案常见的有两种,一种是在客户端,也就是web开发中的浏览器。一种是在服务器端,以memcached为代表。

浏览器缓存

这几天因为项目需了解了下浏览器缓存相关的知识。

重点说一下HTML5 Storage技术,之前的那些技术都是浮云,存不了什么东西还贼难用,各浏览器不兼容。
听名字就知道这是这两年刚出来的技术,相应的也就对浏览器版本要求比较高,低版本的浏览器不支持。对用公司内部用的话这个技术还是很不错的。
最多支持5M的容量,是个xml文件,备注:
Html5 storage最大支持5M容量
文件位置,根据系统用户位置会有区别。
C:\Documents and Settings\Administrator\Local Settings\Application Data\Microsoft\Internet Explorer\DOMStore\KF2G0R0O
也就是说别人都能看到你的数据,所以不能存放需要保密的内容。
每次用户登录的时候最好检查一下缓存版本是否跟服务器一致。

现在的项目中有个业务受理环节,设置的过程中需要大量使用一些基础数据。类似分公司、部门、产品列表这类数据,不经常变动,反复到服务器请求的话对服务器来讲是不小的压力。
业务受理的步骤很多,得点好几个下一步才能把操作完成,半截数据放到数据库里维护起来结构就复杂了。
因此考虑采用本地缓存技术,比较来比较去HTML5 Storage是不错的选择,反正都是公司同事可以要求都使用IE8以上浏览器。

下边这段是js中用到的代码

//用jquery方式,为加载缓存到本地按钮绑定方法
    $('#loadBtn').bind('click',function(event){
        
if(supports_html5_storage()){
            localStorage.clear();
            load();
            alert(
"数据已经缓存到本地!");
            initCorpSelect();
            initDptSelect(
"-1");
        }
else{
            alert(
"You're out!");
        }

        
    }
) ;
    
//清空缓存
    $('#clearBtn').bind('click',function(event){
        
if(supports_html5_storage()){
            localStorage.clear();
            alert(
"本地缓存已经清空!");
            initCorpSelect();
            initDptSelect(
"-1");
        }
else{
            alert(
"You're out!");
        }

    }
) ;
//加载缓存到本地浏览器
function load(){
     
var params = {
        url:
"${ctx}/crm/product/product/webstorage!ajaxLoad.do"
        type: 
"post",
        dataType: 
"json",
        data: 
null
        success: 
function(response){
            
var corps = response.corps;  
            
var dpts = response.dpts; 
            
var stations = response.stations; 

            
for(var i=0;i<corps.length;i++){
                
var corp = corps[i];
                
var jsCorp = new Corp(corp.corpCode,corp.corpName);
                localStorage.setItem(
"corp."+corp.corpCode, jsCorp.toJSONString()); 
            }


            
for(var i=0;i<dpts.length;i++){
                
var dpt = dpts[i];
                localStorage.setItem(
"dpt."+dpt.dptCode, dpt.toJSONString()); 
            }


            
for(var i=0;i<stations.length;i++){
                
var station = stations[i];
                localStorage.setItem(
"station."+station.stationCode, station.toJSONString()); 
            }

        }

    }
;                
    ajax(params);
}


 

服务器缓存

缓存解决方案很多了,只说刚刚用到的memcached。
memcached很好用了
1.安装启动memcached
2.写一个memcached客户端工具类,我用的是com.danga.MemCached.MemCachedClient 比较稳定,至于其他性能更高的目前没有需求没用到。
3.加载数据到memcached
4.程序中需要基础数据的时候从memcached获取。

/**
 * memcached接口
 * 
@author ce
 *
 
*/

public interface Imemcached {
    
/**
     * 可增加,可覆盖
     
*/

    
public abstract boolean set(Object key, Object value);
    
public abstract boolean set(Object key, Object value,Date expire);
    
/**
     * 只能增加;如果增加的key存在返回“false”
     
*/

    
public abstract boolean add(Object key, Object value);
    
public abstract boolean add(Object key, Object value,Date expire);

    
public abstract boolean delete(Object key);

    
/**
     * 只能修改;如果修改不存在的key返回“false”
     
*/

    
public abstract boolean modify(Object key, Object value);

    
/**
     * 如果key不存在返回null
     
*/

    
public abstract Object getKey(Object key);

    
/**
     * 清除服务器上所有数据
     
*/

    
public abstract boolean flushAll();

    
/**
     * 判断服务器上是否存在key
     
*/

    
public abstract boolean keyExists(Object key);

    
/**
     * 一次获取多个数据,减少网络传输时间
     
*/

    
public abstract Map<String, Object> getKeys(String[] keys);
    
    
    
/**
     * 设置是否使用字符串方式
     
*/

    
public abstract void setPrimitiveAsString(boolean flag);
}


实际测试结果
查询一张人员表,同时需要根据分公司编号,部门编号从分公司、部门表获取名称。
使用缓存技术的时候,不管客户端还是服务器端,因为只查询单表,速度明显比多表联合查询要快的多。
在系统使用高峰的时候这种差别明显能改善用户的操作体验。
实际测试了以下几种情况:

1.查询:
直接通过表关联的方式进行查询,速度最慢,开发最简便
查询结果列表中的公司名称、部门名称直接从数据库查出。
2.查询(本地缓存),缓存数据到本地,清除本地缓存:
速度最快,数据同步有一定工作量,需要高版本浏览器支持
查询结果列表中的公司名称、部门名称从本地缓存获取,增加_IE标识以区别。
3.查询(服务器缓存),缓存数据到服务器,清除服务器缓存:
速度也很快,也有数据同步问题,缓存数据到服务器比本地慢
查询结果列表中的公司名称、部门名称从服务器缓存获取,增加_mem标识以区别。





缓存使用总结

1.采用缓存技术后系统性能有明显改善,可以从性能测试工具明显感受到(这不是废话嘛,呵呵)。
2.缓存的数据同步问题必须解决好
3.项目中采用缓存技术需要统一规划,各系统不能互相干扰。
4.性能压力不明显的情况下,缓存开发要显得复杂一点。


 
作者: zyskm

本文地址:
http://www.blogjava.net/zyskm/archive/2011/11/30/364722.html

 

posted @ 2011-11-30 16:25 zyskm 阅读(6704) | 评论 (0)编辑 收藏

spring声明性事务常见问题分析

声明性事务是spring一个很重要的功能,可以避免开发陷入繁琐的事务控制逻辑中。
但是可能是用着太方便了很多人对spring事务原理并不清楚,有必要做一番分析。
下边以拦截器配置方式进行说明,tx标签配置方式将在接下来另一篇文章做分析。
一、首先看配置文件:
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="matchAllTxInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
    
<property name="transactionManager">
        
<ref bean="transactionManager" />
    
</property>
    
<property name="transactionAttributes">
        
<props>
            
<prop key="get*">PROPAGATION_REQUIRED,readOnly,-Exception </prop>
            
<prop key="find*">PROPAGATION_REQUIRED,readOnly,-Exception </prop>
            
<prop key="search*">PROPAGATION_REQUIRED,readOnly,-Exception </prop>
            
<prop key="save*">PROPAGATION_REQUIRED,-Exception </prop>
            
<prop key="modify*">PROPAGATION_REQUIRED,-Exception </prop>
            
<prop key="send*">PROPAGATION_REQUIRED,-Exception </prop>
            
<prop key="revoke*">PROPAGATION_REQUIRED,-Exception </prop>
            
<prop key="del*">PROPAGATION_REQUIRED,-Exception </prop>
            
<prop key="logging*">PROPAGATION_NOT_SUPPORTED,readOnly,-Exception </prop>
            
<prop key="*">PROPAGATION_SUPPORTS,-Exception </prop>
        
</props>
    
</property>
</bean>
<bean id="autoProxyCreator"
    class
="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    
<property name="interceptorNames">
        
<list><idref local="matchAllTxInterceptor" /></list>
    
</property>
    
<property name="proxyTargetClass"><value>true</value></property>
    
<property name="beanNames">
        
<list><value>*Service</value></list>
    
</property>
</bean>

配置第一步引入AOP代理autoProxyCreator,使用的是spring默认的jdk动态代理BeanNameAutoProxyCreator。
有两个属性要介绍一下:
1.拦截范围beanNames;例子中拦截范围是*Service,表示IOC容器中以Service结尾的bean,一般配置在spring.xml,serviceContext.xml之类的spring配置文件。
要注意这里不是值src下边的类。
bean配置信息:
<bean id="menuService" class="cn.ceopen.bss..service.impl.MenuServiceImpl"/>
有图有真相,下边是BeanNameAutoProxyCreator 调试信息。




2.截器interceptorNames
interceptorNames定义事务属性和事务管理器
配置第二步就是定义事务属性:事务传播范围、事务隔离级别
事务属性没什么好说的,使用spring进行事务管理的都了解,不在这里详细说了网上有大量资料。

配置第三步,指定事务管理器
这里用的是HibernateTransactionManager,spring提供对常见orm的事务支持。从spring源码可以看出HibernateTransactionManager.doGetTransaction()同时支持hibernate和jdbc。
支持hibernate和jdbc混合事务,不使用jta方式的话有个前提条件:使用同一个数据源,
这里所说的同一个数据源,不仅仅指物理上是同一个,在spring配置文件中也要是同一个。
我在开发中遇到过这个问题,最早定义了一个数据baseDataSource,hibernate和jdbc都使用此数据源,后来项目要求使用动态数据源就又配了一个数据源dynamicDataSource
仅在hibernate下做了改动,未改动jdbc对应配置,出现了事务控制问题。
出错了事务配置:
<bean id="sessionFactory"
        class
="com.sitechasia.webx.dao.hibernate3.NamedMoudleHbmLocalSessionFactoryBean">
    
<property name="dataSource" ref="dynamicDataSource" />
    
<!--与主题无关,省略部分内容-->
</bean>
<bean id="dynamicDataSource" class="cn.ceopen.bss.pub.base.dao.RoutingDataSource">      
   
<property name="targetDataSources">      
      
<map key-type="java.lang.String">      
         
<entry key="baseDataSource" value-ref="baseDataSource"/>  
      
</map>      
   
</property>      
   
<property name="defaultTargetDataSource" ref="baseDataSource"/>      
</bean>
 
<bean id="baseDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    
<!--与主题无关,省略部分内容-->
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 
    
<!--dataSource应该与sessionFactor一致-->
    
<property name="dataSource"><ref bean="baseDataSource"/></property> 
</bean> 
<bean id="abstractJdbcDao" abstract="true">
    
<property name="jdbc" ref="jdbcTemplate" />
</bean>
dao配置文件:
<bean id="actDao" class="cn.ceopen.bss.impl.ActDaoImpl" parent="abstractJdbcDao"/>
dao中同时支持hibernate操作和jdbc操作。

二、事务属性传播
先看这样一个列子:

1.基于jdk动态代理的AOP事务控制,只能针对接口。
在上边的配置文件中设置的事务属性对a3()都不起作用,a3()不能单独设计事务属性,只能继承接口方法的事务属性。
2.类自身事务嵌套
第一种情况:
AbcIService abcService;
BcdIService bcdService;
abcService.a1();
abcService.a2();
bcdService.b1();
这三个方法对应的事务属性都起作用。

第二种情况:
方法定义
public void a1() {
  bcdService.b1();
}
调用:
abcService.a1();
结果:
abcService.a1();
bcdService.b1();
这两个方法对应的事务属性都起作用。

第三种情况:
方法定义
public void a1() {
  this.a2();
}
调用:
abcService.a1();
结果:
abcService.a1();
abcService.a2();
a2()对应的事务属性配置不起作用。
解决办法:
1.把a2()拆到另一个类中去;
    缺点:麻烦,会把相关业务逻辑拆分了
2.调用是不用this.a2(),用abcService.a2();
public void a1() {
  abcService.a2();
}
缺点:要在类中注入自身引用。
原因分析:
为什么会出现这种情况呢?
我们在调用abcService.a1();时abcService是从IOC容器获取的,并AbcServiceImpl而是它的动态代理AbcServiceProxy。
示意图如下,spring不一定是这么实现的但原理一样.



AbcServiceProxy.a()方法进行了AOP增强,根据配置文件中事务属性增加了事务控制。
public void a1() {
  this.a2();
}
this.a2()这里this指的是AbcIServiceImpl并没用进行AOP增强,所以没用应用事务属性,只能继承a1()的事务属性。
public void a1() {
  abcService.a2();
}
abcService则实际是AbcServiceProxy.a2()所以可以应用事务属性。

所以在类内部进行方法嵌套调用,如果被嵌套的方法a2()需要区别于嵌套方法a1()的事务属性,需要:1.在接口公开;2.通过代理调用。


作者:zyskm
http://www.blogjava.net/zyskm

posted @ 2011-11-11 16:33 zyskm 阅读(1757) | 评论 (3)编辑 收藏

<<七步掌握业务分析>>阅读笔记

      上周在西单图书城看到本不错的书<<七步掌握业务分析>>,系统的讲了些业务分析方面的知识,以前看到业务分析方面的资料都是站在需求捕获分析的角度来写,向这么完整系统介绍业务分析概念方法的不多。本着书非借不能读的精神,我用了两个周末在西单图书大厦看完了整本书。记录一下阅读感受,同时结合一些自己的理解。
        目录结构见下图,大概是这个意思,名词记得不是很准确。


        一个个说一下。
        1.什么是业务分析
        一般来讲"什么是...?"这种问题都可以细分为这几个问题,什么是业务分析、业务分析做什么(工作范围)、跟系统分析有什么区别、什么人能做业务分析。
        让大家明白组织是怎么运作的,为了实现组织的目标提供解决方案。
        实际开发过程中谁都可以做业务分析工作,目前很少看到这门业务分析师这一角色,一般是需求和系统分析师主要来做。根据个人能力的不同介入的程度不同。
        说到范围,业务分析主要从业务需求的角度来考虑,区别于系统分析更多的从系统能否实现、怎么实现的角度来考虑。很多时候系统分析师是同时兼这两个角色的,优势是考虑问题有统一方向,缺点的是容易互相干扰。通用的解决思路是颜色帽子法,做哪块工作时戴那个帽子只想这部分的事情,先不想别的部分怎么办,先过今天再说明天。每一部分单独考虑后再进行综合考虑,这样工作才好开展,要不然一次想太多了事情就变得太复杂。
        2.什么人来做
        有人的地方就有江湖,既然在江湖里混就要了解这个江湖是什么人组成的,每个人的立场、对事情的认识程度、角色、权利、影响。对这些人有了认识,才能更好的认识人做的事情。
这一点一般的需求书上只是提了一下,不想这本书就组织架构、角色关系、沟通技巧各方面做了阐述。有个理论认识实际操作起来更容易有方向感。
        3.项目做什么
        很多开发人员经常是领导让做什么就做什么,作为一个业务分析师显然不能这么干。
        业务分析师很多时候起的是一个导游的角色,探险的时候大家全两眼一抹黑只能掉沟里了。
        谁发起的项目,项目要达成什么目标,对哪些人有益,对哪些人不利。这些都要了解,在项目的过程中才知道从哪方面去推动,避开可能会引起的麻烦。
        4.了解业务
        这个是当然了,业务分析师嘛,具体方法先不写了,都是写常见的,重要的是要经常实际总结提高。
        5.了解业务环境
        这也是一个江湖,更多的是从事情的角度进行分类
        6.了解技术环境
        业务分析虽然不用写代码技术还是要懂一点的,好的服装设计师都会自己做衣服(这可不是随便说的,我见过几个,呵呵)。
        7.提升自身价值
        洞悉事态,能够提出完整解决方案,这样的人当然是有价值的。做得越好越有价值。
        书中提到了几种提高技能方法:时间管理和一些分析技术,包括沟通技巧。
先写这么多。

作者:zyskm
http://www.blogjava.net/zyskm

posted @ 2011-11-02 17:18 zyskm 阅读(1824) | 评论 (2)编辑 收藏

基于spring的动态数据源

基于spring的动态数据源
项目过程中遇到这样一个需求,系统启动后动态设置数据源,不同用户登录系统后访问的数据库不同。
好在所有书库结构一致。
用spring 的AbstractRoutingDataSource解决了这个问题。
原理如图:

项目采用的是hibernate,直接在spring.xml设置sessionFactory的dataSource属性为动态数据源即可。
因为项目所有数据库结构都一致,为了避免每次设置数据源的时候要改一堆参数,修改了spring AbstractRoutingDataSource类增加了一个getTargetDataSources方法,获取当前数据源详细信息,在其基础上修改数据库名称、用户名、密码即可,不用每次设置一堆参数。
Map<String,ComboPooledDataSource> targetDataSources=dynamicDataSource.getTargetDataSources();
                
if(targetDataSources==null){
                    targetDataSources
=new HashMap<String, ComboPooledDataSource>();
                    targetDataSources.put(
"baseDataSource", baseDataSource);
                }

                targetDataSources.put(dataSourceName, subSystemDataSource);
                dynamicDataSource.setTargetDataSources(targetDataSources);
                dynamicDataSource.afterPropertiesSet();
另外,设置AbstractRoutingDataSource参数后要调用afterPropertiesSet()方法,spring容器才会进行加载操作。

在动态设置数据源方面,可以通过两种方式实现:
1.在action(项目使用struts)中进行设置,可以确保在每个servlet线程中数据源是一致的。
2.以aop方式,对service方法进行拦截,根据需求设置不同数据源。

posted @ 2011-10-24 17:11 zyskm 阅读(3575) | 评论 (2)编辑 收藏

开发过程注意事项(数据库方面)

在开发过程中数据库的操作和使用要有一定规范,不然会引起混乱。
下边是我们开发中具体例子,因为涉及公司在用项目详细代码就不列出来了,整个思路可供参考。

1.初始化脚本
各子系统建立自己的数据库初始化脚本,格式可参照附件产品管理初始化脚本sql.rar(需要解压到c:/sql才能在命令行执行,见init.sql说明)
包括两部分内容:1.建表语句(ddl);2.基础数据初始化(data)
建表语句由数据库设计文档(PowerDesigner)导出,基础数据由excel文件导出(sql.rar提供示例,开发框架提供工具支持DbUtilTest.testExcel2Sql ())
作用:
1.数据库结构和基础数据文档化
2.便于快速搭建开发测试环境,新建一套环境时不用拷贝原数据库而是执行脚本
3.便于独立开发测试,有一个干净的数据,避免开发测试依赖历史数据和调试过程中互相影响
2.数据库结构比对
在部署多套数据库时,怀疑表结构不一致,可使用DbUtilTest.testCompareDataBase ()进行检查。
执行后会在子系统根目录生成dbcompare.html 文件,参加附件。
说明:红色表示两个表结构不一致,绿色表示多出一表,黑色表示一致
 
3.数据库字符集(UTF-8)
create database dbname CHARACTER SET utf8 COLLATE utf8_bin
不单独对表和字段设置字符集,整个库统一使用utf-8
4.表名字段名
建库脚本中表名和字段名不区分大小写
5.数据库引擎(InnoDb)
目前主要使用的两种引擎MyIsam,InnoDb。MyIsam查询较快,不支持事务。InnoDb支持事务。
在建表sql指明引擎。
create table ***
(
   id bigint(11) not null auto_increment,
.........
   primary key (id)
)
type = innodb;
powerdesiner按如下方式设置:

posted @ 2011-10-24 16:24 zyskm 阅读(210) | 评论 (0)编辑 收藏

集群环境下log4j日志文件命名方式

    在项目中,通过log4j可以实现对不同模块不同级别日志输出到不同的日志文件中。
以xml格式为例:
<appender name="FILE_INFO" class="org.apache.log4j.RollingFileAppender">
    
<param name="File" value="/usr/local/logs/xxx_info.log"/>
    
<layout class="org.apache.log4j.PatternLayout">
        
<param name="ConversionPattern" value="%d %p [%c] [%M]:%L - %m%n"/>
    
</layout>
    
<filter class="org.apache.log4j.varia.LevelRangeFilter">
        
<param name="levelMin" value="INFO" />
        
<param name="levelMax" value="INFO" />
        
<param name="AcceptOnMatch" value="true" />
    
</filter>
</appender>
按这种方式在单机环境下可以很方便的查询日志。
但是在集群环境下,因为项目同时部署在多个机器上,log4j生成的日志文件在每台机器上都叫xxx_info.log,在开发维护的过程中很难区分那个文件是哪台服务上的,尤其在日志查询比较频繁的情况下做区分有一定的工作量。
    为解决这一问题,可以在生成日志文件时增加机器标识。如100_xxx_info.log,标识ip为172.20.80.100这台机器上的。
实现这一功能需要对log4j的Appender做些改动。
通过查看log4j源码可以看出来所有的文件输出都会继承FileAppender ,修改setFile(String file)方法即可实现。
重写DailyRollingFileAppender,改继承重写后的fileappender。
/** 从配置文件读取日志文件名 */
    
public void setFile(String file) {
        String val 
= file.trim();
        
int index = val.lastIndexOf('/'+ 1;
        String path 
= val.substring(0, index);
        String name 
= val.substring(index);
        fileName 
= path + getIpSuffix() + "_" + name;
    }


    
// 获取本机ip最后一位(双网卡内网ip)
    private String getIpSuffix() {
        String ip 
= null;
        String suffix 
= "";
        NetworkInterface ni;
        
try {
            ni 
= NetworkInterface.getByName("eth1");
            
if (ni == null)
                ni 
= NetworkInterface.getByName("eth0");
            Enumeration
<InetAddress> ias = ni.getInetAddresses();
            
for (; ias.hasMoreElements();) {
                InetAddress ia 
= ias.nextElement();
                
if (ia instanceof InetAddress) {
                    ip 
= ia.getHostAddress();
                }

            }

            
if (ip == null{
                InetAddress addr 
= InetAddress.getLocalHost();
                ip 
= addr.getHostAddress();
            }

        }
 catch (SocketException e1) {
            e1.printStackTrace();
        }
 catch (UnknownHostException e) {
            e.printStackTrace();
        }

        
if (ip != null{
            
int index = ip.lastIndexOf('.'+ 1;
            suffix 
= ip.substring(index);
        }

        
return suffix;
    }


posted @ 2011-10-24 15:33 zyskm 阅读(3414) | 评论 (6)编辑 收藏

mysql字符集和校对规则

字符集的概念大家都清楚,校对规则很多人不了解,一般数据库开发中也用不到这个概念,mysql在这方便貌似很先进,大概介绍一下。
简要说明
字符集和校对规则
字符集是一套符号和编码。校对规则是在字符集内用于比较字符的一套规则。
MySql在collation提供较强的支持,oracel在这方面没查到相应的资料。
不同字符集有不同的校对规则,命名约定:以其相关的字符集名开始,通常包括一个语言名,并且以_ci(大小写不敏感)、_cs(大小写敏感)或_bin(二元)结束
校对规则一般分为两类:
binary collation,二元法,直接比较字符的编码,可以认为是区分大小写的,因为字符集中'A'和'a'的编码显然不同。
字符集_语言名,utf8默认校对规则是utf8_general_ci
mysql字符集和校对规则有4个级别的默认设置:服务器级、数据库级、表级和连接级。
具体来说,我们系统使用的是utf8字符集,如果使用utf8_bin校对规则执行sql查询时区分大小写,使用utf8_general_ci 不区分大小写。不要使用utf8_unicode_ci。
如create database demo CHARACTER SET utf8; 默认校对规则是utf8_general_ci 。
 
Unicode与UTF8
Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储.
UTF8字符集是存储Unicode数据的一种可选方法。 mysql同时支持另一种实现ucs2。

详细说明

字符集(charset):是一套符号和编码。
校对规则(collation):是在字符集内用于比较字符的一套规则,比如定义'A'<'B'这样的关系的规则。不同collation可以实现不同的比较规则,如'A'='a'在有的规则中成立,而有的不成立;进而说,就是有的规则区分大小写,而有的无视。
每个字符集有一个或多个校对规则,并且每个校对规则只能属于一个字符集。

binary collation,二元法,直接比较字符的编码,可以认为是区分大小写的,因为字符集中'A'和'a'的编码显然不同。除此以外,还有更加复杂的比较规则,这些规则在简单的二元法之上增加一些额外的规定,比较就更加复杂了。
mysql5.1在字符集和校对规则的使用比其它大多数数据库管理系统超前许多,可以在任何级别进行使用和设置,为了有效地使用这些功能,你需要了解哪些字符集和 校对规则是可用的,怎样改变默认值,以及它们怎样影响字符操作符和字符串函数的行为。

校对规则一般有这些特征:

 两个不同的字符集不能有相同的校对规则。
 每个字符集有一个默认校对规则。例如,utf8默认校对规则是utf8_general_ci。
 存在校对规则命名约定:它们以其相关的字符集名开始,通常包括一个语言名,并且以_ci(大小写不敏感)、_cs(大小写敏感)或_bin(二元)结束


确定默认字符集和校对
 字符集和校对规则有4个级别的默认设置:服务器级、数据库级、表级和连接级。
 数据库字符集和校对
 每一个数据库有一个数据库字符集和一个数据库校对规则,它不能够为空。CREATE DATABASE和ALTER DATABASE语句有一个可选的子句来指定数据库字符集和校对规则:
 例如:
 CREATE DATABASE db_name    DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
 MySQL这样选择数据库字符集和数据库校对规则:
·         如果指定了CHARACTER SET X和COLLATE Y,那么采用字符集X和校对规则Y。
·         如果指定了CHARACTER SET X而没有指定COLLATE Y,那么采用CHARACTER SET X和CHARACTER SET X的默认校对规则。
·         否则,采用服务器字符集和服务器校对规则。
在SQL语句中使用COLLATE
•使用COLLATE子句,能够为一个比较覆盖任何默认校对规则。COLLATE可以用于多种SQL语句中。
使用WHERE:
 select * from pro_product where product_code='ABcdefg' collate utf8_general_ci
Unicode与UTF8
Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储.Unicode码可以采用UCS-2格式直接存储.mysql支持ucs2字符集。
UTF-8就是在互联网上使用最广的一种unicode的实现方式。其他实现方式还包括UTF-16和UTF-32,不过在互联网上基本不用。
UTF8字符集(转换Unicode表示)是存储Unicode数据的一种可选方法。它根据 RFC 3629执行。UTF8字符集的思想是不同Unicode字符采用变长字节序列编码:
·         基本拉丁字母、数字和标点符号使用一个字节。
·         大多数的欧洲和中东手写字母适合两个字节序列:扩展的拉丁字母(包括发音符号、长音符号、重音符号、低音符号和其它音符)、西里尔字母、希腊语、亚美尼亚语、希伯来语、阿拉伯语、叙利亚语和其它语言。
·         韩语、中文和日本象形文字使用三个字节序列。

posted @ 2011-10-24 14:59 zyskm 阅读(1806) | 评论 (3)编辑 收藏

Tomcat6结构分析

Tomcat6结构分析
tomcat在实际开发中大量使用,对其结构不了解的话在配置使用过程中容易出现各种奇怪的问题。

Server.xml在tomcat处于核心地位。当Tomcat启动时,Apache Commons Digester就会读取这份配置文件。
XML结构的本质是嵌套式的机构,Tomcat自身也按这种结构设计。
从这份示例server.xml文档也可以看出,Tomcat的结构和XML的结构是多么的一致。因此,要想弄清楚Tomcat的结构,最快捷的方法就是阅读配置文件。
tomcat结构如图:

对应的server.xml
 1<Server port="8008" shutdown="SHUTDOWN">
 2  <Service name="Catalina">
 3    <Connector port="8080" protocol="HTTP/1.1" 
 4               connectionTimeout="20000" 
 5               redirectPort="8443" URIEncoding="utf-8" />
 6    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
 7    <Engine name="Catalina" defaultHost="localhost">
 8      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
 9             resourceName="UserDatabase"/>
10      <Host name="localhost"  appBase="webapps"
11            unpackWARs="true" autoDeploy="true"
12            xmlValidation="false" xmlNamespaceAware="false">
13        <Context path="/test" reloadable="true" docBase="" />
14      </Host>
15    </Engine>
16  </Service>
17</Server>
l
各部分说明:
1.Server

Server就是Tomcat自身,一个Tomcat程序实例(instance)。
代表整个容器,是Tomcat实例的顶层元素.由org.apache.catalina.Server接口来定义。
提供完整的JVM的独立组件,它可以包含一个或多个“Service”实例。服务器在指定的端口上监听shutdown命令。
它的一个重要属性就是关闭Tomcat的端口号。

测试命令:
    telnet localhost 8008   
    输入:SHUTDOWN
    结果:关闭tomcat

属性说明:
    <Server port="8008" shutdown="SHUTDOWN">
    1)className指定实现org.apache.catalina.Server接口的类.默认值为org.apache.catalina.core.StandardServer
    2)port指定Tomcat监听shutdown命令端口.终止服务器运行时,必须在Tomcat服务器所在的机器上发出shutdown命令.该属性是必须的.
    3)shutdown指定终止Tomcat服务器运行时,发给Tomcat服务器的shutdown监听端口的字符串.该属性必须设置

2.Service
    Service由Connector和Engine组成,Engine可以对应一个或多个Connector。
    Connector 主要负责对外交流,Engine主要处理Connector接受的请求,主要是处理内部事务。
    是 Service 将它们连接在一起,共同负责处理所有Connector所获得的客户请求。
3.Connector
   Connector代表与客户程序实际交互的给件,它负责接收客户请求,以及向客户返回响应结果.
每个connector都有一个端口号,常用的Connector有两种,一种是HTTP Connector用来接收http请求,另一种是AJP Connect
<Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout
="20000" 
               redirectPort
="8443" URIEncoding="utf-8" />
    
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

    port : 在端口号8080处侦听来自客户browser的HTTP1.1请求.如果把8080改成80,则只要输入 http://localhost/ 即可
    protocol:设定Http协议,默认值为HTTP/1.1
4.Engine
Service中的请求处理机,接受和处理来自Connector 的请求。
5.Host
它由Host接口定义.一个Engine元素可以包含多个<Host>元素.每个<Host>的元素定义了一个虚拟主机.它包含了一个或多个Web应用.

<Host name="localhost"  appBase="webapps"
            unpackWARs
="true" autoDeploy="true"
            xmlValidation
="false" xmlNamespaceAware="false">

appBase : 指定虚拟主机的目录,可以指定绝对目录,也可以指定相对于<CATALINA_HOME>的相对目录.如果没有此项,默认为<CATALINA_HOME>/webapps.
它将匹配请求和自己的Context的路径,并把请求转交给对应的Context来处理
autoDeploy:如果此项设为true,表示Tomcat服务处于运行状态时,能够监测appBase下的文件,如果有新有web应用加入进来,会自运发布这个WEB应用
unpackWARs:如果此项设置为true,表示把WEB应用的WAR文件先展开为开放目录结构后再运行.如果设为false将直接运行为WAR文件
alias:指定主机别名,可以指定多个别名
deployOnStartup:如果此项设为true,表示Tomcat服务器启动时会自动发布appBase目录下所有的Web应用.
如果Web应用中的server.xml没有相应的<Context>元素,将采用Tomcat默认的Context
6.Context
它由Context接口定义.是使用最频繁的元素.每个<Context元素代表了运行在虚拟主机上的单个Web应用.一个<Host>可以包含多个<Context>元素.

Context 代表 Servlet 的 Context,它具备了 Servlet 运行的基本环境,理论上只要有 Context 就能运行 Servlet 了。简单的 Tomcat 可以没有 Engine 和 Host。

Context 最重要的功能就是管理它里面的 Servlet 实例,Servlet 实例在 Context 中是以 Wrapper 出现的,还有一点就是 Context 如何才能找到正确的 Servlet 来执行它呢? Tomcat5 以前是通过一个 Mapper 类来管理的,Tomcat5 以后这个功能被移到了 request 中。

<Context path="/test" reloadable="true" docBase="" />

path : 该Context的路径名是"",故该Context是该Host的默认Context
docBase : 该Context的根目录是webapps/mycontext/
reloadable:如果这个属性设为true, Tomcat服务器在运行状态下会监视在WEB-INF/classes和Web-INF/lib目录CLASS文件的改运.如果监视到有class文件被更新,服务器自重新加载Web应用
useNaming:指定是否支持JNDI,默认值为了true
cookies指定是否通过Cookies来支持Session,默认值为true

<Context path="" docBase="mycontext" debug="0"/>

生命周期(Lifecycle)

Tomcat使用的一种“插件式(plugable)”的结构,管理这些插件的生命周期。当用户启动tomcat时,tomcat中的插件也会一起启动,当关闭时也是同样。通过Lifecycle接口:LifecycleEvent和LifecycleListener 实现的。

几乎所有的Tomcat组件都实现了Lifecycle接口,主要的控制组件都有LifecycleSuport对象,它们使用这个对象来管理其中的所有子Lifecycle对象。使用LifecycleSupport对象,当顶层对象调用start()方法时,它就会调用它的子组件的start()方法,子组件的子组件又会调用start()方法。

LifecycleListener接口可以被添加到任何层次的Tomcat容器 (Server, Service, Engine, Host, or Context),在Server这个级别,默认的Listener有三个。用户可以定义自己的Listener,不过需要将其在server.xml或context.xml中添加配置。用户自定义的Listener需要继承LifecycleListene接口。

 

posted @ 2011-10-24 14:17 zyskm 阅读(1509) | 评论 (0)编辑 收藏