﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-常言笑的家-随笔分类-技术总结</title><link>http://www.blogjava.net/wealupa/category/23621.html</link><description>Spring, Hibernate, Struts, Ajax, RoR</description><language>zh-cn</language><lastBuildDate>Thu, 28 Jun 2012 13:10:19 GMT</lastBuildDate><pubDate>Thu, 28 Jun 2012 13:10:19 GMT</pubDate><ttl>60</ttl><item><title>Perl、PHP、Python、Java和Ruby的比较</title><link>http://www.blogjava.net/wealupa/archive/2012/06/28/381724.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 28 Jun 2012 07:41:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2012/06/28/381724.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/381724.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2012/06/28/381724.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/381724.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/381724.html</trackback:ping><description><![CDATA[<div>提问<br /><br />&#9670; Perl、Python、Ruby和PHP各自有何特点?<br /><br />&#9670; 为什么动态语言多作为轻量级的解决方案?<br /><br />&#9670; LAMP为什么受欢迎?<br /><br />&#9670; Ruby on Rails为什么会流行?<br /><br />&#9670; 编程语言的发展趋势是什么?<br /><br />讲解<br /><br />&#8220;剩下四种动态语言，我们将之归为后台脚本语言。&#8221;冒号说着画了张图表&#8212;&#8212;<br /><br /><br /><br />引号听得仔细：&#8220;我记得您开始是把这些语言划分为C族静态语言、非C族静态语言和动态语言三类的。&#8221;<br /><br />冒号解释：&#8220;那是按语法来划分的，偏重理论;现在是按应用来划分，偏重实践。&#8221;<br /><br />句号旋即联想到：&#8220;这种分法貌似三层架构&#8212;&#8212;前台语言对应表现层;平台语言和后台脚本语言对应业务逻辑层;系统语言对应数据层。&#8221;<br /><br />&#8220;的 确有几分神似，但千万不可混淆。&#8221;冒号提醒道，&#8220;三层架构(three-layer  architecture)是模块设计上的逻辑划分[1];而这里是按语言应用范围进行的物理划分&#8212;&#8212;与用户交互的是前台语言，与机器交互的是系统语言， 介于其中的为前台提供服务同时又需要底层系统服务的是后台语言。&#8221;<br /><br />逗号询问：&#8220;后台语言又细分成平台语言与后台脚本语言?&#8221;<br /><br />&#8220;这 是基于程序(program)与脚本(script)、静态与动态而分的。&#8221;冒号进行说明，&#8220;其实Perl，PHP，Python和Ruby都有自己的虚 拟机(virtual  machine)，从这种意义上说它们也可作为平台语言。但在实际应用中，它们没有Java平台和.NET平台那种整合凝聚力和核心作用，通常作为轻量级 的解决方案。&#8221;<br /><br />问号想探个究竟：&#8220;这是由于它们都是动态语言的缘故吗?&#8221;<br /><br />冒号回答：&#8220;理论上动态语言同样能承担大型应 用，但实践上它们多作为粘合语言或用于中小型应用。用句时髦的话来形容，暂时还是主流的配角或非主流的主角。毕竟在运行效率、类型安全、可用资源、开发工 具、技术支持等方面，它们与Java、C#相比尚有一定差距。另外它们同属&#8216;草根&#8217;语言，虽有开源社区的大力支持，在影响力上与后者未可同日而语。&#8221;<br /><br />叹号揣测：&#8220;说不定在不久的将来，动态语言也会成为主流的主角。&#8221;<br /><br />&#8220;世 易时移，殊难逆料。但有一点可以肯定，语言的发展趋势一定是动静结合、刚柔并济。&#8221;冒号断言，&#8220;一方面以Java和C#为代表的静态语言中嫁接了动态语言 的枝条;另一方面以Java和.NET为代表的平台与动态语言的交壤地带也在逐步扩大。比如JRuby允许Ruby与Java之间互相调用，类似的还有 Jython、IronRuby、IronPython等等。此外值得一提的是，动态语言最活跃的舞台当数LAMP，L-A-M-P。&#8221;<br /><br />引号接茬：&#8220;L是Linux，A是Apache，M是MySQL，P是PHP。这四大组件形成了一个完整的开源网络开发平台。&#8221;<br /><br />冒号补充道：&#8220;P也可指Perl、Python，甚至Ruby。&#8221;<br /><br />逗号调侃：&#8220;可惜Ruby的&#8216;R&#8217;比&#8216;P&#8217;多了一根尾巴。&#8221;<br /><br />&#8220;有 人为了自圆其说，干脆让P表示&#8216;Programming  language&#8217;，这下所有语言都囊括其中了。老外就喜欢玩这种首字母缩略(acronym)的文字游戏，尤其LAMP正好还有&#8216;灯&#8217;的含义，寓意开源 世界的一盏明灯，他们一定更得意了。&#8221;冒号语带调笑，&#8220;前面我们曾提及，网络应用是生长动态语言最肥沃的土壤，而LAMP就是这块土壤上搭建的平台。作为 网络平台，LAMP以其开放灵活、开发迅速、部署方便、高可配置、安全可靠、成本低廉等特色而与Java平台和.NET平台鼎足三分，尤其受中小企业的欢 迎。LAMP中Linux是操作系统，Apache是Web服务器，MySQL是数据库系统，而我们当下最关心的是&#8216;P族语言&#8217;：PHP、Perl、 Python还有Ruby。&#8221;<br /><br />问号建议：&#8220;作为动态语言，它们的共性上节课已经谈了不少，能说说它们的个性吗?&#8221;<br /><br />&#8220;它们 的个性极为鲜明：Perl凝练晦涩，Python优雅明晰，Ruby精巧灵动，PHP简明单纯。先看老大哥Perl，它博采众家之长，综合了C语言的结 构、sed的正则表达式、AWK的关联数组(associative array)、Lisp的表(list)和Unix  Shell的命令，此外还有借鉴了一种语言，你们知道是哪种吗?&#8221;冒号忽然卖了个关子。<br /><br />逗号猜想：&#8220;应该是某种OOP语言吧。&#8221;<br /><br />&#8220;Perl 中确有不少C++的影子，但它的对象模型在5.0以后才引入，典型的半路出家，远不如前面的特征那么自然。与其说是一种自然而然的发展，不如说是在OOP 潮流裹挟下的一种身不由己的迎合。真正深入骨髓的借鉴是自然语言。&#8221;冒号给出了答案，&#8220;我们提过，Perl的发明者Larry  Wall是一名语言学家，他认为程序语言应该与自然语言一样，简洁自然、易读易写、表达多样、不拘一格。Perl还有不少的格言或哲学，使得编程语言一改 严谨刻板的面孔，散发出浓郁的人文气息。&#8221;<br /><br />叹号幽了一默：&#8220;我见过Perl的代码，人文气息没闻出来，但我怀疑有乙醚气息&#8212;&#8212;看一会就觉得晕晕乎乎的。&#8221;<br /><br />众人大笑。<br /><br />&#8220;有 人仅用一行Perl代码就实现了RSA算法，你看了那还不得当场晕倒啊?&#8221;冒号打趣道，&#8220;Perl的各种魔符好似一把把锋利的剪刀，做起文本裁剪之类的工 作来游刃有余。这是它最大的长处，当初Perl就是Wall用来做Unix系统管理的，以后在CGI上的广泛应用也得益于此。这也赋予Perl极强的粘合 力，因而有&#8216;internet上的胶带(duct  tape)[2]&#8217;的说法。它又号称瑞士军刀，精练而复杂，实用而强大。但Perl过于灵活自由，缺乏规范，影响了程序的可读性、一致性、整洁性和可维护 性。不熟悉该语言的固然如读天书，熟悉语言而不熟悉问题的也颇费思量。相比之下Python被认为是Perl有力的挑战者，不仅在于它天然的OO设计和丰 富的类库，更重要的是它对程序员友好度大大超过Perl。Python也有一系列的被称为禅(Zen)的哲学，不少与Perl是针锋相对的。比 如：Perl认为做一件事可以有多种方法，而Python认为一件事应该最好只有一种方法;Perl追求语言的表现力，Python追求简单优 雅;Perl喜欢隐性暗示，Python强调显性明示;Perl强调紧凑，Python强调松散;  Perl的语法和语义丰富，Python的语法和语义简单而类库丰富。或许Python最让人不习惯的是它对空白符敏感性。&#8221;<br /><br />引号感到惊奇：&#8220;对空白符敏感?这个倒真怪异。&#8221;<br /><br />冒 号见惯不怪：&#8220;虽然有点违反习惯，但非常符合Python一贯的规范简洁的风格&#8212;&#8212;一方面从语法上保证了良好的编码风格;另一方面，每个代码块不再需要起 始的大括号或begin/end之类的，减少了的代码行数。顺便插一句，另外一种优雅的语言Haskell同样对空白符敏感，或许优雅正是来自对细节和规 范的重视吧。此外许多人抱怨Python中的自引用self太多，殊不知这也是它倡导显式表达的一种体现。总的看来，Python主要的问题还是在性能效 率上不尽如人意。&#8221;<br /><br />叹号好奇地问：&#8220;Ruby怎么样?据说它将取代Java。&#8221;<br /><br />&#8220;不要轻言&#8216;取代&#8217;二字。&#8221;冒号规诫 道，&#8220;Java没有取代C++，也不会被Ruby取代，至多只是一种再分配。不过Ruby的确是门很可爱的语言，兼具Perl的表现力和Python的可 读性。Ruby背后最具特色的理念是：关注程序员使用语言时的感受超过语言本身的功能。通俗地说，兵器的称手比锋利更重要;文雅地说，应给予程序员更多的 人文关怀。就拿代码块(block)和迭代器(iterator)来说，虽然均非Ruby首创，但其语法最为赏心悦目。类似的例子比比皆是。Ruby的元 编程能力特别强，也是它高度灵活的一种体现，但并不是所有人都喜欢这种风格。Ruby的主要弱点有两个：一个与Python类似，在性能上还有待提高;另 一个是它的线程由用户空间(user space)而不是内核空间(kernel  space)来管理[3]，不能充分利用多核或多CPU。真正让Ruby变得炙手可热的是web应用框架 Ruby on  Rails(RoR)的成功，它们还催生了Java平台上的Groovy语言和Groovy on  Grails框架。RoR奉行的CoC(Convention over Configuration)和DRY(Don&#8217;t repeat  yourself )原则以及MVC架构看似了无新意，但与Ruby结合之后，便如一只猱身而上灵猫，立刻衬托出Java和.NET大象般的身影。&#8221;<br /><br />逗号有些怀疑：&#8220;框架竟然捧红了语言，框架真有这么重要吗?&#8221;<br /><br />&#8220;如 果web应用中动态页面较少或业务逻辑不复杂，框架的价值并不大。以前CGI编程就是往Perl之类的代码中嵌入HTML代码，如同Java中的 Servlet;PHP则单纯地在HTML代码中插入PHP代码，如同早期的JSP。没有MVC，也不管什么三层架构，更没有ORM。但是&#8212;&#8212;&#8221;冒号拖了 个转折音，&#8220;一旦业务逻辑变得复杂，开发人员增多，手工作坊式编程开始捉襟见肘，引入框架这个流水生产线来提高生产力便是大势所趋。&#8221;<br /><br />句号不解：&#8220;我想Perl、Python和PHP一定也有不少框架，Java中的框架更是泛滥成灾，何以独独RoR脱颖而出?&#8221;<br /><br />冒 号作出分析：&#8220;正值web2.0和敏捷开发(agile  development)的概念流行之际，RoR将AJAX与Ruby组合在一起成为绝佳的回应。以前各种web应用框架是不少，但在RoR之前轻量级套 餐式解决方案并不多。Perl中的Catalyst、Python中的Pylon还有PHP中的CakePHP等应是效仿之作。因此RoR出现的时机可说 是不早不晚，正当其时。此外，Perl和PHP由于过于流行，反而有不少的历史包袱，人们习惯了将表示逻辑和业务逻辑编织在一起。至于Java企业解决方 案，框架太多，搭配组合更多，增加了选择的难度。即使采用最常见的轻量级SSH(Struts+Spring+Hibernate)组合，维护起来也比 RoR繁杂得多。&#8221;<br /><br />叹号愈发担忧：&#8220;听这意思，Java还是危险啊!&#8221;<br /><br />&#8220;言之过早。&#8221;冒号不以为然，&#8220;首先RoR还有待进一步检验，目前无论是应用广度还是深度上尚无法与Java相提并论;其次Java在性能、安全等方面还是有不少优势，而这些对于大型和关键性的应用来说尤为重要。即使在中小型web应用中，RoR较之PHP还远为不及。&#8221;<br /><br />问号接下话题：&#8220;PHP为何如此流行?&#8221;<br /><br />&#8220;因 为它简单、专一。&#8221;冒号答得很干脆，&#8220;与Python和Ruby一开始就定位通用语言不同，PHP是专为网络而生的。同早期的Perl相似，PHP起初主 要起文本过滤器的作用，只不过Perl多处理文件流(file stream)，而PHP多处理套接字流(socket  stream)。PHP的语法简单，且为网络应用度身定造，受到网络开发人员的追捧当在情理之中。它虽很实用很流行，但并不完美。比如：变量名大小写敏感 而函数名大小写不敏感;函数命名规则不一致;不支持namespace和unicode[4];与Perl一样，它的对象模型不是先天的，直到PHP  5才真正完善;对线程支持不足;相比Perl、Python和Ruby，它的功能稍显单薄等等。&#8221;<br /><br />引号突然想起：&#8220;我记得您在第一堂课提到PHP还能用于桌面应用。&#8221;<br /><br />&#8220;不 仅PHP，Perl、Python还有Ruby，都能作为前台语言来开发命令行或图形界面的应用。同样地，VB、Delphi和JavaScript也能 作为后台语言。现代的程序语言既有自己的专长，又向通用化和全能化发展，以争取更多的生存空间。试想一下，现代的程序员又何尝不是如此呢?&#8221;言及于此，冒 号收住话题，&#8220;语言简评告一段落，还有不少既有趣又有用的语言，在此就不一一评说了。我们看到，每种编程语言都有其独特的惯例用法和哲学理念，它们与编程 范式一道形成了语言的编程风格。体悟愈深者编程语感愈强，思维与语言愈交融无碍，渐从必然王国走向自由王国。&#8221;<br /><br />逗号满怀憧憬：&#8220;那是不是一种人剑合一的境界?&#8221;<br /><br />&#8220;或许人器合一更准确吧，程序员可不能只会一种兵器哟。&#8221;冒号故意抠他的字眼，&#8220;现在请大家每人写一句对本节课的感言。&#8221;<br /><br />众人沉思片刻，齐齐挥笔而就&#8212;&#8212;<br /><br />叹号&#8212;&#8212;没有最好的语言，只有最合适的语言。<br /><br />逗号&#8212;&#8212;没有糟糕的语言，只有糟糕的程序员。<br /><br />问号&#8212;&#8212;没有一种语言是万能的，只会一种语言是万万不能的。<br /><br />引号&#8212;&#8212;废除对语言的宗教信仰，建立对语言的哲学思维。<br /><br />句号&#8212;&#8212;编程就是在人脑和电脑之间寻找最佳平衡点的过程。<br /><br />冒号读罢大悦，顺手一掌拍出五记马屁：&#8220;精彩之极!可谓字字珠玑、句句联璧啊。兹决定，给诸位的奖赏是&#8212;&#8212;立时下课!&#8221;<br /><br />众人欣然领赏而去。<br /><br />插语<br /><br />[1] 有两种三层架构，一种是three-layer architecture，一种是three-tier architecture。它们经常换用，但其实是有分别的：前者仅仅在逻辑进行划分，而后者在物理上也进行了划分&#8212;&#8212;不同层次的模块运行在不同的主机上。<br /><br />[2] 不少地方译作&#8216;输送带&#8217;、&#8216;传送带&#8217;，因为duct有&#8216;输送管&#8217;、&#8216;导管&#8217;之意，于是想当然地认为这表明Perl在internet上起着输送作用。殊不知&#8216;duct type&#8217;专指一种万能的粘性极强的胶带，用以比喻Perl的粘合力。<br /><br />[3] 这类线程被称为绿色线程(green thread)，也称伪线程。据称Ruby2.0将支持原生线程(native thread)。<br /><br />[4] PHP将在5.3.0支持namespace，将在6.0支持unicode。<br /><br />总结<br /><br />&#9670; 比起Java平台和.NET平台，动态语言轻便灵活、开发效率高，但整合凝聚力还不够，在运行效率、类型安全、可用资源、开发工具、技术支持以及影响力等方面也有一定差距，故通常作为轻量级的解决方案。<br /><br />&#9670; LAMP是由Linux、Apache、MySQL和包括PHP、Perl、Python或Ruby在内的脚本语言组成的网络开发平台，具有开放灵活、开发迅速、部署方便、高可配置、安全可靠、成本低廉等优点。<br /><br />&#9670; Perl精练、复杂、强大、灵活、自由、隐晦、表现力强，但规范性、可读性、一致性、整洁性和可维护性较差。<br /><br />&#9670; Python优雅规范、简洁明晰、易学易用、类库丰富，但效率稍差，有些人不喜欢它对空白符敏感的特性。<br /><br />&#9670; Ruby语法精巧、高度灵活，兼具Perl的表现力和Python的可读性，尤其注重程序员的感受，但其性能和线程模型尚有待改进。<br /><br />&#9670; PHP简单、专一、实用、流行，在但相比其他三种语言，在语法和功能上稍有欠缺。<br /><br />&#9670; RoR是一种轻量级套餐式的web应用解决方案，是由好的设计(MVC架构和CoC、DRY原则)加上好的语言(Ruby)在好的时机(web2.0和敏捷开发风行之际)打造出的好的框架。<br /><br />&#9670; 静态语言与动态语言从语言特征到运行环境都在逐渐融合。<br /><br />&#9670; 程序员应该与程序语言一样，既要有自己的专长，又要向通用化和全能化发展。<br /><br />&#9670; 编程语言惯例用法、哲学理念和编程范式形成了语言的编程风格。</div><img src ="http://www.blogjava.net/wealupa/aggbug/381724.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2012-06-28 15:41 <a href="http://www.blogjava.net/wealupa/archive/2012/06/28/381724.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LAMP网站架构方案分析</title><link>http://www.blogjava.net/wealupa/archive/2012/06/28/381722.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 28 Jun 2012 07:00:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2012/06/28/381722.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/381722.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2012/06/28/381722.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/381722.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/381722.html</trackback:ping><description><![CDATA[<div>LAMP（Linux-Apache-MySQL-PHP）网站架构是目前国际流行的Web框架，该框架包括：Linux操作系统，Apache网 络服务器，MySQL数据库，Perl、PHP或者Python编程语言，所有组成产品均是开源软件，是国际上成熟的架构框架，很多流行的商业应用都是采 取这个架构，和Java/J2EE架构相比，LAMP具有Web资源丰富、轻量、快速开发等特点，微软的.NET架构相比，LAMP具有通用、跨平台、高 性能、低价格的优势，因此LAMP无论是性能、质量还是价格都是企业搭建网站的首选平台。<p>　　对于大流量、大并发量的网站系统架构来说，除 了硬件上使用高性能的服务器、负载均衡、CDN等之外，在软件架构上需要重点关注下面几个环节：使用高性能的操作系统（OS）、高性能的网页服务器 （Web Server）、高性能的数据库（Databse）、高效率的编程语言等。下面我将从这几点对其一一讨论。</p><p>　　<strong>操作系统</strong></p><p>　 　Linux操作系统有很多个不同的发行版，如Red Hat Enterprise Linux、SUSE Linux  Enterprice、Debian、Ubuntu、CentOS等，每一个发行版都有自己的特色，比如RHEL的稳定，Ubuntu的易用，基于稳定性 和性能的考虑，操作系统选择CentOS（Community ENTerprise Operating System）是一个理想的方案。</p><p>　 　CentOS（Community ENTerprise Operating System）是Linux发行版之一，是RHEL/Red Hat  Enterprise Linux的精简免费版，和RHEL为同样的源代码，不过，RHEL和SUSE  LE等企业版，提供的升级服务均是收费升级，无法免费在线升级，因此要求免费的高度稳定性的服务器可以用CentOS替代Red Hat  Enterprise Linux使用。</p><p><img alt="LAMP网站架构方案分析" src="http://www.williamlong.info/upload/1908_1.jpg" /></p><p>LAMP网站架构图</p><p>　　<strong>Web服务器、缓存和PHP加速</strong></p><p>　 　Apache是LAMP架构最核心的Web  Server，开源、稳定、模块丰富是Apache的优势。但Apache的缺点是有些臃肿，内存和CPU开销大，性能上有损耗，不如一些轻量级的Web 服务器（例如nginx）高效，轻量级的Web服务器对于静态文件的响应能力来说远高于Apache服务器。</p><p>　　Apache做为Web  Server是负载PHP的最佳选择，如果流量很大的话，可以采用nginx来负载非PHP的Web请求。nginx是一个高性能的HTTP和反向代理服 务器，Nginx以它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。Nginx不支持PHP和CGI等动态语言，但支持负载均衡和容 错，可和Apache配合使用，是轻量级的HTTP服务器的首选。</p><p>　　Web服务器的缓存也有多种方案，Apache提供了自己的缓存模 块，也可以使用外加的Squid模块进行缓存，这两种方式均可以有效的提高Apache的访问响应能力。Squid  Cache是一个Web缓存服务器，支持高效的缓存，可以作为网页服务器的前置cache服务器缓存相关请求来提高Web服务器的速度，把Squid放在 Apache的前端来缓存Web服务器生成的动态内容，而Web应用程序只需要适当地设置页面实效时间即可。如访问量巨大则可考虑使用memcache作 为分布式缓存。</p><p>　　PHP的加速使用eAccelerator加速器，eAccelerator是一个自由开放源码PHP加速器，优化和动 态内容缓存，提高了性能PHP脚本的缓存性能，使得PHP脚本在编译的状态下，对服务器的开销几乎完全消除。它还有对脚本起优化作用，以加快其执行效率。 使PHP程序代码执效率能提高1-10倍。</p><p>　　具体的解决方案有以下几种：</p><p>　　1、squid + Apache + PHP + eAccelerator</p><p>　　使用Apache负载PHP，使用squid进行缓存，html或图片的请求可以直接由squid返回给用户。很多大型网站都采用这种架构。</p><p>　　2、nginx/Apache + PHP（fastcgi） + eAccelerator</p><p>　　使用nginx或Apache负载PHP，PHP使用fastcgi方式运行，效率较高。</p><p>　　3、nginx + Apache + PHP + eAccelerator</p><p>　　此方案综合了nginx和Apache的优点，使用Apache负载PHP，nginx负责解析其他Web请求，使用nginx的rewrite模块，Apache端口不对外开放。</p><p>　　<strong>数据库</strong></p><p>　 　开源的数据库中，MySQL在性能、稳定性和功能上是首选，可以达到百万级别的数据存储，网站初期可以将MySQL和Web服务器放在一起，但是当访问 量达到一定规模后，应该将MySQL数据库从Web Server上独立出来，在单独的服务器上运行，同时保持Web  Server和MySQL服务器的稳定连接。</p><p>　　当数据库访问量达到更大的级别，可以考虑使用MySQL Cluster等数据库集群或者库表散列等解决方案。</p><p>　　总的来说，LAMP架构的网站性能会远远优于Windows IIS + ASP + Access（例如月光博客）这样的网站，可以负载的访问量也非常大，国内的大量个人网站如果想要支撑大访问量，采用LAMP架构是一个不错的方案。</p><p>　　综上所述，基于LAMP架构设计具有成本低廉、部署灵活、快速开发、安全稳定等特点，是Web网络应用和环境的优秀组合。</p></div><img src ="http://www.blogjava.net/wealupa/aggbug/381722.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2012-06-28 15:00 <a href="http://www.blogjava.net/wealupa/archive/2012/06/28/381722.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大型网站架构设计及技术分析</title><link>http://www.blogjava.net/wealupa/archive/2012/06/28/381720.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 28 Jun 2012 06:53:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2012/06/28/381720.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/381720.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2012/06/28/381720.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/381720.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/381720.html</trackback:ping><description><![CDATA[<div><span style="font-size:16px;">一个小型的网站，比如个人网站，可以使用最简单的html静态页面就实现了，配合一 些图片达到美化效果，所有的页面均存放在一个目录下，这样的网站对系统架构、性能的要求都很简单，随着互联网业务的不断丰富，网站相关的技术经过这些年的 发展，已经细分到很细的方方面面，尤其对于大型网站来说，所采用的技术更是涉及面非常广，从硬件到软件、编程语言、数据库、WebServer、防火墙等 各个领域都有了很高的要求，已经不是原来简单的html静态网站所能比拟的。 </span><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp; 大型网站，比如门户网站。在面对大量用户访问、高并发请求方面，基本的解决方案集中在这样几个环节：使用高性能的服务器、高性能的数据库、高效率的编程语言、还有高性能的Web容器。但是除了这几个方面，还没法根本解决大型网站面临的高负载和高并发问题。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp; 上面提供的几个解决思路在一定程度上也意味着更大的投入，并且这样的解决思路具备瓶颈，没有很好的扩展性，下面我从低成本、高性能和高扩张性的角度来说说我的一些经验 。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-size: 14px; padding-top: 0px"><strong><span style="font-size:16px;">1、HTML静态化</span></strong></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp;   其实大家都知道，效率最高、消耗最小的就是纯静态化的html页面，所以我们尽可能使我们的网站上的页面采用静态页面来实现，这个最简单的方法其实也是最 有效的方法。但是对于大量内容并且频繁更新的网站，我们无法全部手动去挨个实现，于是出现了我们常见的信息发布系统CMS  ，像我们常访问的各个门户站点的新闻频道，甚至他们的其他频道，都是通过信息发布系统来管理和实现的，信息发布系统可以实现最简单的信息录入自动生成静态 页面，还能具备频道管理、权限管理、自动抓取等功能，对于一个大型网站来说，拥有一套高效、可管理的CMS是必不可少的。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp; 除了门户和信息发布类型的网站，对于交互性要求很高的社区类型网站来说，尽可能的静态化也是提高性能的必要手段，将社区内的帖子、文章进行实时的静态化，有更新的时候再重新静态化也是大量使用的策略，像Mop的大杂烩就是使用了这样的策略，网易社区等也是如此。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp;   同时，html静态化也是某些缓存策略使用的手段，对于系统中频繁使用数据库查询但是内容更新很小的应用，可以考虑使用html静态化来实现，比如论坛中 论坛的公用设置信息，这些信息目前的主流论坛都可以进行后台管理并且存储在数据库中，这些信息其实大量被前台程序调用，但是更新频率很小，可以考虑将这部 分内容进行后台更新的时候进行静态化，这样避免了大量的数据库访问请求。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><strong><span style="font-size:16px;">2、图片服务器分离</span></strong></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp;   大家知道，对于Web服务器来说，不管是Apache、IIS还是其他容器，图片是最消耗资源的，于是我们有必要将图片与页面进行分离，这是基本上大型网 站都会采用的策略，他们都有独立的图片服务器，甚至很多台图片服务器。这样的架构可以降低提供页面访问请求的服务器系统压力，并且可以保证系统不会因为图 片问题而崩溃，在应用服务器和图片服务器上，可以进行不同的配置优化，比如apache在配置ContentType的时候可以尽量少支持，尽可能少的 LoadModule，保证更高的系统消耗和执行效率。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><strong><span style="font-size:16px;">3、数据库集群和库表散列</span></strong></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp;   大型网站都有复杂的应用，这些应用必须使用数据库，那么在面对大量访问的时候，数据库的瓶颈很快就能显现出来，这时一台数据库将很快无法满足应用，于是我 们需要使用数据库集群或者库表散列。在数据库集群方面，很多数据库都有自己的解决方案，  Oracle、Sybase等都有很好的方案，常用的MySQL提供的Master/Slave也是类似的方案，您使用了什么样的DB，就参考相应的解决 方案来实施即可。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp;   上面提到的数据库集群由于在架构、成本、扩张性方面都会受到所采用DB类型的限制，于是我们需要从应用程序的角度来考虑改善系统架构，库表散列是常用并且 最有效的解决方案。我们在应用程序中安装业务和应用或者功能模块将数据库进行分离，不同的模块对应不同的数据库或者表，再按照一定的策略对某个页面或者功 能进行更小的数据库散列，比如用户表，按照用户ID进行表散列，这样就能够低成本的提升系统的性能并且有很好的扩展性。sohu的论坛就是采用了这样的架 构，将论坛的用户、设置、帖子等信息进行数据库分离，然后对帖子、用户按照板块和ID进行散列数据库和表，最终可以在配置文件中进行简单的配置便能让系统 随时增加一台低成本的数据库进来补充系统性能。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;"><strong>4、缓存</strong> </span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp;   缓存一词搞技术的都接触过，很多地方用到缓存。网站架构和网站开发中的缓存也是非常重要。这里先讲述最基本的两种缓存。高级和分布式的缓存在后面讲述。架 构方面的缓存，对Apache比较熟悉的人都能知道Apache提供了自己的缓存模块，也可以使用外加的Squid模块进行缓存，这两种方式均可以有效的 提高Apache的访问响应能力。</span></p><p style="padding-bottom: 0px; line-height: 21px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; margin-bottom: 0.5em; margin-left: 0px; font-size: 14px; margin-right: 0px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp;  网站程序开发方面的缓存，Linux上提供的Memory Cache是常用的缓存接口，可以在web开发中使  用，比如用Java开发的时候就可以调用MemoryCache对一些数据进行缓存和通讯共享，一些大型社区使用了这样的架构。另外，在使用web语言开 发的时候，各种语言基本都有自己的缓存模块和方法。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><strong><span style="font-size:16px;">5、镜像</span></strong></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp;   镜像是大型网站常采用的提高性能和数据安全性的方式，镜像的技术可以解决不同网络接入商和地域带来的用户访问速度差异，比如ChinaNet和 EduNet之间的差异就促使了很多网站在教育网内搭建镜像站点，数据进行定时更新或者实时更新。在镜像的细节技术方面，这里不阐述太深，有很多专业的现 成的解决架构和产品可选。也有廉价的通过软件实现的思路，比如Linux上的rsync等工具 。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-size: 14px; padding-top: 0px"><strong><span style="font-size:16px;">6、负载均衡</span></strong></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp; 负载均衡将是大型网站解决高负荷访问和大量并发请求采用的终极解决办法。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin-top: 1em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; margin-left: 0px; font-size: 14px; margin-right: 0px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp; 负载均衡技术发展了多年，有很多专业的服务提供商和产品可以选择，我个人接触过一些解决方法，其中有两个架构可以给大家做参考。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">硬件四层交换</span></p><p style="padding-bottom: 0px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp;   第四层交换使用第三层和第四层信息包的报头信息，根据应用区间识别业务流，将整个区间段的业务流分配到合适的应用服务器进行处理。第四层交换功能就象是虚 IP，指向物理服务器。它传输的业务服从的协议多种多样，有HTTP、FTP、NFS、Telnet或其他协议。这些业务在物理服务器基础上，需要复杂的 载量平衡算法。在IP世界，业务类型由终端TCP或UDP  端口地址来决定，在第四层交换中的应用区间则由源端和终端IP地址、TCP和UDP端口共同决定。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp; 在硬件四层交换产品领域，有一些知名的产品可以选择，比如Alteon、F5等，这些产品很昂贵，但是物有所值，能够提供非常优秀的性能和很灵活的管理能力。Yahoo中国当初接近2000台服务器使用了三四台Alteon就搞定了。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">软件四层交换</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp; 大家知道了硬件四层交换机的原理后，基于OSI模型来实现的软件四层交换也就应运而生，这样的解决方案实现的原理一致，不过性能稍差。但是满足一定量的压力还是游刃有余的，有人说软件实现方式其实更灵活，处理能力完全看你配置的熟悉能力。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp;  软件四层交换我们可以使用Linux上常用的LVS来解决，LVS就是Linux Virtual  Server，他提供了基于心跳线heartbeat的实时灾难应对解决方案，提高系统的鲁棒性，同时可供了灵活的虚拟VIP配置和管理功能，可以同时满 足多种应用需求，这对于分布式的系统来说必不可少。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp;   一个典型的使用负载均衡的策略就是，在软件或者硬件四层交换的基础上搭建squid集群，这种思路在很多大型网站包括搜索引擎上被采用，这样的架构低成 本、高性能还有很强的扩张性，随时往架构里面增减节点都非常容易。这样的架构我准备空了专门详细整理一下和大家探讨。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp; 对于大型网站来说，前面提到的每个方法可能都会被同时使用到，我这里介绍得比较浅显，具体实现过程中很多细节还需要大家慢慢熟悉和体会，有时一个很小的squid参数或者apache参数设置，对于系统性能的影响就会很大，希望大家一起讨论，达到抛砖引玉之效。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">讨论大型高并发负载网站的系统架构问题，作者提出了几点建议：</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">1. HTML静态化，这可以通过CMS 自动实现；</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">2. 图片服务器分离（类似的，在视频网站中，视频文件也应独立出来）；</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; padding-top: 0px"><span style="font-size:16px;">3. 数据库集群和库表散列，Oracle、MySQL等DBMS都有完美的支持；</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">4. 缓存，比如使用 Apache的Squid模块，或者是开发语言的缓存模块，；</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">5. 网站镜像；</span></p><p style="padding-bottom: 0px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">6. 负载均衡。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp;   作者将负载均衡称为&#8220;是大型网站解决高负荷访问和大量并发请求采用的终极解决办法&#8221;，并提出&#8220;一个典型的使用负载均衡的策略就是，在软件或者硬件四层交换 的基础上搭建squid集群&#8221;。在实践时可以考虑建立应用服务器集群和Web服务器集群，应用服务器集群可以采用Apache+Tomcat集群和 WebLogic集群等，Web服务器集群可以用反向代理，也可以用NAT的方式，或者多域名解析均可。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp;  从提升网站性能的角度出发，静态资源不应和应用服务器放在一起，数据库服务器也应尽  量独立开来。在典型的MVC模式中，由谁来完成数据逻辑处理的，对系统性能有着至关重要的影响。以Java  EE为例，在OO的设计思想中，我们强调系统的抽象、重用、可维护性，强调下层的更改不会扩散到上层逻辑，强调系统移植的便捷性，  因而往往存在一种过分抽象的问题，比如在Hibernate的基础上再加入一层DAO的设计。另外一方面，却会忽视利用DBMS本身的优秀特性（存储过 程、触发器）来完成高效的数据处理。诚然，如果客户要求将数据从Oracle移植到MySQL，那么DBMS特性的东西越少，移植便越容易。但事实上，在 实践中，提出类似移植要求的情况非常少见，因此在做架构设计时，不一定为了这种潜在的需求而大幅牺牲系统的性能与稳定性。此外，我不建议采用分布式数据库 管理结构，这样带来的开销太大，数据维护也是个头痛的问题，尽可能采用集中式的数据管理。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp;   在商业系统中，算法逻辑本身并不复杂，在这种情况下，程序设计本身的好坏不会对系统的性能造成致命的影响。重要的影响因素反而变为软件系统架构本身。在传 统的CORBA、J2EE、DCOM等对象模  型中，我们看到专家们对分布式对象计算的理论偏好，但实践证明，对象的分布带来的恶劣影响远远胜过其积极意义。这也  是现在轻量级的开发框架受推崇的一个重要原因。如果能用简单的，就不要用复杂的，例如能够用Python、RoR完成的任务，是否一定要用Java来做？ 我看未必。对于用户来说，他们关心的不是采用什么先进的技术，而是我们提供的产品能否满足他的需求。而且，Python、RoR这些开发工具已经强大到足 以应对大部分网站应用，在各种缓存系统的帮助下，在其他技术的协调配合下，完全能够胜任高负载高并发的网站访问任务。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp; 在HTML静态化方面，如果是对于更新相对较少的页面，可以这样处理，例如新闻、社区通告、或者类似与淘宝网的产品分类信息。但若数据更新频繁，这样做的意义便不大。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">&nbsp;&nbsp;&nbsp; 网站镜像是个传统的技术，更高级的应用来自流媒体领域的CDN(Content Delivery Network)，CDN的概念可以由流媒体数据扩展到图片、视频文件等静态资源的传输。不过，在电子商务领域，很少有这样的应用。</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px">&nbsp;</p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">开源平台的高并发集群思考目前碰到的高并发应用，需要高性能需求的主要是两个方面:</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">1。网络</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">2。数据库 </span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">这两个方面的解决方式其实还是一致的</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">1。充分接近单机的性能瓶颈，自我优化</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">2。单机搞不定的时候(数据传输瓶颈:单位时间内磁盘读写/网络数据包的收发cpu计算瓶颈)，把负荷分担给多台机器，就是所谓的负载均衡</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">网络方面单机的处理</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">1。底层包收发处理的模式变化(从select 模式到epoll / kevent)</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">2。应用模式的变化</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">2.1 应用层包的构造方式</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">2.2 应用协议的实现</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">2.3 包的缓冲模式</span></p><p style="padding-bottom: 0px; line-height: 21px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; margin-bottom: 0.5em; margin-left: 0px; font-size: 14px; margin-right: 0px; padding-top: 0px"><span style="font-size:16px;">2.4 单线程到多线程</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">网络负载均衡的几个办法</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">1。代理模式：代理服务器只管收发包，收到包以后转给后面的应用服务器群（服务器群后可能还会有一堆堆的数据库服务器等等），并且把返回的结果再返回给请求端</span></p><p style="padding-bottom: 0px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">2。虚拟代理ip：代理服务器收发包还负载太高，那就增加多台代理服务器，都来管包的转发。这些代理服务器可以用统一的虚拟ip，也可以单独的ip</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">3。p2p：一些广播的数据可以p2p的模式来减轻服务器的网络压力</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">数据库(指mysql)单 机的处理</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">1。数据库本身结构的设计优化（分表，分记录，目的在于保证每个表的记录数在可定的范围内）</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">2。sql语句的优化</span></p><p style="padding-bottom: 0px; line-height: 21px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; margin-bottom: 0.5em; margin-left: 0px; font-size: 14px; margin-right: 0px; padding-top: 0px"><span style="font-size:16px;">3。master + slave模式</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">数据库集群的处理</span></p><p style="padding-bottom: 0px; line-height: 21px; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; margin-bottom: 0.5em; margin-left: 0px; font-size: 14px; margin-right: 0px; padding-top: 0px"><span style="font-size:16px;">1。master + slave模式 （可有效地处理 并发查询）</span></p><p style="padding-bottom: 0px; line-height: 21px; margin: 1em 0px 0.5em; padding-left: 0px; padding-right: 0px; font-family: verdana, sans-serif; font-size: 14px; padding-top: 0px"><span style="font-size:16px;">2。mysql cluster 模式 （可有效地处理并发数据变化）</span></p></div><img src ="http://www.blogjava.net/wealupa/aggbug/381720.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2012-06-28 14:53 <a href="http://www.blogjava.net/wealupa/archive/2012/06/28/381720.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大型互联网网站架构心得</title><link>http://www.blogjava.net/wealupa/archive/2012/06/28/381719.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 28 Jun 2012 06:48:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2012/06/28/381719.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/381719.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2012/06/28/381719.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/381719.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/381719.html</trackback:ping><description><![CDATA[<div>     <p>我们知道，对于一个大型网站来说，可伸缩性是非常重要的，怎么样在纵向和横向有良好的可伸缩性，就需要在做架构设计的时候考虑到一个分的原则，我想在多个方面说一下怎么分：</p><p> &nbsp; &nbsp;首先是横向的分：</p><p> &nbsp; &nbsp;1. 大的网站化解为多个小网站：当我们一个网站有多个功能的时候，可以考虑把这个网站拆分成几个小模块，每一个模块可以是一个网站，这样的话我们到时候就可以很灵活地去把这些网站部署到不同的服务器上。</p><p>  &nbsp; &nbsp;2.  静态动态分离：静态文件和动态文件最好分离开成2个网站，我们知道静态网站和动态网站对服务器来说压力的侧重不同，前者可能重IO后者重CPU，那么我们 在选择硬件的时候也可以有侧重，而且静态和动态内容的缓存策略也不一样。典型的应用，我们一般会有独立的文件或图片服务器。而且，使用不用的域名还可以提 高浏览器并行加载的能力。</p><p> &nbsp; &nbsp;3. 按照功能来分：比如有一个模块是负责上传的，上传操作很消耗时间，如果和其它应用混在一起的话很可能，一点点访问就会使服务器瘫痪，这种特殊的模块应该分开。安全的不安全的也要分开，还需要考虑到以后SSL的购买。</p><p> &nbsp; &nbsp;4. 我们不一定要全部用自己的服务器，搜索、报表可以依靠别人的服务，比如google的搜索和报表服务，自己做的不一定比得过别人，服务器带宽都省了。</p><p> &nbsp; &nbsp;其次是纵向的分：</p><p> &nbsp; &nbsp;1. 文件也相当于数据库，IO的流量可能比数据库还大，这也算是纵向级别的访问，上传的文件图片一定要和WEB服务器分开。当然，数据库和网站都放在一个服务器上的很少了，这是最基本的。</p><p>  &nbsp; &nbsp;2.  对于涉及到数据库访问的动态程序来说，我们可以使用一个中间层（所谓的应用层或逻辑层）来访问数据库（部署在独立的服务器上），最大的好处就是缓存和灵活 性。缓存的内存占用比较大，我们要把它和网站进程分开，而且这样做我们可以很方便的去改变一些数据访问的策略，即使到时候数据库有分布的话在这里可以做一 个调配工作，这样灵活性就很大了。还有好处是中间层可以做电线网通桥梁，可能网通访问双线再访问电信会比网通直接访问电信服务器快。</p><p> &nbsp;  &nbsp;有人说我不分，我可以做负载均衡，对，是可以的，但是如果分的话，同样的10台机器肯定比不分10台机器可以承受更多的访问量，而且对硬件的需求可能不 会很高，因为知道需要哪个硬件特别好。争取让每一个服务期都不空闲，又都不是太忙，合理进行组合调整和扩充，这样的系统伸缩性就高了，能根据访问量来调整 的前提就是之前有考虑到分，分的好处是灵活性、伸缩性、隔离性以及安全性。</p><p> &nbsp; &nbsp;对服务器来说，我们有几点是要长期观察的，任何一点都可能是瓶颈：</p><p> &nbsp; &nbsp;1. CPU：动态文件的解析需要比较多的CPU，CPU出现瓶颈就要看是不是哪个功能过长时间占用线程，如果是就分出去。或者就是每一个请求处理时间不长，但是访问量很高，那么就加服务器。CPU是好东西，不能让他干等，不做事情。</p><p> &nbsp; &nbsp;2. 内存：缓存从IIS进程独立出去，一般对WEB服务器来说内存不够的情况不是很多。内存比磁盘快，要合理利用。</p><p> &nbsp; 3. 磁盘IO：用性能监视器找到哪些文件IO特别大，找到了就分到独立的一组文件服务器上去，或者直接做CDN。磁盘慢，大规模读取数据的应用靠缓存，大规模写入数据的应用可以靠队列来降低突发的并发。</p><p>  &nbsp; &nbsp;4.  网络：我们知道，网络的通讯是比较慢的，比磁盘还慢，如果是做分布式缓存，分布式计算的话，要考虑到物理服务器之间网络通讯的时间，当然，在流量大了以 后，这可以提高系统的接纳能力一个等级。静态内容可以借助CSD分担一部分，在做服务器假设的时候还要考虑中国特色的电信网通情况以及防火墙。</p><p> &nbsp; 对SQL SERVER数据库服务器来说：</p><p> &nbsp; &nbsp;其实还是水平分割和纵向分割，一个二维表，水平分割就是横过来切一刀，纵向分割就是竖直切一刀：</p><p> &nbsp; &nbsp;1、纵向分割就是，我们不同的应用可以分到不同的DB中，不同的实例中，或者说把某个拥有很多字段的表拆分成小表。</p><p>  &nbsp;  &nbsp;2、横向分割就是，某些应用可能不负载，比如用户注册，但是用户表会非常大，可以把大表分开。可以采用表分区，数据存储在不同文件上，然后再部署到独立 物理服务器增加IO吞吐以改善读写性能，土一点的做法就是自己定期把老的数据存档。表分区的另外一个优势可以增加数据查询速度，因为我们的页索引可以有多 层了，就像一个文件夹中的文件不要太多，多分几层文件夹一样。</p><p> &nbsp; &nbsp;3、还可以通过数据库镜像、复制订阅、事物日志，把读写分开到不同的镜像物理数据库上，一般来说够用，如果还不行可以用硬件来实现数据库的负载均衡。当然，对于BI，我们可能还会有数据仓库。</p><p> &nbsp; &nbsp; &nbsp;架构上考虑到了这些之后，流量大了，就可以在这个的基础上再去调整或者做WEB服务器或者应用服务器的负载均衡。很多时候我们都是在重复发现问题-》找到瓶颈-》解决这个过程。</p><p> &nbsp; &nbsp;典型的架构如下：</p><p id="div4556062" style="text-align:center;"><img src="http://img.ddvip.com/2012/0619/201206190553134255.jpg" height="451" width="546"  alt="" /></p><p> &nbsp; &nbsp;动态WEB服务器配好点的CPU，静态WEB服务器和文件服务器磁盘好点<br style="font-size:12px;" /> &nbsp; &nbsp;应用服务器内存大点，缓存服务器也是，数据库服务器当然内存和CPU都要好</p><p>上次说的&#8220;分&#8221;是一个比较大的原则也是一个比较高层的原则，这次我想说一下其它两个原则：并与换。</p><p> 并</p><p> &nbsp; &nbsp; 为什么要分？是因为我们希望通过分来提高系统的承载能力，那并又是并什么呢？我想了一下有几个方面可以并：</p><p> &nbsp; &nbsp; 1. 合并用户请求，最基本的就是合并CSS/图片/脚本，还可以合并页面。不过合并就可能产生流量的浪费，需要有一个平衡点。</p><p> &nbsp; &nbsp;2. 合并接口的粒度，如果做分布式应用的话，我们可能不会直接访问数据库而是调用应用层提供的接口，由于是网络调用，代价比较大，因此在设计的时候尽量提供粒度比较粗的接口，一次调用返回比较多的数据，而不是细化到添加删除修改的层次。</p><p> &nbsp; &nbsp;3. 合并接口的部署，对于频繁的跨机器调用可以考虑有一些数据冗余，把跨网络的服务编程进程间通讯，甚至转到客户端来做。比如论坛发贴时候脏词的过滤，直接调用应用层提供的接口（跨机器）是可以的，但是可能代价比较大，可以把这个接口使用IPC方式部署在本机。</p><p> 换</p><p> &nbsp; &nbsp; 时间换空间，空间换时间是常见的做法，具体一点说：</p><p>  &nbsp; &nbsp; 1.  缓存。缓存的重要性早计算机的硬件中就有重要的体现。对于网站，有很多种缓存，可以是客户端资源的缓存，可以是页面输出缓存，也可以是应用层的数据缓存， 目的都是一样的，或是减少了服务器请求次数，或是减少了请求的处理过程，或是减少了数据库的访问次数。当然，生成静态文件也可以算是一种缓存。不访问磁盘 固然不可能，但是我们要极大限度降低磁盘访问的机会。</p><p> &nbsp; &nbsp;2.  有的时候为了获取极快的响应，我们还会不惜代价采用重复计算。比如，我们的某个操作很可能会由于网络问题等原因响应比较慢，在设计的时候可以有一个统一的 处理接口，由这个接口分发到不同的服务器去异步实现这个操作，哪个服务器先返回了结果我们就用这个结果，然后杀死其他服务器的冗余操作。</p><p> &nbsp; &nbsp;3. 网站一般追求比较快的响应，一般不太会在比较高的层次用时间来换取空间，但是在一些用户独有数据的处理算法上可能还是会考虑到空间的节省问题。</p><p> &nbsp; &nbsp;4. 有的时候我们会用一些聚合表来存放聚合数据，也就是进行一些预计算提高复杂计算（比如报表）的性能。当然，对于数据分析，构建多维数据库也是一种不错的选择。</p><p>  &nbsp; &nbsp;  有很多网友留言说说的比较粗，没有什么具体的东西。我觉得架构这个东西很难去说具体怎么做，因为具体实施的时候要看情况去应用的，由于没有完美的东西，所 以做架构通常是去做一个平衡，很可能某一个侧重不同会影响到架构的实施。希望我的这些文章能给大家一个提示的作用，看了之后如果你觉得&#8220;这点我倒没有考虑 到，以后要注意&#8221;那或许就是最大的帮助了，下面我想说一些其它方面的问题，每一条都很零散，算是一个补充吧：</p><p> &nbsp; &nbsp; 1.  到底是采用已有的东西还是自己去做需要详细考虑的，采用别人的东西可能比较稳定，但是自己的控制少了一点，采用自己做的东西可以很灵活，但是可能会问题比 较多。不管怎么样，我们在采用一个第三方框架的时候务必要进行缜密的调查，看到他的不足，否则项目很可能在后期被这个框架制约，反之，决定自己去做一个框 架的时候也要看到自己需要什么其他框架不能提供的东西。</p><p> &nbsp; &nbsp;2. 数据传输的时候可以做压缩，但要考虑到压缩解压缩需要CPU资源，在IO（磁盘，带宽，传输能力）和CPU之间有一个平衡的考虑。</p><p> &nbsp; &nbsp;3. 理想的可伸缩性架构是可以自由增加或替换服务器，无需去停机维护或做很大的调整。在使用一个统一的调度中心来调度这些服务器，分配请求的时候，我们要考虑一下调度服务器能承受多少流量。</p><p> &nbsp; 4. 使用大量的廉价服务器还是少量的高配服务器？如何根据需求来组合服务器发挥最大作用。</p><p> &nbsp; &nbsp;5. 对于分布式构架，我们尽量让每一个节点保持简单的逻辑，尽量减少同一层次节点之间的依赖，另外。需要有统一的地方来管理所有的节点。</p><p> &nbsp; &nbsp;6. 功能分解、使用异步进行整合、故障转移、失效保护。</p><p> &nbsp; 7. 软件的架构升级和计算机硬件的架构升级很像，可能有一段时期，我们是在慢慢提高整体能力，2年也才提高了几倍，之后发现只有通过某种彻底的架构改变才能提高数十倍的能力，升级之后，我们或许又会遇到其他问题。就像CPU，是简单提高主频还是彻底更换架构。</p><p> &nbsp; &nbsp;8. 数据方面，读写分离、数据库分隔、功能划分、缓存、镜像。</p><p> &nbsp; 9. 硬件网络上的架构很重要，但软件开发中的一些细节不可忽略，好的架构不意味着不需要代码审阅。</p></div><img src ="http://www.blogjava.net/wealupa/aggbug/381719.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2012-06-28 14:48 <a href="http://www.blogjava.net/wealupa/archive/2012/06/28/381719.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大型网站架构设计及技术总结</title><link>http://www.blogjava.net/wealupa/archive/2012/06/28/381717.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 28 Jun 2012 06:37:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2012/06/28/381717.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/381717.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2012/06/28/381717.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/381717.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/381717.html</trackback:ping><description><![CDATA[<div>随着中国大型IT企业信息化速度的加快，大部分应用的数据量和访问量都急剧增加，大型企业网站正面临性能和高数据访问量的压力，而且对存储、安全以及信息检索等等方面都提出了更高的要求&#8230;&#8230;  <br />&nbsp;&nbsp;&nbsp;&nbsp; 本文中，我想通过几个国外大型IT企业及网站的成功案例，从Web技术人员角度探讨如何积极地应对国内大型网站即将面临的扩展（主要是技术方面，而较少涉及管理及营销等方面）矛盾。  <br /><br /><strong>一、 国外大型IT网站的成功之道</strong> <br />(一) MySpace <br />&nbsp;&nbsp;&nbsp;&nbsp; 今天，MySpace已经成为全球众口皆碑的社区网站之王。尽管一流和营销和管理经验自然是每个IT企业取得成功的首要因素，但是本节中我们却抛弃这一点，而主要着眼于探讨在数次面临系统扩张的紧急关头MySpace是如何从技术方面采取应对策略的。  <br />第一代架构&#8212;添置更多的Web服务器  <br />&nbsp;&nbsp;&nbsp;&nbsp;  MySpace最初的系统很小，只有两台Web服务器（分担处理用户请求的工作量）和一个数据库服务器（所有数据都存储在这一个地方）。那时使用的是   Dell双CPU、4G内存的系统。在早期阶段，MySpace基本是通过添置更多Web服务器来对付用户暴增问题的。但到在2004年早期，在   MySpace用户数增长到五十万后，其数据库服务器已经开始疲于奔命了。 <br /><br />第二代架构&#8212;增加数据库服务器  <br />&nbsp;&nbsp;&nbsp;&nbsp; 与增加Web服务器不同，增加数据库并没那么简单。如果一个站点由多个数据库支持，设计者必须考虑的是，如何在保证数据一致性的前提下让多个数据库分担压力。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;  MySpace运行在三个SQL   Server数据库服务器上&#8212;一个为主，所有的新数据都向它提交，然后由它复制到其它两个；另两个数据库服务器全力向用户供给数据，用以在博客和个人资料 栏显示。这种方式在一段时间内效果很好&#8212;&#8212;只要增加数据库服务器，加大硬盘，就可以应对用户数和访问量的增加。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;  这一次的数据库架构按照垂直分割模式设计，不同的数据库服务于站点的不同功能，如登录、用户资料和博客。垂直分割策略利于多个数据库分担访问压力，当用户 要求增加新功能时，MySpace只需要投入新的数据库加以支持。在账户到达二百万后，MySpace还从存储设备与数据库服务器直接交互的方式切换到    SAN（存储区域网络）&#8212;用高带宽、专门设计的网络将大量磁盘存储设备连接在一起，而数据库连接到SAN。这项措施极大提升了系统性能、正常运行时间和可 靠性。然而，当用户继续增加到三百万后，垂直分割策略也变得难以维持下去。<br /><br />第三代架构&#8212;转到分布式计算架构  <br />&nbsp;&nbsp;&nbsp;&nbsp;  几经折腾，最终，MySpace将目光移到分布式计算架构&#8212;&#8212;它在物理上分布的众多服务器，整体必须逻辑上等同于单台机器。拿数据库来说，就不能再像过去 那样将应用拆分，再以不同数据库分别支持，而必须将整个站点看作一个应用。现在，数据库模型里只有一个用户表，支持博客、个人资料和其他核心功能的数据都 存储在相同数据库。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;  既然所有的核心数据逻辑上都组织到一个数据库，那么MySpace必须找到新的办法以分担负荷&#8212;&#8212;显然，运行在普通硬件上的单个数据库服务器是无能为力 的。这次，不再按站点功能和应用分割数据库，MySpace开始将它的用户按每百万一组分割，然后将各组的全部数据分别存入独立的SQL   Server实例。目前，MySpace的每台数据库服务器实际运行两个SQL   Server实例，也就是说每台服务器服务大约二百万用户。据MySpace的技术人员说，以后还可以按照这种模式以更小粒度划分架构，从而优化负荷分 担。  <br /><br />第四代架构&#8212;求助于微软方案  <br />&nbsp;&nbsp;&nbsp;&nbsp; 2005年早期，账户达到九百万，MySpace开始用微软的C#编写ASP.NET程序。在收到一定成效后，MySpace开始大规模迁移到ASP.NET。  <br />&nbsp;&nbsp;&nbsp;&nbsp; 账户达到一千万时，MySpace再次遭遇存储瓶颈问题。SAN的引入解决了早期一些性能问题，但站点目前的要求已经开始周期性超越SAN的I/O容量&#8212;&#8212;即它从磁盘存储系统读写数据的极限速度。  <br /><br />第五代架构&#8212;增加数据缓存层并转到支持64位处理器的SQL Server 2005  <br />&nbsp;&nbsp;&nbsp;&nbsp;   2005年春天，MySpace账户达到一千七百万，MySpace又启用了新的策略以减轻存储系统压力，即增加数据缓存层&#8212;&#8212;位于Web服务器和数据库 服务器之间，其唯一职能是在内存中建立被频繁请求数据对象的副本，如此一来，不访问数据库也可以向Web应用供给数据。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;  2005年中期，服务账户数达到两千六百万时，MySpace因为我们对内存的渴求而切换到了还处于beta测试的支持64位处理器的SQL   Server 2005。升级到SQL Server 2005和64位Windows Server   2003后，MySpace每台服务器配备了32G内存，后于2006年再次将配置标准提升到64G。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; 事实上，MySpace的Web服务器和数据库仍然经常发生超负荷，其用户频繁遭遇&#8220;意外错误&#8221;和&#8220;站点离线维护&#8221;等告示，他们不得不在论坛抱怨不停&#8230;&#8230;  <br />&nbsp;&nbsp;&nbsp;&nbsp;   MySpace正是在这样不断重构站点软件、数据库和存储系统中，才一步步走到今天。事实上，MySpace已经成功解决了很多系统扩展性问题，其中存在 相当的经验值得我们借鉴。MySpace系统架构到目前为止保持了相对稳定，但其技术人员仍然在为SQL   Server支持的同时连接数等方面继续攻坚，尽可能把事情做到最好。 <br /><br />(二) Amazon <br />&nbsp;&nbsp;&nbsp;&nbsp; 亚马逊书店无疑是电子商务发展的里程碑。2000年到现在，世界网络业腥风血雨。Amazon曾经成为网络泡沫的头号代表。如今，当这个&#8220;最大的泡沫&#8221;用几经易改的数字把自己变成了坚实的IT巨人。  <br />&nbsp;&nbsp;&nbsp;&nbsp;   历览Amazon发展过程，其成功经验在于，它创造性地进行了电子商务中每一环节的探索，包括系统平台的建设，程序编写、网站设立、配送系统等等方面。用   Amazon当家人贝索斯的话说就是，&#8220;在现实世界的商店最有力的武器就是地段，地段，地段，而对于我们来说最重要的三件事就是技术，技术，技术。&#8221;   <br /><br />(三) eBay  <br />&nbsp;&nbsp;&nbsp;&nbsp; eBay是世界闻名的拍卖网站，eBay公司通信部主管凯文?帕斯格拉夫认为，&#8220;eBay成功的最重要原因在于公司管理和服务。&#8221;  <br />&nbsp;&nbsp;&nbsp;&nbsp; 其成功的奥秘可以列举为以下几点： <br />&nbsp;&nbsp;&nbsp;&nbsp; &#9312;敢为天下先&#8212;在网络尚不普及的时代，eBay率先进入网络拍卖领域；  <br />&nbsp;&nbsp;&nbsp;&nbsp;   &#9313;依托虚拟商场所产生的特有的&#8220;零库存&#8221;是eBay公司取得成功的另一个重要原因。该公司的核心业务没有任何库存风险，所有的商品都是由客户提供，它只需 要负责提供虚拟的拍卖平台&#8212;网络和软件。所以，eBay公司的财务报表上不会出现&#8220;库存费用&#8221;和&#8220;保管费用&#8221;等。  <br />&#9314;自eBay公司成立开始，它就一直遵循两条&#8220;黄金原则&#8221;：建设虚拟社区，给网民以家的感觉；保证网站稳定安全地运行。<br /><strong>二、  国内大型网站开发时的几点建议</strong>  <br />&nbsp;&nbsp;&nbsp;&nbsp; 从本节开始，我们将结合国内外大型IT网站在技术扩展方面的沉痛教训和成功经验，探讨在如今刚刚开始的Web  2.0时代如何应对国内网站即将面临的数据访问量增加（甚至是急剧膨胀）的问题，并提出一些供参考的策略和建议。 <br /><br />(四) 搭建科学的系统架构  <br />&nbsp;&nbsp;&nbsp;&nbsp;   构建大型的商业网站绝对不可能像构建普通的小型网站一样一蹴而就，需要从严格的软件工程管理的角度进行认真规划，有步骤有逻辑地进行开发。对于大型网站来 说，所采用的技术涉及面极其广泛，从硬件到软件、编程语言、数据库、Web服务器、防火墙等各个领域都有了很高的要求，已经不是原来简单的html静态网 站所能比拟的。以著名的Yahoo!为例，他们的每一个大型网站工程都需要大量相应专业人员的参与。  <br /><br />(五) 页面静态化  <br />&nbsp;&nbsp;&nbsp;&nbsp;   可不要小看纯静态化的HTML页面！其实在很多情况下，HTML往往意味着&#8220;效率最高、消耗最小&#8221;，所以我们尽可能使我们的网站上的页面采用静态页面来实 现。但是，对于大量内容并且频繁更新的网站，我们无法全部手动实现，因此可以开发相应的自动化更新工具，例如我们常见的信息发布系统CMS。像我们经常访 问的各个门户站点的新闻频道，甚至他们的其他频道，都是通过信息发布系统来管理和实现的。信息发布系统可以实现最简单的信息录入自动生成静态页面，还能具 备频道管理、权限管理、自动抓取等功能，对于一个大型网站来说，拥有一套高效、可管理的CMS是必不可少的。  <br /><br />(六) 存储问题 <br />&nbsp;&nbsp;&nbsp;&nbsp; 存储也是一个大问题，一种是小文件的存储，比如图片这类；另一种是大文件的存储，比如搜索引擎的索引。  <br />大 家知道，对于Web服务器来说，不管是Apache、IIS还是其他容器，图片是最消耗资源的，于是我们有必要将图片与页面进行分离，这是基本上大型网站 都会采用的策略，他们都有独立的图片服务器，甚至很多台图片服务器。这样的架构可以降低提供页面访问请求的服务器系统压力，并且可以保证系统不会因为图片 问题而崩溃，在应用服务器和图片服务器上，可以进行不同的配置优化以保证更高的系统消耗和执行效率。<br /><br />(七)  数据库技术&#8212;集群和库表散列  <br />&nbsp;&nbsp;&nbsp;&nbsp; 对于大型网站而言，使用大型的数据库服务器是必须的事情。但是，在面对大量访问的时候，数据库的瓶颈仍然会显现出来，这时一台数据库将很快无法满足应用，于是我们需要借助于数据库集群或者库表散列技术。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;  在数据库集群方面，很多数据库厂商都有自己的解决方案，Oracle、Sybase、SQL   Server等都有很好的方案，常用的MySQL提供的Master/Slave也是类似的方案。因此，你使用了什么样的数据库，就参考相应的解决方案来 实施即可。  <br /><br />&nbsp;&nbsp;&nbsp;&nbsp;  上面提到的数据库集群由于在架构、成本、扩张性方面都会受到所采用数据库类型的限制，于是我们需要从应用程序的角度来考虑改善系统架构，其中，库表散列是 常用并且最有效的解决方案。我们在应用程序中安装业务和应用或者功能模块将数据库进行分离，不同的模块对应不同的数据库或者表，再按照一定的策略对某个页 面或者功能进行更小的数据库散列，比如用户表，按照用户ID进行表散列，这样就能够低成本的提升系统的性能并且有很好的扩展性。在这一方面一个现成的例子 就是搜狐。它的论坛就是采用了这样的架构，将论坛的用户、设置、帖子等信息进行数据库分离，然后对帖子、用户按照板块和ID进行散列数据库和表，最终可以 在配置文件中进行简单的配置便能让系统随时增加一台低成本的数据库进来补充系统性能。  <br /><br />(八) 缓存策略  <br />&nbsp;&nbsp;&nbsp;&nbsp;  这绝对不单指低级的缓存技术相关的编程，应从整个架构角度着眼，深入研究Web服务器、数据库服务器的各层级的缓冲策略，最后才是低级的缓冲技术的编程。 不同的Web服务器、数据库服务器及Web编程语言都有自己不同的缓冲策略。例如数据库存储方面，SQL  Serve  2005中的主动式缓存机制，Oracle数据的cache   group技术，Hibernate的缓存包括Session的缓存和SessionFactory的缓存；Web服务器方面，Apache提供了自己的 缓存模块，也可以使用外加的Squid模块进行缓存，这两种方式均可以有效的提高Apache的访问响应能力，IIS缓冲器技术；至于web开发语言，所 用缓存技术更存在很大不同，例如ASP.NET   2.0中提出了两种缓存应用程序数据和缓存服务页输出的策略，这两种缓存技术相互独立但不相互排斥，PHP有Pear的Cache模块，等等。 <br /><br />(九)  镜像  <br />&nbsp;&nbsp;&nbsp;&nbsp;   镜像是大型网站常采用的提高性能和数据安全性的方式，镜像的技术可以解决不同网络接入商和地域带来的用户访问速度差异。在镜像的细节技术方面，这里不阐述 太深，有很多专业的现成的解决架构和产品可选。也有廉价的通过软件实现的思路，比如Linux上的rsync等工具。  <br /><br />(十) 负载均衡 <br />&nbsp;&nbsp;&nbsp;&nbsp; 负载均衡将是大型网站解决高负荷访问和大量并发请求采用的终极解决办法。  <br />负载均衡技术发展了多年，有很多专业的服务提供商和产品可以选择，基于LAMP解决方案的Lighttped+Squid是相当不错的解决负载均衡和加速系统的有效方式。<br /><br />(十一)  硬件四层交换  <br />&nbsp;&nbsp;&nbsp;&nbsp;   第四层交换使用第三层和第四层信息包的报头信息，根据应用区间识别业务流，将整个区间段的业务流分配到合适的应用服务器进行处理。第四层交换功能就象是虚    IP，指向物理服务器。它传输的业务服从的协议多种多样，有HTTP、FTP、NFS、Telnet或其他协议。这些业务在物理服务器基础上，需要复杂的 载量平衡算法。在IP世界，业务类型由终端TCP或UDP端口地址来决定，在第四层交换中的应用区间则由源端和终端IP地址、TCP和UDP端口共同决 定。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; 在硬件四层交换产品领域，有一些知名的产品可以选择，比如Alteon、F5等，这些产品很昂贵，但是物有所值，能够提供非常优秀的性能和很灵活的管理能力。Yahoo中国当初接近2000台服务器使用了三四台Alteon就搞定了。<br />(十二)  软件四层交换  <br />&nbsp;&nbsp;&nbsp;&nbsp; 大家知道了硬件四层交换机的原理后，基于OSI模型来实现的软件四层交换也就应运而生，这样的解决方案实现的原理一致，不过性能稍差。但是满足一定量的压力还是游刃有余的。<br />&nbsp;&nbsp;&nbsp;&nbsp; 一个典型的使用负载均衡的策略就是，在软件或者硬件四层交换的基础上搭建squid集群，这种思路在很多大型网站包括搜索引擎上被采用，这样的架构低成本、高性能还有很强的扩张性，随时往架构里面增减节点都非常容易。  <br /><br />(十三) 软件投资问题  <br />&nbsp;&nbsp;&nbsp;&nbsp;   据报导，目前国内除了一些上市企业和特别大知名大公司以外，很少有企业在成本中考虑正版软件的购置费用。这种思维极有可能给中国互联网带来噩梦。如果一些 公司真正面临软件资金方面的困难，完全可以考虑使用开源世界的LAMP解决方案（Linux＋Apache＋MySQL＋Perl、PHP或者   Python Web编程语言）；否则，随着我国加入WTO范围的不断扩大，盗版打击必然越来越严。因此，&#8220;苟且偷生&#8221;必将自食其果。  <br /><br />&nbsp;&nbsp;&nbsp;&nbsp; 另外，随着网络带宽日渐提升，WEB  2.0技术必将影响到网络世界的几乎每一个角落。因此，如何积聚技术人员进行技术攻关并进一步加强安全防范也成为一个日益严峻的问题，宜尽早纳入到公司的议事日程。  <br />&nbsp;&nbsp;  <br /><strong>四、 总结</strong>  <br />&nbsp;&nbsp;&nbsp;&nbsp; 中国电子商务真正理性发展的一个标志，是大量的传统企业实实在在地开始用互联网来处理商务、做生意，而现在这样的浪潮已经开始。北京发行集团，联合SINA、6688.com等单位共同推出的网上虚拟书店&#8212;新新书店就是这样的一个标志。  <br />&nbsp;&nbsp;&nbsp;&nbsp;  随着网络带宽日渐提升，随着网络理念和WEB   2.0技术的断深入人心，各种B2B、B2C、C2C等电子商务模式很可能以立体交叉方式整合到各种大型商务网站中来。因此，作为公司的技术人员，作为临 危救驾的&#8220;白衣骑士&#8221;，如何应对海量存储、海量访问问题，海量信息检索的问题，日益严峻的安全问题，等等，已经刻不容缓。<img src="http://cnc.imgcache.qq.com/ac/b.gif"  alt="" /></div><img src ="http://www.blogjava.net/wealupa/aggbug/381717.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2012-06-28 14:37 <a href="http://www.blogjava.net/wealupa/archive/2012/06/28/381717.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大型网站架构技术方案集锦</title><link>http://www.blogjava.net/wealupa/archive/2012/06/28/381716.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 28 Jun 2012 06:35:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2012/06/28/381716.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/381716.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2012/06/28/381716.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/381716.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/381716.html</trackback:ping><description><![CDATA[<div><div id="cnblogs_post_body"><p>1. PlentyOfFish 网站架构学习</p> <p><a href="http://www.dbanotes.net/arch/plentyoffish_arch.html">http://www.dbanotes.net/arch/plentyoffish_arch.html</a></p> <p>采取 Windows 技术路线的 Web 2.0 站点并不多，除了 MySpace ，另外就是这个 PlentyOfFish。这个站点提供  &#8220;Online Dating&#8221; 服务。一个令人津津乐道的、惊人的数据是这个只有一个人(创建人Markus Frind）的站点价值 10  亿，估计要让很多人眼热，更何况 Markus Frind 每天只用两个小时打理网站&#8211;可操作性很强嘛。</p> <p>2. 从LiveJournal后台发展看 大型网站系统架构以及性能优化方法</p> <p><a href="http://www.example.net.cn/archives/2006/03/olivejournaloio.html">http://www.example.net.cn/archives/2006/03/olivejournaloio.html</a></p> <p>LiveJournal是99年始于校园中的项目，几个人出于爱好做了这样一个应用，以实现以下功能：</p> <p>* 博客，论坛</p> <p>* 社会性网络，找到朋友</p> <p>* 聚合，把朋友的文章聚合在一起</p> <p>LiveJournal采用了大量的开源软件，甚至它本身也是一个开源软件。</p> <p>在上线后，LiveJournal实现了非常快速的增长：</p> <p>* 2004年4月份：280万注册用户。</p> <p>* 2005年4月份：680万注册用户。</p> <p>* 2005年8月份：790万注册用户。</p> <p>* 达到了每秒钟上千次的页面请求及处理。</p> <p>* 使用了大量MySQL服务器。</p> <p>* 使用了大量通用组件。</p> <p>3. YouTube 的架构扩展</p> <p><a href="http://www.dbanotes.net/opensource/youtube_web_arch.html">http://www.dbanotes.net/opensource/youtube_web_arch.html</a></p> <p>在西雅图扩展性的技术研讨会上，YouTube 的 Cuong Do 做了关于 YouTube Scalability 的报告。视频内容在 Google Video 上有(地址)，可惜国内用户看不到。</p> <p>Kyle Cordes 对这个视频中的内容做了介绍。里面有不少技术性的内容。值得分享一下。(Kyle Cordes 的介绍是本文的主要来源)</p> <p>4. WikiPedia 技术架构学习分享</p> <p><a href="http://www.dbanotes.net/opensource/wikipedia_arch.html">http://www.dbanotes.net/opensource/wikipedia_arch.html</a></p> <p>维基百科(WikiPedia.org)位列世界十大网站，目前排名第八位。这是开放的力量。</p> <p>来点直接的数据：</p> <p>* 峰值每秒钟3万个 HTTP 请求</p> <p>* 每秒钟 3Gbit 流量, 近乎375MB</p> <p>* 350 台 PC 服务器</p> <p>5. Tailrank 网站架构</p> <p><a href="http://www.dbanotes.net/review/tailrank_arch.html">http://www.dbanotes.net/review/tailrank_arch.html</a></p> <p>每天数以千万计的 Blog 内容中，实时的热点是什么? Tailrank 这个 Web 2.0 Startup 致力于回答这个问题。</p> <p>专门爆料网站架构的 Todd Hoff 对 Kevin Burton 进行了采访。于是我们能了解一下 Tailrank  架构的一些信息。每小时索引 2400 万的 Blog 与 Feed，内容处理能力为 160-200Mbps，IO  写入大约在10-15MBps。每个月要处理 52T 之多的原始数据。Tailrank 所用的爬虫现在已经成为一个独立产品：spinn3r。</p> <p>6. LinkedIn 架构笔记</p> <p><a href="http://www.dbanotes.net/arch/linkedin.html">http://www.dbanotes.net/arch/linkedin.html</a></p> <p>LinkedIn 雇员有 180 个，在 Web 2.0 公司中算是比较多的，不过人家自从 2006 年就盈利了，这在 Web 2.0 站点中可算少的。用户超过 1600 万，现在每月新增 100 万，50％ 会员来自海外(中国用户不少，也包括我).</p> <p>7. Yahoo！社区架构</p> <p><a href="http://www.dbanotes.net/arch/yahoo_arch.html">http://www.dbanotes.net/arch/yahoo_arch.html</a></p> <p>旧金山举行的 QCon 会议带给我们很多新鲜的信息。虽然没机会参加，但是看看各个网站&#8221;晒架构&#8221;也是个比较过瘾的事情。请参观并收藏这个页面：Architectures you&#8217;ve always wondered about。</p> <p>8. Craigslist 的数据库架构</p> <p><a href="http://www.dbanotes.net/database/craigslist_database_arch.html">http://www.dbanotes.net/database/craigslist_database_arch.html</a></p> <p>Craigslist 绝对是互联网的一个传奇公司。根据以前的一则报道：</p> <p>每月超过 1000 万人使用该站服务，月浏览量超过 30 亿次，(Craigslist每月新增的帖子近 10 亿条??)网站的网页数量在以每年近百倍的速度增长。Craigslist 至今却只有 18 名员工(现在可能会多一些了)。</p> <p>9. Fotolog.com 的技术信息拾零</p> <p><a href="http://www.dbanotes.net/review/fotolog_arch.html">http://www.dbanotes.net/review/fotolog_arch.html</a></p> <p>尽管是世界上最大的图片服务网站, Fotolog.com 在国内的名气并不是很响亮, 每当提到图片服务, 很多人第一个会想起  Flickr. 但实际上 Fotolog 也的确是很猛的, Alexa 上的排名一直在 Flickr 前面, 目前注册用户超过 1100 万.  而前不久也卖了一个好价钱, 9000 万美金. 算下来的话, 1 个注册用户大约 9 美金. Yupoo  的刘平阳可以偷着算算自己的网站如果卖给老外是怎样一个价格了.</p> <p>10. Digg 网站架构</p> <p><a href="http://www.dbanotes.net/arch/digg_arch_cache_and_shard.html">http://www.dbanotes.net/arch/digg_arch_cache_and_shard.html</a></p> <p>Digg 工程师采用 LAMP (Linux, Apache, MySQL and PHP) 模式。这个 Alexa 排名在 100  左右的、自我估价 1.5 亿美金的站点目前有超过 100 台的 PC 服务器(足够少了)，可以粗略分成三个部分：数据库服务器，Web  服务器，搜索服务器。</p> <p>11. Amazon 的 Dynamo 架构</p> <p><a href="http://www.dbanotes.net/techmemo/amazon_dynamo.html">http://www.dbanotes.net/techmemo/amazon_dynamo.html</a></p> <p>我在 DBAnotes.net 上记录过不少比较大的网站架构分析(eg: eBay [1], eBay [2]) ，Amazon  一直找不到太多的资料。国庆期间读到了一篇关于 Amazon Dynamo 的论文，非常精彩。Amazon Dynamo  这个高可用、可扩展存储体系支撑了Amazon 不少核心服务.</p> <p>12. 财帮子（caibangzi.com）网站架构</p> <p><a href="http://www.dbanotes.net/arch/caibangzi_web_arch.html">http://www.dbanotes.net/arch/caibangzi_web_arch.html</a></p> <p>财帮子(caibangzi.com) 定位在&#8221;基金理财社区&#8221;。是国内访问量最大的基于 Ruby on rails 的 startup  项目。&#8220;理财&#8221;这个词据说是光大银行发明的，且不去管，不可否认的是，目前国内&#8221;理财&#8221;是个很有潜力的切入点。财帮子网站潜在用户群还是很大的。</p> <p>13. 了解一下 Technorati 的后台数据库架构</p> <p><a href="http://www.dbanotes.net/web/technorati_db_arch.html">http://www.dbanotes.net/web/technorati_db_arch.html</a></p> <p>目前处理着大约 10Tb 核心数据, 分布在大约 20 台机器上.通过复制, 多增加了 100Tb 数据, 分布在 200 台机器上.  每天增长的数据 1TB. 通过 SOA 的运用, 物理与逻辑的访问相隔离,似乎消除了数据库的瓶颈. 值得一提的是,  该扩展过程始终是利用普通的硬件与开源软件来完成的. 毕竟 , Web 2.0 站点都不是烧钱的主. 从数据量来看，这绝对是一个相对比较大的  Web 2.0 应用.</p> <p>14. 说说大型高并发高负载网站的系统架构</p> <p><a href="http://www.toplee.com/blog/?p=71">http://www.toplee.com/blog/?p=71</a></p> <p>我在CERNET做过拨号接入平台的搭建，而后在Yahoo&amp;3721从事过搜索引擎前端开发，又在MOP处理过大型社区猫扑大杂烩的架构 升级等工作，同时自己接触和开发过不少大中型网站的模块，因此在大型网站应对高负载和并发的解决方案上有一些积累和经验，可以和大家一起探讨一下。</p> <p>15. 大型高负载网站架构 的感想</p> <p><a href="http://atman.memoab.com/articles/194">http://atman.memoab.com/articles/194</a></p> <p>昨日认识了位健谈的IT人，原在verycd作系统管理的叶宁(这哥们现飘泊去见首都人民了).</p> <p>以前sweater给我介绍的他写的《大型高负载网站架构和应用初探》, 他总结了很多信息和数据，感谢叶宁的辛劳成果. 这里我也想就此PPT写些自己的感想. </p></div></div><img src ="http://www.blogjava.net/wealupa/aggbug/381716.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2012-06-28 14:35 <a href="http://www.blogjava.net/wealupa/archive/2012/06/28/381716.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大型网站架构设计</title><link>http://www.blogjava.net/wealupa/archive/2012/06/28/381707.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 28 Jun 2012 05:34:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2012/06/28/381707.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/381707.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2012/06/28/381707.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/381707.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/381707.html</trackback:ping><description><![CDATA[<div><div fc05="" fc11="" nbw-blog="" ztag=""  js-fs2"=""><p style="text-indent: 2em;">按需提供大型网站的架构设计，具体包括：</p> <div><img alt="大型网站架构设计 - adyhpq - adyhpq的个人主页" style="margin: 0px 10px 0px 0px;" src="http://img.ph.126.net/BR6fmxenKbFga2FeA-TPzw==/3057944146985054952.jpg" /></div> <p style="text-indent: 2em;">&nbsp;<br /></p> <p style="text-indent: 2em;">A. 提供后台数据库设计：根据业务需求的理解，针对指定的数据库（涵盖Oracle,MySql,SqlServer,DB2）提供网站项目的后台数据库设计。</p> <p style="text-indent: 2em;">后台数据库的设计是整个网站最重要的环节，其结构定义通常确定了后台业务数据的存储方式以及 绝大部分后台数据访问模型。对大型网站而言，由于其需要支撑的负荷很大，数据库设计将关系到数据储存量，数据访问效率，缓存效率，数据安全等多个方面，大 型网站的数据库设计原则与普通企业应用的设计原则有许多区别，需要经验丰富的架构师才能胜任。</p> <p style="text-indent: 2em;">提供后台持久层设计：持久层设计是在后台数据库设计的基础上，根据具体编程语言，根据网站访问特征具体设计的编程框架。设计目标将兼顾处理效率和代码的可维护性、可理解性（如面向对象）。</p> <p style="text-indent: 2em;">B. 提供缓存设计：根据业务需求，结合后台数据库设计和后台持久层设计，提供网站的缓存设计方案。具体包括前端缓存，共享数据缓存，分布式缓存。</p> <p style="text-indent: 2em;">所谓前端缓存，指把网页上短期内不太变化的内容、根据访问效率评估，通过片段形式以一定策略缓存起来，从而减少后台内容生成的时间，提升网站的响应效率和节省服务器的处理资源占用。</p> <p style="text-indent: 2em;">所谓共享数据缓存，指把后台中公共的数据根据访问频度和更新频度以一定策略在服务器缓存起来，避免每次使用都需要从数据库或磁盘提取。</p> <p style="text-indent: 2em;">所谓分布式缓存，指大型网站需要利用分布式的缓存来在多台集群机器之间共享某些处理结果内容。</p> <p style="text-indent: 2em;">C. 提供MVC（Model-View-Controller）框架设计：根据业务需求和网站特点提供合适的、高效的MVC处理框架。</p> <p style="text-indent: 2em;">MVC是Web应用前端的重要架构组成，网站交互的绝大部分内容将集中在这个部分，一套高效而易于扩展和使用的MVC框架是整个网站中重要组成。</p> <p style="text-indent: 2em;">D. 提供安全框架：根据业务需要和数据安全保护的需要，提供网站安全框架。</p> <p style="text-indent: 2em;">E. 提供SEO（Search Engine Optimize)方案：面向搜索引擎提供网站搜索优化方案。</p> <p style="text-indent: 2em;">F. 提供备份方案：根据业务需要提供针对不同平台的数据（代码、数据、用户资料）等备份方案。</p></div></div><img src ="http://www.blogjava.net/wealupa/aggbug/381707.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2012-06-28 13:34 <a href="http://www.blogjava.net/wealupa/archive/2012/06/28/381707.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大型网站架构不得不考虑的10个问题</title><link>http://www.blogjava.net/wealupa/archive/2012/06/28/381705.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 28 Jun 2012 05:26:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2012/06/28/381705.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/381705.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2012/06/28/381705.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/381705.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/381705.html</trackback:ping><description><![CDATA[<div><p>这里的大型网站架构只包括高互动性高交互性的数据型大型网站，基于大家众所周知的原因，我们就不谈新闻类和一些依靠HTML静态化就可以实现的架构 了，我们以高负载高数据交换高数据流动性的网站为例，比如海内，开心网等类似的web2.0系列架构。我们这里不讨论是PHP还是JSP或者.NET环 境，我们从架构的方面去看问题，实现语言方面并不是问题，语言的优势在于实现而不是好坏，不论你选择任何语言，架构都是必须要面对的。</p> <p>这里讨论一下大型网站需要注意和考虑的问题</p> <p><strong>1、海量数据的处理</strong> </p> <p>众所周知，对于一些相对小的站点来说，数据量并不是很大，select和update就可以解决我们面对的问题，本身负载量不是很大，最多再加几个 索引就可以搞定。对于大型网站，每天的数据量可能就上百万，如果一个设计不好的多对多关系，在前期是没有任何问题的，但是随着用户的增长，数据量会是几何 级的增长的。在这个时候我们对于一个表的select和update的时候(还不说多表联合查询)的成本的非常高的。</p> <p><strong>2、数据并发的处理</strong> </p> <p>在一些时候，2.0的CTO都有个尚方宝剑，就是缓存。对于缓存，在高并发高处理的时候也是个大问题。在整个应用程序下，缓存是全局共享的，然而在 我们进行修改的时候就，如果两个或者多个请求同时对缓存有更新的要求的情况下，应用程序会直接的死掉。这个时候，就需要一个好的数据并发处理策略以及缓存 策略。</p> <p>另外，就是数据库的死锁问题，也许平时我们感觉不到，死锁在高并发的情况下的出现的概率是非常高的，磁盘缓存就是一个大问题。</p> <p><strong>3、文件存贮的问题</strong> </p> <p>对于一些支持文件上传的2.0的站点，在庆幸硬盘容量越来越大的时候我们更多的应该考虑的是文件应该如何被存储并且被有效的索引。常见的方案是对文 件按照日期和类型进行存贮。但是当文件量是海量的数据的情况下，如果一块硬盘存贮了500个G的琐碎文件，那么维护的时候和使用的时候磁盘的Io就是一个 巨大的问题，哪怕你的带宽足够，但是你的磁盘也未必响应过来。如果这个时候还涉及上传，磁盘很容易就over了。</p> <p>也许用raid和专用存贮服务器能解决眼下的问题，但是还有个问题就是各地的访问问题，也许我们的服务器在北京，可能在云南或者新疆的访问速度如何解决?如果做分布式，那么我们的文件索引以及架构该如何规划。</p> <p>所以我们不得不承认，文件存贮是个很不容易的问题</p> <p><strong>4、数据关系的处理</strong> </p> <p>我们可以很容易的规划出一个符合第三范式的数据库，里面布满了多对多关系，还能用GUID来替换INDENTIFY COLUMN 但是，多对多关系充斥的2.0时代，第三范式是第一个应该被抛弃的。必须有效的把多表联合查询降到最低。</p> <p><strong>5、数据索引的问题</strong> </p> <p>众所周知，索引是提高数据库效率查询的最方面最廉价最容易实现的方案。但是，在高UPDATE的情况下，update和delete付出的成本会高的无法想想，笔者遇到过一个情况，在更新一个聚焦索引的时候需要10分钟来完成，那么对于站点来说，这些基本上是不可忍受的。</p> <p>索引和更新是一对天生的冤家，问题A，D，E这些是我们在做架构的时候不得不考虑的问题，并且也可能是花费时间最多的问题，</p> <p><strong>6、分布式处理</strong> </p> <p>对于2.0网站由于其高互动性，CDN实现的效果基本上为0，内容是实时更新的，我们常规的处理。为了保证各地的访问速度，我们就需要面对一个绝大的问题，就是如何有效的实现数据同步和更新，实现各地服务器的实时通讯有是一个不得不需要考虑的问题。</p> <p><strong>7、Ajax的利弊分析</strong> </p> <p>成也AJAX，败也AJAX，AJAX成为了主流趋势，突然发现基于XMLHTTP的post和get是如此的容易。客户端get或者post  到服务器数据，服务器接到数据请求之后返回来，这是一个很正常的AJAX请求。但是在AJAX处理的时候，如果我们使用一个抓包工具的话，对数据返回和处 理是一目了然。对于一些计算量大的AJAX请求的话，我们可以构造一个发包机，很容易就可以把一个webserver干掉。</p> <p><strong>8、数据安全性的分析</strong> </p> <p>对于HTTP协议来说，数据包都是明文传输的，也许我们可以说我们可以用加密啊，但是对于G问题来说的话，加密的过程就可能是明文了(比如我们知道 的QQ，可以很容易的判断他的加密，并有效的写一个跟他一样的加密和解密方法出来的)。当你站点流量不是很大的时候没有人会在乎你，但是当你流量上来之 后，那么所谓的外挂，所谓的群发就会接踵而来(从qq一开始的群发可见端倪)。也许我们可以很的意的说，我们可以采用更高级别的判断甚至HTTPS来实 现，注意，当你做这些处理的时候付出的将是海量的database，io以及CPU的成本。对于一些群发，基本上是不可能的。笔者已经可以实现对于百度空 间和qq空间的群发了。大家愿意试试，实际上并不是很难。</p> <p><strong>9、数据同步和集群的处理的问题</strong> </p> <p>当我们的一台databaseserver不堪重负的时候，这个时候我们就需要做基于数据库的负载和集群了。而这个时候可能是最让人困扰的的问题 了，数据基于网络传输根据数据库的设计的不同，数据延迟是很可怕的问题，也是不可避免的问题，这样的话，我们就需要通过另外的手段来保证在这延迟的几秒或 者更长的几分钟时间内，实现有效的交互。比如数据散列，分割，内容处理等等问题</p> <p><strong>10、数据共享的渠道以及OPENAPI趋势</strong> </p> <p>Openapi已经成为一个不可避免的趋势，从google，facebook，myspace到海内校内，都在考虑这个问题，它可以更有效的留住 用户并激发用户的更多的兴趣以及让更多的人帮助你做最有效的开发。这个时候一个有效的数据共享平台，数据开放平台就成为必不可少的途径了，而在开放的接口 的情况保证数据的安全性和性能，又是一个我们必须要认真思考的问题了。</p></div><img src ="http://www.blogjava.net/wealupa/aggbug/381705.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2012-06-28 13:26 <a href="http://www.blogjava.net/wealupa/archive/2012/06/28/381705.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>面向对象建模与数据库建模两种分析设计方法的比较</title><link>http://www.blogjava.net/wealupa/archive/2011/10/08/360201.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 08 Oct 2011 07:59:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2011/10/08/360201.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/360201.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2011/10/08/360201.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/360201.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/360201.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我们知道：一个软件从无到有需要经过如下几个阶段：分析、设计、编程、调试、部署和运行。<br /><br />　　 编程阶段我们通常使用Java/.NET这样面向对象语言工具，可以带来很多设计上的好处，但是也存在一个奇怪的现象：<br />很多程序员虽然在使用OO语言，但是却在code非OO的代码，最终导致系统性能降低或失败，这个现象在Java语言尤其<br />显得突出，难怪有些人就把问题归结于Java语言本身，睡不着觉怪床歪，又为了面子问题，说自己转向.NET，实际上是在 回避自己的问题和弱点。 
<p>　　那么，这些人的问题和弱点体现在什么地方呢？从上面软件生产过程来看，每个阶段都对前面有所依赖， 在编程阶段出问题，追根溯源，问题无疑出在分析和设计阶段，分析设计作为一个软件产生的龙头，有着映射实际需求世界 到计算机世界这样一个拷贝任务，<span class="STYLE1"><font color="#ff0000"><strong>如何做到拷贝不走样，是衡量映射方法好坏与否的主要判断标准。<br /><br /></strong></p>
<p><strong>　　</strong><span style="color: #000000">目前，将需求从客观现实世界映射到计算机软件世界主要有两种方式：传统数据库分析设计和面向对象建模( object-oriented class model)， 当前软件主要潮流无疑是面向对象占据主流，虽然它可能不是唯一最好最简单的解决方案，但是它是最普通，也是最恰当的。</span></p>
<p><span style="color: #000000">　　也就是说：在分析设计阶段，采取围绕什么为核心(是对象还是数据表为核心)的分析方法决定了后面编码阶段的编程特点，如果以数据表为核心进行分析设计， 也就是根据需求首先得到数据表名和字段，然后培训程序员学会SQL语句如何操作这些数据表，那么程序员为实现数据表的前后顺序操作， 必然会将代码写成过程式的风格。</span></p>
<p><span style="color: #000000">　　相反，如果分析设计首先根据需求得出对象模型(class Model)，那么程序员使用对象语言，再加上框架辅助，就很顺理成章走上OO编程风格。 至于OO代码相比传统过程编码的好处不是本文重点，可参考J道(jdon.com)相关讨论，扩展性和维护性好，开发越深入开发速度越快无疑是OO系统主要优点。</span><br /><br /><span style="color: #000000">　　本文重点主要是比较OO建模和数据表建模两者特点，这两者我们已经发现属于两个不同方向，也就是说，属于两个完全不同的领域，在J道其他文章里我们 其实已经把这两个领域上升为不同的学科，数据表建模属于数学范畴思维；而OO建模属于哲学思维。（用科学的思维方法指导软件的设计开发</span><a href="http://www.jdon.com/article/32520.html" target="_blank"><span style="color: #000000"> </span><span style="color: #0000ff">http://www.jdon.com/article/32520.html</span></a><span style="color: #000000">）</span></p>
<p><span style="color: #000000">　　下面我们看看面向对象的Class Model和Database Model是如何来表达客观世界的，也就是他们在表达需求上有些什么不同？<br /><br /></span></p>
<p><strong>面向对象模型(Class Model)</strong></p>
<p><span style="color: #000000">　　类代表一个对象类型，类在代码运行阶段将被创建为一个个对象实例， 每个类由两个部分组成：属性和行为，属性通常是一些数据状态值，也就是说：类将数据封装隐藏在自己内部了， 访问这些数据属性必须通过类公开的方法，或者接口。</span></p>
<p><span style="color: #000000">　　别小看这样一个小小包装，却决定了以后代码的维护性和扩展性， 打个比喻，日常生活中我们经常用各种盒子和袋子包装一些东西，这样做就是为了方便这些东西的携带或储藏，小到生活， 大到客观世界每个地方，都是包装分类的影子，无论大小公司都是一个封装，行政部分单位划分，仓库物流更需要包装， 我们从来不会因为嫌麻烦而不愿意引入一个似乎多余的盒子或袋子，那么有什么理由不在我们赖之生存的软件中（靠编软件吃饭） 引入封装概念呢？</span></p>
<p><span style="color: #000000">　　这里可以再深入想像一下：不愿意用盒子和袋子的携带东西大部分是一些急脾气的毛头小伙子，而偏偏这些小伙子又从事 软件工作，看来软件的非对象化是注定的，只是一个玩笑。</span></p>
<p><span style="color: #000000">　　类的方法行为也有多种类型，如公开 私有等，我们可以设计一些方法为公开接口，而将另外一些行为隐藏起来， 这样一个看似简单灵活的选择，却能够应付我们日后频繁的修改，软件不修改就不叫软件，软件修改了就崩溃是业务软件， 专业的软件是抗修改的，而且能够极其方便快速地被修改。这些都依靠接口公开和隐藏这样一个简单魔术，具体各种魔术表演 可以参考GoF设计模式(</span><a href="http://www.jdon.com/designpatterns/index.htm" target="_blank"><span style="color: #0000ff">http://www.jdon.com/designpatterns/index.htm</span></a><span style="color: #000000">)。</span></p>
<p><br /><strong>类的关系<br /></strong>　　我们不能只用一个一个单独的类来表达客观世界，因为客观世界存在千丝万缕的各种关系，在计算机领域无疑我们使用 类的关系来表达映射这些关系。这里我们只探讨类在建模方法上的关系，而不是UML中类的通用关系。 类在建模上主要有如下几个关系：</p>
<p><span style="color: #000000">　　类与类关系经常是这样：一个类包含一个类(构造性structural)，或者借助另外一个类达到某个功能（功能性）， 在对需求建模分析中，构造性的这种关系，也称为关联(Association)是我们关注重点，当然这种关系很显然表达的是一种 静态的结构，比如电脑包含屏幕，他们之间的关系就是一种关联。</span></p>
<p><span style="color: #000000">　　聚合(Aggregation)是一种表格式样的关联，表示一个类包含多项子类，这种关系是一种整体与部分的关系。 一个汽车有四个轮子，四个轮子是汽车的部分。</span></p>
<p><span style="color: #000000">　　组成(Composition)是一种更强烈的聚合关系，一个对象实际是由其子对象组成，子对象也唯一属于父对象。</span></p>
<p><span style="color: #000000">　　继承也是类建模中经常用到的关系，继承可以将一些数据属性抽象到父类中，避免重复，如入库单和出库单有 很多属性是差不多的，唯一不动的就是入库和出库的行为，那么我们可以抽象一个库单为父类，使用继承关系分别 表达入库单和出库单。</span></p>
<p><span style="color: #000000">　　在</span><a href="http://www.jdon.com/mda/ddd.html" target="_blank"><span style="color: #000000">Evans DDD</span></a><span style="color: #000000">中，提到通过访问聚合根来遍历导航关联对象，这样做的好处很明显保证了对象的从属性，非常符合 我们日常生活逻辑，比如，你要得到盒子里面的东西，必须首先得到盒子，然后经过一些准备如打开盒子，才能得到 盒子里面的东西，假设一下，如果没有这样封装导航关系，盒子和东西都是可以透明并行得到，你想得到东西就能够 直接获得，而不必经过打开盒子这一关，这样的访问方式首先怪诞，其次是不安全，如果盒子和东西放在数据表中，就会发生 这种情况。</span><br /><br /><strong>数据库模型(Database Model </strong><a href="http://www.google.cn/custom?complete=1&amp;hl=zh-CN&amp;newwindow=1&amp;client=pub-2190557680964036&amp;cof=FORID%3A1%3BGL%3A1%3BS%3Ahttp%3A%2F%2Fwww.jdon.com%2F%3BL%3Ahttp%3A%2F%2Fwww.jdon.com%2Fimages%2Fjdon.gif%3BLH%3A60%3BLW%3A120%3BLBGC%3AFFFFFF%3BLP%3A1%3BLC%3A%230000ff%3BVLC%3A%23663399%3BGFNT%3A%230000ff%3BGIMP%3A%230000ff%3B&amp;domains=jdon.com&amp;q=e-r%E6%A8%A1%E5%9E%8B&amp;btnG=Google+%E6%90%9C%E7%B4%A2&amp;sitesearch=&amp;meta=" target="_blank"><strong>传统E-R模型</strong></a><strong> )</strong></p>
<p><span style="color: #000000">　　好了，下面我们谈论关系数据表模型，以前我们朴素的分析设计都是根据需求直接建立数据表的方式来进行的，为什么称为朴素， 是因为我们好像只有数据结构 算法方面的知识，也认为只有这样做才叫做软件。 那么既然这条路能够走出来，我们看看这个领域是如何映射客观世界的。</span></p>
<p><span style="color: #000000">　　数据表由于技术提供庞大数据存储和可靠的数据访问，正在不断从技术领域走向社会领域，很多不懂计算机的人 也知道需要建立数据库来管理一些事务，但是不代表我们就必须围绕数据库的分析设计。</span></p>
<p><span style="color: #000000">　　数据表是类似前面的&#8220;类&#8221;，也是一种表达客观世界的基本单元，表有多列字段，表的字段是保存数据的，每个字段有数据类型。 注意，这里没有数据的封装和公开，表的字段是赤裸的，只要有数据库访问权限，任何人都可以访问，没有结构层次关系， 都是扁平并列的，如果你想在数据表字段之间试图看出客观世界中的层次和封装，那就错了，</span><span class="STYLE1"><font color="#ff0000"><span style="color: #000000">在拷贝不走样这个条件下， 这个映射方法至少把这个信息拷贝丢了。</span></font></span></p>
<p><span style="color: #000000">　　数据表也有一些行为，这些行为是基于实体的一些规则：</span></p>
<p><span style="color: #000000">　　约束(Constraints) 能够保证不同表字段之间的关系完整安全性，保证数据库的数据安全。</span></p>
<p><span style="color: #000000">　　触发器(Triggers)提供了实体在修改 新增和删除之前或之后的一些附加行为，</span></p>
<p><span style="color: #000000">　　存储过程(Database stored procedures)提供数据专有的脚本性语言，存储过程象一个数学公式虽然具有抽象简洁美学，但是这种简洁是闷葫芦美学，不是大众美学，只有公式存储过程发明者自己了解精通，别人无法插手，软件不是科学，不是比谁智商高，科研水平高，软件是人机工程，更讲究集体，讲究别人是否方便与你协同扩展软件。</span><br /><br /><span style="color: #000000">　　关系数据表的遍历访问是通过列字段遍历或表join等方式实现，SQL语句是这样标准语言， 只要会写SQL语句，就能访问那些失去层次，失去客观世界特征的苍白的数据，这样的系统能够多少真实 反映客观需求，是有问号的？SQL语句是否方便修改，是否经得起频繁修改而不出错，都是有疑问的地方，是否 SQL语句越复杂，修改越快，或者另外一个程序员能够很快修改不是自己写的SQL语句，这些都是问题所在。</span></p>
<p><br /><strong>数据表关系</strong></p>
<p><span style="color: #000000">　　数据表的关系主要是通过外健或专门关联表来表达的，这种关系虽然可以反映1:1或1:N这样关系，但是无法 表达关系的性质，是紧密组成关系式的关联，还是无关紧要的普通关系，正因为如此，使用数据表分析设计时， 我们会有蜘蛛网的关系表，这些关系由于在后期无法分辨性质，无法进行整理，增加了系统复杂性。</span></p>
<p><span style="color: #000000">　　更重要的是：分析就是对一个可能陌生领域进行探寻，如果使用数据表的分析设计方法，那么我们实际就是 在陌生领域中寻找数据表这样一个形式，那么有可能产生误判断，将一个实则是表达关系的东东误认为是一个实体表， 因为关系表必然带来关系，这样，就必然产生蜘蛛网式的数据表模型，将简单问题复杂化。</span><br /></p>
<p><br /><strong>总结<br /></strong>　　要谈方法，这个世界其实只存在两种：一是将复杂问题简单化的方法；一个是将简单问题复杂化的方法。 你使用什么样的方法，你就有什么样的世界观，就是什么样的人，但是对于软件这个领域，你只能选择前者。</p>
<p><span style="color: #000000">　　因为方法的不同，软件路线也就存在下面几个路线：完全面向对象类建模路线(J道网站和笔者一直致力于这种路线的推介)； 一种是对象和关系数据库混合型，还有一种就是过去的完全关系数据库类型软件（如Foxpro/VB/Delphi等）。需要参考完全面向对象类建模路线的源码可见(<a href="http://www.jdon.com/jdonframework/app.htm#simple。" target="_blank">http://www.jdon.com/jdonframework/app.htm#simple。</a>)</span></p>
<p></font></span></p><img src ="http://www.blogjava.net/wealupa/aggbug/360201.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2011-10-08 15:59 <a href="http://www.blogjava.net/wealupa/archive/2011/10/08/360201.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>接口和抽象类的区别 --相信你看完不会再混淆了</title><link>http://www.blogjava.net/wealupa/archive/2011/05/30/351348.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Mon, 30 May 2011 08:41:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2011/05/30/351348.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/351348.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2011/05/30/351348.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/351348.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/351348.html</trackback:ping><description><![CDATA[<span style="widows: 2; text-transform: none; text-indent: 0px; border-collapse: separate; font: medium Simsun; white-space: normal; orphans: 2; letter-spacing: normal; color: #000000; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple"><span style="line-height: 24px; font-family: 微软雅黑, sans-serif; color: #333333; font-size: 14px" class="Apple">&nbsp; 
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">我想，对于各位使用面向对象编程语言的程序员来说，&#8220;接口&#8221;这个名词一定不陌生，但是不知各位有没有这样的疑惑：接口有什么用途？它和抽象类有什么区别？能不能用抽象类代替接口呢？而且，作为程序员，一定经常听到&#8220;面向接口编程&#8221;这个短语，那么它是什么意思？有什么思想内涵？和面向对象编程是什么关系？本文将一一解答这些疑问。</p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">1.面向接口编程和面向对象编程是什么关系</strong></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">首先，面向接口编程和面向对象编程并不是平级的，它并不是比面向对象编程更先进的一种独立的编程思想，而是附属于面向对象思想体系，属于其一部分。或者说，它是面向对象编程体系中的思想精髓之一。</p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">2.接口的本质</strong></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">接口，在表面上是由几个没有主体代码的方法定义组成的集合体，有唯一的名称，可以被类或其他接口所实现（或者也可以说继承）。它在形式上可能是如下的样子：</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; margin: 0px; padding-left: 4px; width: 961px; padding-right: 5px; font-size: 13px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img style="padding-bottom: 0px; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" align="top" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif"  alt="" /><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #0000ff; padding-top: 0px">interface</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #000000; padding-top: 0px">&nbsp;InterfaceName<br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /><img style="padding-bottom: 0px; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" id="Codehighlighter1_24_121_Open_Image" align="top" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif"  alt="" /></span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" id="Codehighlighter1_24_121_Open_Text"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #000000; padding-top: 0px">{<br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /><img style="padding-bottom: 0px; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" align="top" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #0000ff; padding-top: 0px">void</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #000000; padding-top: 0px">&nbsp;Method1();<br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /><img style="padding-bottom: 0px; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" align="top" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #0000ff; padding-top: 0px">void</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #000000; padding-top: 0px">&nbsp;Method2(</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #0000ff; padding-top: 0px">int</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #000000; padding-top: 0px">&nbsp;para1);<br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /><img style="padding-bottom: 0px; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" align="top" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #0000ff; padding-top: 0px">void</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #000000; padding-top: 0px">&nbsp;Method3(</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #0000ff; padding-top: 0px">string</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #000000; padding-top: 0px">&nbsp;para2,</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #0000ff; padding-top: 0px">string</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #000000; padding-top: 0px">&nbsp;para3);<br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" /><img style="padding-bottom: 0px; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" align="top" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />}</span></span></div>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">&nbsp;</p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">那么，接口的本质是什么呢？或者说接口存在的意义是什么。我认为可以从以下两个视角考虑：</p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: red; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">1）接口是一组规则的集合，它规定了实现本接口的类或接口必须拥有的一组规则。体现了自然界&#8220;如果你是&#8230;&#8230;则必须能&#8230;&#8230;&#8221;的理念。</strong></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: red; padding-top: 0px">&nbsp;</span>例如，在自然界中，人都能吃饭，即&#8220;如果你是人，则必须能吃饭&#8221;。那么模拟到计算机程序中，就应该有一个IPerson（习惯上，接口名由&#8220;I&#8221;开头）接口，并有一个方法叫Eat()，然后我们规定，每一个表示&#8220;人&#8221;的类，必须实现IPerson接口，这就模拟了自然界&#8220;如果你是人，则必须能吃饭&#8221;这条规则。</p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">从这里，我想各位也能看到些许面向对象思想的东西。面向对象思想的核心之一，就是模拟真实世界，把真实世界中的事物抽象成类，整个程序靠各个类的实例互相通信、互相协作完成系统功能，这非常符合真实世界的运行状况，也是面向对象思想的精髓。</p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: red; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">2）接口是在一定粒度视图上同类事物的抽象表示。注意这里我强调了在一定粒度视图上，因为&#8220;同类事物&#8221;这个概念是相对的，它因为粒度视图不同而不同。</strong></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: red; padding-top: 0px">&nbsp;</span>例如，在我的眼里，我是一个人，和一头猪有本质区别，我可以接受我和我同学是同类这个说法，但绝不能接受我和一头猪是同类。但是，如果在一个动物学家眼里，我和猪应该是同类，因为我们都是动物，他可以认为&#8220;人&#8221;和&#8220;猪&#8221;都实现了IAnimal这个接口，而他在研究动物行为时，不会把我和猪分开对待，而会从&#8220;动物&#8221;这个较大的粒度上研究，但他会认为我和一棵树有本质区别。</p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px">现在换了一个遗传学家，情况又不同了，因为生物都能遗传，所以在他眼里，我不仅和猪没区别，和一只蚊子、一个细菌、一颗树、一个蘑菇乃至一个SARS病毒都没什么区别，因为他会认为我们都实现了ID<span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">escendable这个接口（注：descend&nbsp;vi. 遗传），即我们都是可遗传的东西，他不会分别研究我们，而会将所有生物作为同类进行研究，在他眼里没有人和病毒之分，只有可遗传的物质和不可遗传的物质。但至少，我和一块石头还是有区别的。</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">可不幸的事情发生了，某日，地球上出现了一位伟大的人，他叫列宁，他在熟读马克思、恩格斯的辩证唯物主义思想巨著后，颇有心得，于是他下了一个著名的定义：所谓物质，就是能被意识所反映的客观实在。至此，我和一块石头、一丝空气、一条成语和传输手机信号的电磁场已经没什么区别了，因为在列宁的眼里，我们都是可以被意识所反映的客观实在。如果列宁是一名程序员，他会这么说：所谓物质，就是所有同时实现了&#8220;IReflectabe&#8221;和&#8220;IE<span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">sse</span>&#8221;两个接口的类所生成的实例。（注：reflect v. 反映&nbsp; esse n. 客观实在）</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">也许你会觉得我上面的例子像在瞎掰，但是，这正是接口得以存在的意义。面向对象思想和核心之一叫做多态性，什么叫多态性？说白了就是在某个粒度视图层面上对同类事物不加区别的对待而统一处理。而之所以敢这样做，就是因为有接口的存在。像那个遗传学家，他明白所有生物都实现了ID<span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">escendable</span>接口，那只要是生物，一定有Descend（）这个方法，于是他就可以统一研究，而不至于分别研究每一种生物而最终累死。</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">可能这里还不能给你一个关于接口本质和作用的直观印象。那么在后文的例子和对几个设计模式的解析中，你将会更直观体验到接口的内涵。</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">3.面向接口编程综述</strong></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">通过上文，我想大家对接口和接口的思想内涵有了一个了解，那么什么是面向接口编程呢？我个人的定义是：<strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: red; padding-top: 0px">在系统分析和架构中，分清层次和依赖关系，每个层次不是直接向其上层提供服务（即不是直接实例化在上层中），而是通过定义一组接口，仅向上层暴露其接口功能，上层对于下层仅仅是接口依赖，而不依赖具体类</span>。</strong></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">这样做的好处是显而易见的，首先对系统灵活性大有好处。当下层需要改变时，只要接口及接口功能不变，则上层不用做任何修改。甚至可以在不改动上层代码时将下层整个替换掉，就像我们将一个WD的60G硬盘换成一个希捷的160G的硬盘，计算机其他地方不用做任何改动，而是把原硬盘拔下来、新硬盘插上就行了，因为计算机其他部分不依赖具体硬盘，而只依赖一个IDE接口，只要硬盘实现了这个接口，就可以替换上去。从这里看，程序中的接口和现实中的接口极为相似，所以我一直认为，接口（interface）这个词用的真是神似！</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">使用接口的另一个好处就是不同部件或层次的开发人员可以并行开工，就像造硬盘的不用等造CPU的，也不用等造显示器的，只要接口一致，设计合理，完全可以并行进行开发，从而提高效率。</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">本篇文章先到这里。最后我想再啰嗦一句：面向对象的精髓是模拟现实，这也可以说是我这篇文章的灵魂。所以，多从现实中思考面向对象的东西，对提高系统分析设计能力大有脾益。</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">下篇文章，我将用一个实例来展示接口编程的基本方法。</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">而第三篇，我将解析经典设计模式中的一些面向接口编程思想，并解析一下.NET分层架构中的面向接口思想。</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #0000ff; padding-top: 0px">对本文的补充：</strong></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #808080; padding-top: 0px">仔细看了各位的回复，非常高兴能和大家一起讨论技术问题。感谢给出肯定的朋友，也要感谢提出意见和质疑的朋友，这促使我更深入思考一些东西，希望能借此进步。在这里我想补充一些东西，以讨论一些回复中比较集中的问题。</span></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #808080; padding-top: 0px"></span><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">1.关于&#8220;面向接口编程&#8221;中的&#8220;接口&#8221;与具体面向对象语言中&#8220;接口&#8221;两个词</strong></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">看到有朋友提出&#8220;面向接口编程&#8221;中的&#8220;接口&#8221;二字应该比单纯编程语言中的interface范围更大。我经过思考，觉得很有道理。这里我写的确实不太合理。我想，面向对象语言中的&#8220;接口&#8221;是指具体的一种代码结构，例如C#中用interface关键字定义的接口。而&#8220;面向接口编程&#8221;中的&#8220;接口&#8221;可以说是一种从软件架构的角度、从一个更抽象的层面上指那种用于隐藏具体底层类和实现多态性的结构部件。从这个意义上说，如果定义一个抽象类，并且目的是为了实现多态，那么我认为把这个抽象类也称为&#8220;接口&#8221;是合理的。但是用抽象类实现多态合理不合理？在下面第二条讨论。</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">概括来说，我觉得两个&#8220;接口&#8221;的概念既相互区别又相互联系。<strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #ff0000; padding-top: 0px">&#8220;</span><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #ff0000; padding-top: 0px">面向接口编程&#8221;中的接口是一种思想层面的用于实现多态性、提高软件灵活性和可维护性的架构部件，而具体语言中的&#8220;接口&#8221;是将这种思想中的部件具体实施到代码里的手<span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #ff0000; padding-top: 0px">段。</span></span></strong></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #ff0000; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #ff0000; padding-top: 0px"></span></span><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">2.关于抽象类与接口</strong></span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">看到回复中这是讨论的比较激烈的一个问题。很抱歉我考虑不周没有在文章中讨论这个问题。我个人对这个问题的理解如下：</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">如果单从具体代码来看，对这两个概念很容易模糊，甚至觉得接口就是多余的，因为单从具体功能来看，除多重继承外（C#，Java中），抽象类似乎完全能取代接口。但是，难道接口的存在是为了实现多重继承？当然不是。<span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; color: #ff0000; padding-top: 0px"><strong style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">我认为，抽象类和接口的区别在于使用动机。使用抽象类是为了代码的复用，而使用接口的动机是为了实现多态性。</strong></span>所以，如果你在为某个地方该使用接口还是抽象类而犹豫不决时，那么可以想想你的动机是什么。</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">看到有朋友对IPerson这个接口的质疑，我个人的理解是，IPerson这个接口该不该定义，关键看具体应用中是怎么个情况。如果我们的项目中有Women和Man，都继承Person，而且Women和Man绝大多数方法都相同，只有一个方法DoSomethingInWC（）不同（例子比较粗俗，各位见谅），那么当然定义一个AbstractPerson抽象类比较合理，因为它可以把其他所有方法都包含进去，子类只定义DoSomethingInWC（），大大减少了重复代码量。</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">但是，如果我们程序中的Women和Man两个类基本没有共同代码，而且有一个PersonHandle类需要实例化他们，并且不希望知道他们是男是女，而只需把他们当作人看待，并实现多态，那么定义成接口就有必要了。</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">总而言之，接口与抽象类的区别主要在于使用的动机，而不在于其本身。而一个东西该定义成抽象类还是接口，要根据具体环境的上下文决定。</span></p>
<p style="padding-bottom: 0px; text-indent: 0px; margin: 0px auto 10px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" class="word">再者，我认为接口和抽象类的另一个区别在于，抽象类和它的子类之间应该是一般和特殊的关系，而接口仅仅是它的子类应该实现的一组规则。（当然，有时也可能存在一般与特殊的关系，但我们使用接口的目的不在这里）如，交通工具定义成抽象类，汽车、飞机、轮船定义成子类，是可以接受的，因为汽车、飞机、轮船都是一种特殊的交通工具。再譬如Icomparable接口，它只是说，实现这个接口的类必须要可以进行比较，这是一条规则。如果Car这个类实现了Icomparable，只是说，我们的Car中有一个方法可以对两个Car的实例进行比较，可能是比哪辆车更贵，也可能比哪辆车更大，这都无所谓，但我们不能说&#8220;汽车是一种特殊的可以比较&#8221;，这在文法上都不通。</span></p></span></span><img src ="http://www.blogjava.net/wealupa/aggbug/351348.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2011-05-30 16:41 <a href="http://www.blogjava.net/wealupa/archive/2011/05/30/351348.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TFS 2010 新建 Work Item</title><link>http://www.blogjava.net/wealupa/archive/2010/10/11/334371.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Mon, 11 Oct 2010 08:09:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2010/10/11/334371.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/334371.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2010/10/11/334371.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/334371.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/334371.html</trackback:ping><description><![CDATA[如果想要自定义的话，可以创建自己的自定义流程模板，从而从头开始或通过修改 Microsoft 提供的模板来创建自己的自定义工作项。定义自己的自定义工作项时，还可以定义自定义字段定义。<br />
你可以去下载一个Visual Studio Team System 2008 Team Foundation Server Power Tools，具体下载地址请参考： <a href="http://msdn.microsoft.com/zh-cn/teamsystem/bb980963.aspx">http://msdn.microsoft.com/zh-cn/teamsystem/bb980963.aspx</a>。<br />
可以用其中的Process Template Editor来进行编辑。<br />
<a href="http://msdn.microsoft.com/en-us/teamsystem/bb980963.aspx#pte">http://msdn.microsoft.com/en-us/teamsystem/bb980963.aspx#pte</a>。<br />
<br />
希望对你有所帮助。
<img src ="http://www.blogjava.net/wealupa/aggbug/334371.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2010-10-11 16:09 <a href="http://www.blogjava.net/wealupa/archive/2010/10/11/334371.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate继承实现</title><link>http://www.blogjava.net/wealupa/archive/2010/10/08/334015.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Fri, 08 Oct 2010 15:25:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2010/10/08/334015.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/334015.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2010/10/08/334015.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/334015.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/334015.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: hiberate继承分为三种方式:一个表对应所有继承的类,具体类对应一个表,一个类对应一个表(父类及子类)一个类对应一个表(父类及子类)数据库脚本CREATE&nbsp;TABLE&nbsp;`t_item1`&nbsp;(&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs...&nbsp;&nbsp;<a href='http://www.blogjava.net/wealupa/archive/2010/10/08/334015.html'>阅读全文</a><img src ="http://www.blogjava.net/wealupa/aggbug/334015.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2010-10-08 23:25 <a href="http://www.blogjava.net/wealupa/archive/2010/10/08/334015.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ibatis 对象关系实现</title><link>http://www.blogjava.net/wealupa/archive/2010/10/08/333998.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Fri, 08 Oct 2010 12:15:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2010/10/08/333998.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/333998.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2010/10/08/333998.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/333998.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/333998.html</trackback:ping><description><![CDATA[hibernate 的强大在于完全的对象化，对于对象之间的关系解决的比较好，如1对1，1对多，多对1，以及多对多。当然也包括继承关系。<br />
&nbsp;&nbsp;&nbsp; 而ibatis这方面就比较逊色了，不过对于也支持简单的关连查询，如1对1，和1对多。对于一般的情况来说，这两种已经足够了，当然不能层叠更新是一个缺陷，看了半天文档，也没有找到对象之间的层叠更新，估计是不支持。<br />
&nbsp;&nbsp;&nbsp; 以前的版本ibatis处理关连是通过执行两次sql来实现的，如下的实例：<br />
&nbsp;&nbsp;&nbsp; 一对多关联：<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #0000ff">&lt;</span><span style="color: #800000">sqlMap&nbsp;</span><span style="color: #ff0000">namespace</span><span style="color: #0000ff">="User"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">typeAlias&nbsp;</span><span style="color: #ff0000">alias</span><span style="color: #0000ff">="user"</span><span style="color: #ff0000">&nbsp;type</span><span style="color: #0000ff">="com.ibatis.sample.User"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">typeAlias&nbsp;</span><span style="color: #ff0000">alias</span><span style="color: #0000ff">="address"</span><span style="color: #ff0000">&nbsp;type</span><span style="color: #0000ff">="com.ibatis.sample.Address"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">resultMap&nbsp;</span><span style="color: #ff0000">id</span><span style="color: #0000ff">="get-user-result"</span><span style="color: #ff0000">&nbsp;class</span><span style="color: #0000ff">="user"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">result&nbsp;</span><span style="color: #ff0000">property</span><span style="color: #0000ff">="id"</span><span style="color: #ff0000">&nbsp;column</span><span style="color: #0000ff">="id"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">result&nbsp;</span><span style="color: #ff0000">property</span><span style="color: #0000ff">="name"</span><span style="color: #ff0000">&nbsp;column</span><span style="color: #0000ff">="name"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">result&nbsp;</span><span style="color: #ff0000">property</span><span style="color: #0000ff">="sex"</span><span style="color: #ff0000">&nbsp;column</span><span style="color: #0000ff">="sex"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">result&nbsp;</span><span style="color: #ff0000">property</span><span style="color: #0000ff">="addresses"</span><span style="color: #ff0000">&nbsp;column</span><span style="color: #0000ff">="id"</span><span style="color: #ff0000">&nbsp;select</span><span style="color: #0000ff">="User.getAddressByUserId"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">resultMap</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">select&nbsp;</span><span style="color: #ff0000">id</span><span style="color: #0000ff">="getUsers"</span><span style="color: #ff0000">&nbsp;parameterClass</span><span style="color: #0000ff">="java.lang.String"</span><span style="color: #ff0000">&nbsp;resultMap</span><span style="color: #0000ff">="get-user-result"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;![CDATA[</span><span style="color: #808080">&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />select&nbsp;id,name,sex&nbsp;from&nbsp;t_user&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />where&nbsp;id&nbsp;=&nbsp;#id#&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">]]&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">select</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">select&nbsp;</span><span style="color: #ff0000">id</span><span style="color: #0000ff">="getAddressByUserId"</span><span style="color: #ff0000">&nbsp;parameterClass</span><span style="color: #0000ff">="int"</span><span style="color: #ff0000">&nbsp;resultClass</span><span style="color: #0000ff">="address"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;![CDATA[</span><span style="color: #808080">&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />select&nbsp;address,zipcode&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />from&nbsp;t_address&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />where&nbsp;user_id&nbsp;=&nbsp;#userid#&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">]]&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">select</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">sqlMap</span><span style="color: #0000ff">&gt;</span></div>
这里通过在resultMap 中定义嵌套查询getAddressByUserId，我们实现了关联数据的读取。<br />
需要注意的是，这里有一个潜在的性能问题，也就是所谓&#8220;n+1&#8221;Select问题。<br />
一对一关联：<br />
对于这种情况，我们可以采用一次Select两张表的方式，避免这样的性能开销（假设上面示例中，每个User 只有一个对应的Address记录）：<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #0000ff">&lt;</span><span style="color: #800000">resultMap&nbsp;</span><span style="color: #ff0000">id</span><span style="color: #0000ff">="get-user-result"</span><span style="color: #ff0000">&nbsp;class</span><span style="color: #0000ff">="user"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">result&nbsp;</span><span style="color: #ff0000">property</span><span style="color: #0000ff">="id"</span><span style="color: #ff0000">&nbsp;column</span><span style="color: #0000ff">="id"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">result&nbsp;</span><span style="color: #ff0000">property</span><span style="color: #0000ff">="name"</span><span style="color: #ff0000">&nbsp;column</span><span style="color: #0000ff">="name"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">result&nbsp;</span><span style="color: #ff0000">property</span><span style="color: #0000ff">="sex"</span><span style="color: #ff0000">&nbsp;column</span><span style="color: #0000ff">="sex"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">result&nbsp;</span><span style="color: #ff0000">property</span><span style="color: #0000ff">="address"</span><span style="color: #ff0000">&nbsp;column</span><span style="color: #0000ff">="t_address.address"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">result&nbsp;</span><span style="color: #ff0000">property</span><span style="color: #0000ff">="zipCode"</span><span style="color: #ff0000">&nbsp;column</span><span style="color: #0000ff">="t_address.zipcode"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">resultMap</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">select&nbsp;</span><span style="color: #ff0000">id</span><span style="color: #0000ff">="getUsers"</span><span style="color: #ff0000">&nbsp;parameterClass</span><span style="color: #0000ff">="java.lang.String"</span><span style="color: #ff0000">&nbsp;resultMap</span><span style="color: #0000ff">="get-user-result"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;![CDATA[</span><span style="color: #808080">&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />select&nbsp;*&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />from&nbsp;t_user,t_address&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />where&nbsp;t_user.id=t_address.user_id&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">]]&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">select</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;</span></div>
在现在的版本中，对于n+1问题，ibatis已经很好的解决了。如下的配置：<br />
一对一<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #0000ff">&lt;</span><span style="color: #800000">resultMap&nbsp;</span><span style="color: #ff0000">id</span><span style="color: #0000ff">=&#8221;get-product-result&#8221;&nbsp;</span><span style="color: #ff0000">class</span><span style="color: #0000ff">=&#8221;com.ibatis.example.Product&#8221;&gt;&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">&lt;result&nbsp;property</span><span style="color: #0000ff">=&#8221;id&#8221;&nbsp;</span><span style="color: #ff0000">column</span><span style="color: #0000ff">=&#8221;PRD_ID&#8221;/&gt;&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">&lt;result&nbsp;property</span><span style="color: #0000ff">=&#8221;description&#8221;&nbsp;</span><span style="color: #ff0000">column</span><span style="color: #0000ff">=&#8221;PRD_DESCRIPTION&#8221;/&gt;&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">&lt;result&nbsp;property</span><span style="color: #0000ff">=&#8221;category&#8221;&nbsp;</span><span style="color: #ff0000">resultMap</span><span style="color: #0000ff">=&#8220;get-category-result&#8221;&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">resultMap</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">resultMap&nbsp;</span><span style="color: #ff0000">id</span><span style="color: #0000ff">=&#8221;get-category-result&#8221;&nbsp;</span><span style="color: #ff0000">class</span><span style="color: #0000ff">=&#8221;com.ibatis.example.Category&#8221;&gt;&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">&lt;result&nbsp;property</span><span style="color: #0000ff">=&#8221;id&#8221;&nbsp;</span><span style="color: #ff0000">column</span><span style="color: #0000ff">=&#8221;CAT_ID&#8221;&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">result&nbsp;</span><span style="color: #ff0000">property</span><span style="color: #0000ff">=&#8221;description&#8221;&nbsp;</span><span style="color: #ff0000">column</span><span style="color: #0000ff">=&#8221;CAT_DESCRIPTION&#8221;&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">resultMap</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">select&nbsp;</span><span style="color: #ff0000">id</span><span style="color: #0000ff">=&#8221;getProduct&#8221;&nbsp;</span><span style="color: #ff0000">parameterClass</span><span style="color: #0000ff">=&#8221;int&#8221;&nbsp;</span><span style="color: #ff0000">resultMap</span><span style="color: #0000ff">=&#8221;get-product-result&#8221;&gt;&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">select&nbsp;*&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />from&nbsp;PRODUCT,&nbsp;CATEGORY&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />where&nbsp;PRD_CAT_ID</span><span style="color: #0000ff">=CAT_ID&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">and&nbsp;PRD_ID&nbsp;</span><span style="color: #0000ff">=&nbsp;#value#&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">&lt;/select</span><span style="color: #0000ff">&gt;</span></div>
可以使用内在的resultMap来解决此问题。<br />
同样一对多如下：<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #0000ff">&lt;</span><span style="color: #800000">sqlMap&nbsp;</span><span style="color: #ff0000">namespace</span><span style="color: #0000ff">="ProductCategory"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">resultMap&nbsp;</span><span style="color: #ff0000">id</span><span style="color: #0000ff">=&#8221;categoryResult&#8221;&nbsp;</span><span style="color: #ff0000">class</span><span style="color: #0000ff">=&#8221;com.ibatis.example.Category&#8221;&nbsp;</span><span style="color: #ff0000">groupBy</span><span style="color: #0000ff">=&#8221;id&#8221;&gt;&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">&lt;result&nbsp;property</span><span style="color: #0000ff">=&#8221;id&#8221;&nbsp;</span><span style="color: #ff0000">column</span><span style="color: #0000ff">=&#8221;CAT_ID&#8221;/&gt;&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">&lt;result&nbsp;property</span><span style="color: #0000ff">=&#8221;description&#8221;&nbsp;</span><span style="color: #ff0000">column</span><span style="color: #0000ff">=&#8221;CAT_DESCRIPTION&#8221;/&gt;&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">&lt;result&nbsp;property</span><span style="color: #0000ff">=&#8221;productList&#8221;&nbsp;</span><span style="color: #ff0000">resultMap</span><span style="color: #0000ff">=&#8221;ProductCategory.productResult&#8221;/&gt;&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">&lt;/resultMap</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">resultMap&nbsp;</span><span style="color: #ff0000">id</span><span style="color: #0000ff">=&#8221;productResult&#8221;&nbsp;</span><span style="color: #ff0000">class</span><span style="color: #0000ff">=&#8221;com.ibatis.example.Product&#8221;&gt;&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">&lt;result&nbsp;property</span><span style="color: #0000ff">=&#8221;id&#8221;&nbsp;</span><span style="color: #ff0000">column</span><span style="color: #0000ff">=&#8221;PRD_ID&#8221;/&gt;&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">&lt;result&nbsp;property</span><span style="color: #0000ff">=&#8221;description&#8221;&nbsp;</span><span style="color: #ff0000">column</span><span style="color: #0000ff">=&#8221;PRD_DESCRIPTION&#8221;/&gt;&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">&lt;/resultMap</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">select&nbsp;</span><span style="color: #ff0000">id</span><span style="color: #0000ff">=&#8221;getCategory&#8221;&nbsp;</span><span style="color: #ff0000">parameterClass</span><span style="color: #0000ff">=&#8221;int&#8221;&nbsp;</span><span style="color: #ff0000">resultMap</span><span style="color: #0000ff">=&#8221;categoryResult&#8221;&gt;&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">select&nbsp;C.CAT_ID,&nbsp;C.CAT_DESCRIPTION,&nbsp;P.PRD_ID,&nbsp;P.PRD_DESCRIPTION&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />from&nbsp;CATEGORY&nbsp;C&nbsp;left&nbsp;outer&nbsp;join&nbsp;PRODUCT&nbsp;P&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />on&nbsp;C.CAT_ID&nbsp;</span><span style="color: #0000ff">=&nbsp;P.PRD_CAT_ID&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">where&nbsp;CAT_ID&nbsp;</span><span style="color: #0000ff">=&nbsp;#value#&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #ff0000">&lt;/select</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">sqlMap</span><span style="color: #0000ff">&gt;</span></div>
注意，需要使用增加groupBy属性来分类<br />
如果想实现，延迟加载的情况：<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #0000ff">&lt;</span><span style="color: #800000">sqlMapConfig</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">settings&nbsp;</span><span style="color: #ff0000">lazyLoadingEnabled</span><span style="color: #0000ff">="true"</span><span style="color: #ff0000">&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"  alt="" />&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span></div>
在日志中显示sql语句 <br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #000000">log4j.logger.com.ibatis=DEBUG&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG&nbsp;</span></div>
<img src ="http://www.blogjava.net/wealupa/aggbug/333998.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2010-10-08 20:15 <a href="http://www.blogjava.net/wealupa/archive/2010/10/08/333998.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ibatis中的resultMap如何继承</title><link>http://www.blogjava.net/wealupa/archive/2010/10/08/333997.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Fri, 08 Oct 2010 12:05:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2010/10/08/333997.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/333997.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2010/10/08/333997.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/333997.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/333997.html</trackback:ping><description><![CDATA[<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #000000">1.</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">typeAlias&nbsp;</span><span style="color: #ff0000">alias</span><span style="color: #0000ff">="Domain"</span><span style="color: #ff0000">&nbsp;type</span><span style="color: #0000ff">="com.xxx.Domain"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />2.</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">resultMap&nbsp;</span><span style="color: #ff0000">id&nbsp;</span><span style="color: #0000ff">=&nbsp;"domain"</span><span style="color: #ff0000">&nbsp;type&nbsp;</span><span style="color: #0000ff">=&nbsp;"Domain"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />3.&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">result&nbsp;</span><span style="color: #ff0000">property</span><span style="color: #0000ff">="id"</span><span style="color: #ff0000">&nbsp;column</span><span style="color: #0000ff">="id"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />4.</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">resultMap</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />5.</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">resultMap&nbsp;</span><span style="color: #ff0000">id&nbsp;</span><span style="color: #0000ff">=&nbsp;"extraDomain"</span><span style="color: #ff0000">&nbsp;extends</span><span style="color: #0000ff">="domain"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />6.&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">result&nbsp;</span><span style="color: #ff0000">property</span><span style="color: #0000ff">="name"</span><span style="color: #ff0000">&nbsp;column</span><span style="color: #0000ff">="name"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000">&nbsp;&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />7.</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">resultMap</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;&nbsp;</span></div>
<img src ="http://www.blogjava.net/wealupa/aggbug/333997.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2010-10-08 20:05 <a href="http://www.blogjava.net/wealupa/archive/2010/10/08/333997.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>简单的MVC就够了吗？浅谈service Layer的引入</title><link>http://www.blogjava.net/wealupa/archive/2010/10/07/333904.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 07 Oct 2010 08:29:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2010/10/07/333904.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/333904.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2010/10/07/333904.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/333904.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/333904.html</trackback:ping><description><![CDATA[<p>MVC是web开发中常见的程序结构。</p>
<p>简单的mvc结构如下：</p>
<p>view层：显示层。 </p>
<p>control层：业务层，集合了各种action。 </p>
<p>model层：模型层，一般和数据打交道。简单的sample：一个表对应一个model类。</p>
<p>其中control层调用model层的方法，实现对数据的访问。 </p>
<p>&nbsp;</p>
<p>采用这样的结构在一定程度上，可以做到代码清晰，较容易扩展，代码的管理复杂度较低。</p>
<p>但是如果是业务很多，逻辑又很复杂的网站，如果再加上开发人员的水平参差不齐，那必然会导致下面的情况：</p>
<p>1<span style="white-space: pre" class="Apple-tab-span"> </span>action中的代码越来越长，逻辑越来越复杂，不同action之间看起来有很多可以重用的代码， 但是真要进行重构的话，又非常困难。</p>
<p>2<span style="white-space: pre" class="Apple-tab-span"> </span>model层中包含的方法越来越多，有些方法也过于复杂。甚至在不少方法中还包含了业务逻辑。</p>
<p>3<span style="white-space: pre" class="Apple-tab-span"> </span>代码的修改，还是牵一发而动全身。</p>
<p>4<span style="white-space: pre" class="Apple-tab-span"> </span>代码难以进行自动化测试。</p>
<p>&nbsp;</p>
<p><strong>本来以为引入了mvc，程序的管理复杂度问题就高枕无忧了，但现在又面临了相同的问题了。</strong></p>
<p>&nbsp;</p>
<p>以我最近的所学看，在mvc中再引入service层，可以在很大程度上避免或者缓解上述问题。</p>
<p>原有的mvc结构改成如下：</p>
<p style="margin: 5px auto">1<span style="white-space: pre" class="Apple-tab-span"> </span>view层：显示层。 </p>
<p style="margin: 5px auto">2<span style="white-space: pre" class="Apple-tab-span"> </span>control层：业务层，集合了各种action。 </p>
<p><strong>3</strong><span style="white-space: pre" class="Apple-tab-span"><strong> </strong></span><strong>service层。</strong></p>
<p><strong>4</strong><span style="white-space: pre" class="Apple-tab-span"><strong> </strong></span><strong>DAO层。</strong></p>
<p>原来的model层不见了，增加了service层和DAO层。<span style="line-height: 24px" class="Apple-style-span">DAO，即Data Access Object，数据访问接口，数据访问：顾名思义就是与数据库打交道</span>。</p>
<p>&nbsp;</p>
<p><strong>在这个结构中，control不直接和DAO联系，</strong></p>
<p><strong>需要操作数据的时候，通过service层访问DAO层来实现。</strong></p>
<p><strong>service层做的事情，不仅仅是调用DAO操作数据，还会包含了一定的业务逻辑。整个程序的设计，也变成了针对服务进行设计。</strong></p>
<p>&nbsp;</p>
<p>这样做的好处是：</p>
<p>1<span style="white-space: pre" class="Apple-tab-span"> </span>control层中的action得以精简，因为action中的一些逻辑，被重构成一个个的服务。<strong>而不同的action也可以重用服务了</strong>。</p>
<p>2<span style="white-space: pre" class="Apple-tab-span"> </span>只负责和数据打交道的DAO层，相比之前的model层，也得以精简（<strong>DAO层尽量只做最原子的数据操作，不同数据操作之间的联系，这边不考虑，那是service层的事情</strong>）。 </p>
<p>3<span style="white-space: pre" class="Apple-tab-span"> </span>service层可以实现很大程度上的代码复用，程序的功能封装更清晰了。</p>
<p>4<span style="white-space: pre" class="Apple-tab-span"> </span>由于service层更加清晰的<span style="line-height: 20px; color: #542d24; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px" class="Apple-style-span">定义了应用程序的边界，<strong>那么对于各个service函数（对应某个服务/应用），要做到自动化测试就方便多了</strong>。WEB程序如何做到能方便的进行单元测试，这是一直困扰我的难题，这样的设计似乎真的可行了~</span> </p>
<p>5<span style="white-space: pre" class="Apple-tab-span"> </span>开发人员的工作分配，理论上真的可以按层次划分了。只是理论上~</p>
<p>&nbsp;</p>
<p>同时，这样的设计模式也是存在一定的缺点的：</p>
<p>层次太多，刚接触的开发人员理解起来比简单的mvc结构费时；</p>
<p>service层的设计需要一定的功力，因为action中和model层的逻辑在很大程度上转移到这里了。</p>
<p>&nbsp;</p>
<p><strong>但整体上看，service </strong><span style="line-height: normal; white-space: pre; font-size: 13px" class="Apple-style-span"><strong>Layer</strong><span style="line-height: 21px; white-space: normal; font-size: 14px" class="Apple-style-span"><strong>的引入，更加清晰的</strong><span style="line-height: 20px; color: #542d24; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px" class="Apple-style-span"><strong>定义了应用程序的边界，提供了一系列可以重用的操作集合。这对于网站的可扩展性和可维护性是非常有帮助的。</strong></span></span></span></p>
<p>&nbsp;</p>
<p>当然，如果网站的业务逻辑并不复杂，完全没必要用这样的设计。过度设计是万恶之源~ </p>
<img src ="http://www.blogjava.net/wealupa/aggbug/333904.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2010-10-07 16:29 <a href="http://www.blogjava.net/wealupa/archive/2010/10/07/333904.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java static 方法并发问题</title><link>http://www.blogjava.net/wealupa/archive/2010/10/07/333853.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Wed, 06 Oct 2010 16:33:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2010/10/07/333853.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/333853.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2010/10/07/333853.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/333853.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/333853.html</trackback:ping><description><![CDATA[只要你的静态方法不访问全局变量的话，就不会有并发问题<br />
<br />
访问全局变量肯定会出现并发问题，这是毫无疑问的<br />
静态方法内部的变量，都是局部变量，每次调用静态方法时都会重新分配内存空间，所以是安全的<br />
<br />
也就是是说只要你的静态方法不访问全局变量的话，就不会有并发问题
<img src ="http://www.blogjava.net/wealupa/aggbug/333853.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2010-10-07 00:33 <a href="http://www.blogjava.net/wealupa/archive/2010/10/07/333853.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>类图和对象图</title><link>http://www.blogjava.net/wealupa/archive/2010/10/06/333842.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Wed, 06 Oct 2010 12:31:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2010/10/06/333842.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/333842.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2010/10/06/333842.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/333842.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/333842.html</trackback:ping><description><![CDATA[<h4><strong>类图的概念</strong></h4>
<p><strong>一、概述</strong></p>
<p>类图（Class Diagram）是描述类、接口、协作以及它们之间关系的图，用来显示系统中各个类的静态结构。类图是定义其他图的基础，在类图基础上，可以使用状态图、协作图、组件图和配置图等进一步描述系统其他方面的特性。</p>
<p>类图包括7个元素：类（Class）、接口（Interface）、协作（collaboration）、依赖关系（Dependency）、泛化关系（Generalization）、关联关系（Association）以及实现关系（Realization）。</p>
<p><strong>二、类</strong></p>
<p>类定义了一组有着状态和行为的对象。其中，属性和关联用来描述状态。属性通常用没有身份的数据值表示，如数字和字符串。关联则用有身份的对象之间的关系表示。行为由操作来描述，方法是操作的实现。对象的生命期则由附加给类的状态机来描述。</p>
<p>1、 名称：类的名称是每个类中所必有的构成元素。</p>
<p>2、 属性（Attribute）</p>
<p>（1） 可见性：类中属性的可见性主要包括公有（public）、私有（Private）和受保护（Protected）。在UML中，公有类型的用&#8220;+&#8221;表达，私有类型用&#8220;-&#8221;表达，而受保护类型则用&#8220;#&#8221;表达。UML的类中不存在默认的可见性，如果没有显示任何一种符号，就表示没有定义该属性的可见性。</p>
<p>（2） 属性名：按照UML的约定，单字属性名小写。如果属性名包含多个单词，这些单词要合并，且除了第一个单词外其余单词的首字母要大写。</p>
<p>（3） 属性字符串。属性字符串用来指定关于属性的其他信息，例如某个属性应该是永久的。任何希望添加在属性定义字符串值但又没有合适地方可以加入的规则，都可以放在属性字符串里。</p>
<p>（4） 类属性。属性也可以作为一个类属属性来定义，这就意味着此属性被该类的所有对象共享。在类图中，类属性带有一条下划线。</p>
<p>3、 操作。类的操作是对类的对象所能做的事务的抽象，相当于一个服务的实现。</p>
<p>4、 职责：在操作部分下面的区域，可以用来说明类的职责。职责是类或其他元素的契约或义务。类的职责是是自由形式的文本，写一个短语，一个句子等。在UML中，把职责列在类图底部的分隔栏中。</p>
<p>5、 约束。说明类的职责是消除二义性的一种非形式化的方法，形式化的方法是使用约束。约束指定了该类所要满足的一个或多个规则。在UML中，约束是用一个花括号括起来的自由文本。</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090027.jpg" width="592" height="209" /></p>
<p><strong>三、接口</strong></p>
<p>接口包含操作但不包含属性，且它没有对外界可见的关联。</p>
<p><strong>四、类之间的关系</strong></p>
<p>类之间的关系最常见的有四种：依赖关系、泛化关系、管理关系、实现关系。</p>
<p>1、 依赖关系（Dependency）</p>
<p>依赖表示两个或多个模型元素之间语义上的关系。它表示了这样一种情形，对于一个元素（提供者）的某些改变可能会影响或提供消息给其他元素（客户），即客户以某种形式依赖于其他类元。根据这个定义，关联、实现和泛化都是依赖关系，但是它们有更特别的语义。在UML中，依赖用一个从客户指向提供者的虚箭头表示，用一个构造型的关键字来区分它的种类。</p>
<p>UML定义了4种基本依赖类型，分别是使用（Usage）依赖、抽象（Abstraction）依赖、授权（Permission）依赖和绑定（Binding）依赖。</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090028.jpg" width="377" height="124" /></p>
<p>（1）、使用依赖。使用依赖都是非常直接的，通常表示客户使用提供者提供的服务以实现它的行为。以下列出了5种使用依赖关系.</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090029.jpg" width="557" height="177" /></p>
<p>（2）、抽象依赖。抽象依赖用来表示客户与提供者之间的关系，依赖于在不同抽象层次上的事物。</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090030.jpg" width="556" height="120" /></p>
<p>（3）、授权依赖。授权依赖表示一个事物访问另一个事物的能力。提供者通过规定客户的权限，可以控制和限制对其内容访问的方法。</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090031.jpg" width="558" height="144" /></p>
<p>（4）、绑定依赖。绑定依赖是较高级的依赖类型，用于绑定模板以创建新的模型元素。</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090032.jpg" width="559" height="75" /></p>
<p>2、泛化关系（Generalization）</p>
<p>泛化关系是一种存在于一般元素和特殊元素之间的分类关系，它只使用在类型上，而不是实例上。在类中，一般元素被称为超类或父类，而特殊元素被称为子类。在UML中，泛化关系用一条从子类指向父类的空心三角箭头表示</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090033.jpg" width="345" height="107" /></p>
<p>3、关联关系（Association）</p>
<p>关联关系是一种结构关系，它指明一个事物的对象与另一个事物的对象之间的联系。也就是说，关联描述了系统中对象或实例之间的离散连接。在UML中，关联关系用一条连接两个类的实线表示</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090034.jpg" width="211" height="97" /></p>
<p>关联关系有6种对应的修饰，它们分别是：名称、角色、多重性、聚合、组合和导航性。</p>
<p>（1）、名称（Name）。名称用来描述关联的性质，通常使用一个动词或动词短语来命名关联。名称以前缀或后缀一个指引阅读的方向指示符以消除名称含义上可能存在的歧义，方向指示符用一个实心的三角形箭头表示。</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090035.jpg" width="254" height="90" /></p>
<p>（2）、角色（Role）。角色是关联关系中一个类对另一个类所表现出来的职责。角色名称是名词或名词短语，以解释对象是如何参与关联的。</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090036.jpg" width="248" height="107" /></p>
<p>（3）、多重性（Multiplicity）。约束是UML三大扩展机制之一，多重性是其中使用最广泛的一种约束。关联的多重性是指有多少对象可以参与该关联，多重性可以用来表达一个取值范围、特定值、无限定的范围或一组离散值。</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090037.jpg" width="276" height="105" /></p>
<p>（4）、聚合（Aggregation）。聚合关系表示整体和部分关系的关联。聚合关系描述了&#8220;has a&#8221;的关系。在UML中聚合关系用带空心的实线来表示，其中头部指向整体。</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090038.jpg" width="222" height="180" /></p>
<p>（5）、组合关系(Composition)。组合关系是聚合关系中的一种特殊情况，是更强形式的聚合，又被称为强聚合。在组合中，成员对象的生命周期取决于聚合的生命周期，聚合不仅控制着成员对象的行为，而且控制着成员对象的创建和析构。在UML中，组合关系用带实心菱头的实线来表示，其中头部指向整体。</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090039.jpg" width="308" height="208" /></p>
<p>（6）、导航性(Nevigation)。导航性描述的是一个对象通过链（关联的实例）进行导航访问另一个对象，即对一个关联端点设置导航属性意味着本端的对象可以被另一端的对象访问。可以在关联关系上加箭头表示导航方向。只在一个方向上可以导航的关联称为单向关联(Unidirection Association),用一条带箭头的实线来表示。在两个方向上都可以导航的关联称为双向关联(Bidirection Association),用一条没有箭头的实线来表示。另外使用导航性可以降低类之间的耦合度，在也是好的面向对象分析与设计的目标之一。</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090040.jpg" width="248" height="106" /></p>
<p>4、实现关系（Realization）</p>
<p>实现是规格说明和其实现之间的关系，它将一种模型元素与另一种模型元素连接起来，比如类和接口。</p>
<p>泛化和实现关系都可以将一般描述与具体描述联系起来。泛化将同一语义层上的元素连接起来，并且通常在同一模型内。实现关系则将不同语义层内的元素连接起来，通常建立在不同的模型内。</p>
<p>实现关系通常在两种情况下被使用：在接口与实现该接口的类之间；在用例以及实现该用例的协作之间。</p>
<p>在UML中，实现关系的符号与泛化关系的符号类似，用一条带指向接口的空心三角箭头的虚线表示。下图所示的是实现关系的一个示例，描述的是Keyboard保证自己的部分行为可以实现Typewriter的行为</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090041.jpg" width="369" height="139" /></p>
<p>实现关系还有一种省略的表示方法，即接口表示为一个小圆圈，并和实现接口的类用一条线段连接，如图</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090042.jpg" width="389" height="141" /></p>
<h4><strong>类图建模技术</strong></h4>
<p><strong>一、对简单协作建模</strong></p>
<p>类不是单独存在的，而是要与其他类协同工作。协作是动态交互在静态视图上的映射，协作的静态结构通过类图来描述。</p>
<p>对协作建模要遵循如下策略</p>
<p>1、识别要建模的机制。一个机制描述了正在建模的部分系统的一些功能和行为，这些功能和行为是由类、接口和一些其他元素的相互作用产生的。</p>
<p>2、对每种机制，识别参与协作的类、接口和其他协作，并识别这些事物之间的关系。</p>
<p>3、用协作的脚本检测事物，通过这种方法可以发现模型中被遗漏的部分和有明显语义错误的部分。</p>
<p>4、把元素和它们的内容聚合在一起。对于类，首先平衡好职责，随着时间的推移，将它们转换成具有的属性和操作。</p>
<p><strong>二、对逻辑数据库模式建模</strong></p>
<p>通用的逻辑数据库建模工具是&#8220;实体-关系（E-R）&#8221;图，传统的E-R图只针对数据，而UML的类图还允许对行为建模。在物理数据库中，类图一般要把逻辑操作转化成触发器或存储过程。</p>
<p>对模式建模要遵循如下策略：</p>
<p>1、在模型中识别的类，其状态必须超过其应用系统的生命周期。</p>
<p>2、创建包含这些类的类图，并把它们标记为永久（persistent）。对于特定的数据库细节，可以定义自己的标记值集合。</p>
<p>3、展开这些类的结构性细节，即详细描述属性的细节，并注重于关联和构造类的基数。</p>
<p>4、观察系统中的公共模式（如循环关联、一对一关联和n元关联），它们常常造成物理数据库设计的复杂化。</p>
<p>5、考虑这些类的行为，扩展对数据库存储和数据完整性来说重要的操作。一般情况下，与对象集的操作相关的业务规则应该被封装在永久类的上一层。</p>
<p><strong>三、正向工程和逆向工程</strong></p>
<p>1、正向工程（Forward Engineering）</p>
<p>正向工程是通过实现语言的映射把模型转换为代码的过程。由于UML中描述的模型在语义上比当前的任何面向对象语言要丰富，所以正向工程会导致一定信息的损失，这也是需要模型的原因。</p>
<p>对类图进行正向工程，要遵循如下的策略 </p>
<p>(1)、识别映射到所选择的实现语言的规则</p>
<p>(2)、根据所选择的语言的语义，可能会限定一些对UML特性的使用</p>
<p>(3)、用标记值详细描述目标语言，若需要精确的控制，该操作可以在单个类的层次上进行，也可以在较高的层次(如协作或包)上进行</p>
<p>(4)、使用工具对模型进行正向工程</p>
<p>2、逆向工程（Reverse Engineering）</p>
<p>逆向工程是通过从特定实现语言的映射，把代码转换为模型的过程。逆向工程会导致大量的冗余信息同时逆向工程又是不完整的。</p>
<p>对类图进行逆向工程，要遵循如下的策略</p>
<p>(1)、识别从实现语言或所选的语言进行映射的规则</p>
<p>(2)、使用工具，指向要进行逆向工程的代码，用工具生成新的模型或修改以前进行正向工程时已有的模型。</p>
<p>(3)、使用工具，通过查询模型创建类图。</p>
<h4><strong>对象图</strong></h4>
<p><strong>一、概述</strong></p>
<p>对象图(Object Diagram)描述的是参与交互的各个对象在交互过程中某一时刻的状态。对象图可以被看作是类图在某一时刻的实例。</p>
<p>在UML中，对象图使用的是与类图相同的符号和关系，因为对象就是类的实例。下图显示了对象图的模型。其中节点可以是对象也可以是类，连线表示对象之间的关系：</p>
<p><img alt="" src="http://www.uml.org.cn/oobject/images/081010090043.jpg" width="268" height="89" /></p>
<p><strong>二、类图和对象图的区别</strong></p>
<table id="table6" class="content" border="1" cellspacing="0" cellpadding="1" width="800">
    <tbody>
        <tr class="content">
            <td>
            <p align="center"><font face="宋体"><strong><span style="line-height: 150%; font-family: 宋体; font-size: 9pt">&nbsp;类图</span></strong></font></p>
            </td>
            <td>
            <p align="center"><font face="宋体"><strong><span style="line-height: 150%; font-family: 宋体; font-size: 9pt">&nbsp;对象图</span></strong></font></p>
            </td>
        </tr>
        <tr class="content">
            <td>&nbsp;类具有3个分栏：名称、属性和操作</td>
            <td>&nbsp;对象只有两个分栏：名称和属性</td>
        </tr>
        <tr class="content">
            <td>&nbsp;在类的名称分栏中只有类名</td>
            <td>&nbsp;对象的名称形式为&#8220;对象名：类名&#8221;，匿名对象的名称形式为&#8220;：类名&#8221;</td>
        </tr>
        <tr class="content">
            <td>&nbsp;类的属性分栏定义了所有属性的特征</td>
            <td>&nbsp;对象则只定义了属性的当前值，以便用于测试用例或例子中</td>
        </tr>
        <tr class="content">
            <td>&nbsp;类中列出了操作</td>
            <td>&nbsp;对象图中不包括操作，因为对于同属于同一个类的对象而言，其操作是相同的</td>
        </tr>
        <tr class="content">
            <td>&nbsp;类使用关联连接，关联使用名称、角色、多重性以及约束等特征定义。类代表的是对对象的分类所以必须说明可以参与关联的对象的数目</td>
            <td>&nbsp;对象使用链连接、链拥有名称、角色，但是没有多重性。对象代表的是单独的实体，所有的链都是一对一的，因此不涉及到多重性。</td>
        </tr>
    </tbody>
</table>
<h4><strong>对象图建模技术</strong></h4>
<p><strong>一、对对象结构建模</strong></p>
<p>对系统的设计视图建模时，可以使用一组类图完整地描述抽象的语义以及它们之间的关系。但是使用对象图不能完整地描述系统的对象结构。对于一个个体类，可能存在多个实例，对于相互之间存在关系的一组类，对象间可有的配置可能是相当多的。所以，在使用对象图时，只能在一定意义上显示感兴趣的具体或原型对象集。这就是对对象结构建模，即一个对象图显示了某一时刻相互联系的一组对象。</p>
<p>对对象结构建模，要遵循以下策略：</p>
<p>(1)、识别将要使用的建模机制。该机制描述了一些正在建模的部分系统的功能和行为，它们由类、接口和其他元素的交互而产生。</p>
<p>(2)、对于各种机制，识别参与协作的类、接口和其他元素，同时也要识别这些事物之间的关系。</p>
<p>(3)、考虑贯穿这个机制的脚本。冻结某一时刻的脚本，并且汇报每个参与这个机制的对象。</p>
<p>(4)、按照需要显示出每个对象的状态和属性值，以便理解脚本。</p>
<p>(5)、显示出对象之间的链，以描述对象之间关联的实例。</p>
<p><strong>二、正向工程和逆向工程</strong></p>
<p>1、正向工程</p>
<p>对对象图工程进行正向工程在理论上是可行的，但是在实际上却是受限制的。 </p>
<p>2、逆向工程</p>
<p>对对象图进行逆向工程是非常困难的。当对系统进行调试时，总要依靠开发人员或工具来进行。</p>
<img src ="http://www.blogjava.net/wealupa/aggbug/333842.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2010-10-06 20:31 <a href="http://www.blogjava.net/wealupa/archive/2010/10/06/333842.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>教程：VS2010 之TFS入门指南</title><link>http://www.blogjava.net/wealupa/archive/2010/09/19/332433.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sun, 19 Sep 2010 07:07:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2010/09/19/332433.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/332433.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2010/09/19/332433.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/332433.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/332433.html</trackback:ping><description><![CDATA[<p>本月初，我们发布了TFS新基础配置。该配置为建立支持源码管理，工作项和生成（builds）的TFS版本提供了便利。 这是一个好机会将你在VSS(Visual Source Safe)上的资源迁移到TFS，并且还可以选用一些新的特性。现在VS2010 Beta2的正式版已经发布了，下面是该系统的入门指南。</p>
<p>这篇文章对那些还没有安装或使用过TFS的人将最有帮助。TFS有对复杂环境的良好支持。比如，报表，SharePoint的整合，支持跨多域，分布式数据库等等。不过我不打算在这里讲述其中的任何一个部分，我的目的是帮助你们了解为什么我们要选择TFS，以及如何使用它。如果你是VSS的用户， 在今后的文章中，我会讲述如何将VSS数据库迁移到TFS上。</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image001(zh-cn,MSDN.10).png" /></p>
<p>在上图中，每个系统都有独立的存储空间，资源标识集，命令和工具集。要让整个系统工作起来，就像把一组自定义立体组件联接在一起：可以实现，但工作量巨大，而且可能在一些地方出现纰漏。</p>
<p>我更想要的就是这样一个系统，它可以将这些工作整合到一起并实现我默认的工作流程。</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image002(zh-cn,MSDN.10).png" /></p>
<p>这个整合实现了一些非常常见的场景。例如每天我会编辑源代码，生成产品并测试它，报Bug并修复它，周而复始。当有一个整合的系统可以全部支持这些工作流程时，那么所有的工作就可以被关联起来。例如，当我签入Bug的修复时，我很想看到那些缺陷被解决时这个变更集能被纪录下来。（详见下面的例子）</p>
<p>TFS的基础配置可以让你精确地做到这些。这跟简单的源码管理相比是一个巨大的进步。TFS的完整版将会加入一些新的特性，包括自动化测试，虚拟实验室的部署和架构验证。下面是扩展后的工作流程：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image003(zh-cn,MSDN.10).png" /></p>
<p>当你使用Visual Studio 加强版和旗舰版的时候，你可以根据需要选择安装这些新组件。</p>
<p>有许多方法可以访问TFS。开发人员经常会通过Visual Studio来访问它。测试人员可以通过新的Test and Lab Manager来访问TFS（没有必要安装VS）。如果你是项目经理，你也可以通过web接口，Excel，Microsoft Project，或者dashboards的MOSS支持（VS2010的新功能）来访问TFS。更多相关内容以后介绍。</p>
<p>在这篇文章的其余部分，我会向你们逐步介绍如何使用基础配置来开始我们的第一个TFS工程。</p>
<p><strong>入门指南</strong></p>
<p>现在, 有了概念层次的了解，是时候把它们连接起来了。以Brian Harry的 TFS文章所列出的<a id="ctl00_mainContentContainer_ctl03" onclick="javascript:Track('ctl00_mainContentContainer_ctl00|ctl00_mainContentContainer_ctl03',this);" href="http://blogs.msdn.com/bharry/archive/2009/10/01/tfs-2010-for-sourcesafe-users.aspx">步骤</a>为开端。所有必要的软件会以默认集合（创造性的称为DefaultCollection）的形式安装到你的机器上。</p>
<p>在这里我们能通过Visual Studio连接到TFS里。做到这一点最简单的方法是使用菜单&#8220;团队&#8221;（你也可以使用起始页上的链接）：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image004(zh-cn,MSDN.10).png" /></p>
<p>这里需要输入TFS的服务器名称。例如，我的Windows 7机器：JLZB2REL。通过添加按钮把服务器加入到列表里， 然后点击关闭：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image005(zh-cn,MSDN.10).png" /></p>
<p>在这里，你可以从组合框里选择服务器，接着选择DefaultCollection，然后点击连接：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image006(zh-cn,MSDN.10).png" /></p>
<p>现在团队资源管理器选项卡有了服务器连接和DefaultCollection，但我们还没有一个可以存储东西的TFS项目：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image007(zh-cn,MSDN.10).png" /></p>
<p>我为本教程创建了一个新的Windows窗体项目作为我们的解决方案样本（文件，新建项目，Windows窗体）。如果你试图添加新的代码项目到源代码管理，会出现错误。例如：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image008(zh-cn,MSDN.10).png" /></p>
<p>你选择&#8220;将解决方案添加到源代码管理&#8221;菜单项后，你会得到&#8220;没有可用的团队项目源代码管理文件夹&#8221;的错误信息：</p>
<p><br />
<img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image009(zh-cn,MSDN.10).png" /></p>
<p>该错误不是很直观（特别是所提供的词项目是用于TFS和你们代码解决方案里面，而它们是不同的概念）。此错误的意思是你必须创建一个真实的TFS项目去包含你工作中有用的资源。在团队资源管理器中，右键点击你的集合，选择新建团队项目：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image010(zh-cn,MSDN.10).png" /></p>
<p>在这里我将为应付帐款系统创建一个TFS项目。该项目将包含整个系统所有需要的解决方案，数据等。填写完资料，点击下一步:</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image011(zh-cn,MSDN.10).png" /></p>
<p>默认的是Agile模板，但你也可以选择CMMI模板。关于模板类型你可以在MSDN上获取更详细的说明。如果你正在使用agile方法（比如TDD），这是个不错的选择。选择后，点击完成。</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image012(zh-cn,MSDN.10).png" /></p>
<p>项目创建过程中，会有各种状态更新。</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image013(zh-cn,MSDN.10).png" /></p>
<p>成功后，点击关闭按钮：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image014(zh-cn,MSDN.10).png" /></p>
<p>团队资源管理器显示了该项目，将包含工作项，生成和源代码管理：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image015(zh-cn,MSDN.10).png" /></p>
<p>此时可以更新项目集合。再增加一个解决方案到TFS中：右击解决方案资源管理器中的项目，选择&#8220;将解决方案添加到源代码管理&#8221;：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image016(zh-cn,MSDN.10).png" /></p>
<p>此时可以在TFS中为解决方案新建一个文件夹或者只是采用默认值。如果准备好了，请点击确定。</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image017(zh-cn,MSDN.10).png" /></p>
<p>到此就可以在解决方案资源管理器中看到所有文件已经在源码管理下了。（查看文件前面的&#8220;+&#8221;号）</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image018(zh-cn,MSDN.10).png" /></p>
<p>此时可以看到列出的源代码管理器可采取的公开解决方案的动作。添加注释然后点击签入：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image019(zh-cn,MSDN.10).png" width="600" /></p>
<p>点击是确认签入。</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image020(zh-cn,MSDN.10).png" /></p>
<p>此时新的解决方案就在TFS中了，并且可以开始工作项了。</p>
<p><strong>工作项</strong></p>
<p>可以直接在Visual Studio里用团队资源管理器或者通过网页前端和Test and Lab Management工具 来创建工程项目。打开团队资源管理器，并展开工作项下的Team Queries项来浏览你的工程项目。也可以通过双击任意查询选项（例如Active Bugs）来浏览任意你所能看到的项目。</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image021(zh-cn,MSDN.10).png" /></p>
<p>因为我们的TFS工程是空的，所以在列表中没有active Bug。</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image022(zh-cn,MSDN.10).png" /></p>
<p>创建一个新的bug，选择菜单：团队，新建工程项。这里可以创建多种工作项来跟踪功能点，缺陷等等。选择Bug继续：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image023(zh-cn,MSDN.10).png" /></p>
<p>为这个新的Bug填入相关资料，然后点击保存工程项来提交到数据库中。</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image024(zh-cn,MSDN.10).png" width="600" /></p>
<p>如果现在刷新Active Bug查询列表，你会看到这个新的Bug：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image025(zh-cn,MSDN.10).png" width="600" /></p>
<p>现在添加一个真正的Bug来修复我们的工程。在我的例子中，只是创建了一个默认的Windows Forms应用程序。如要更新标题：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image026(zh-cn,MSDN.10).png" /></p>
<p>现在我们需要修复这个Bug。重新回到解决方案资源管理器，选择Form1.cs，然后选择&#8220;签出以进行编辑&#8221;：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image027(zh-cn,MSDN.10).png" /></p>
<p>点击&#8220;签出&#8221;按钮来确定：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image028(zh-cn,MSDN.10).png" /></p>
<p>现在在文件的旁边会有一个打勾的标记，这样你就知道它已经可以编辑了：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image029(zh-cn,MSDN.10).png" /></p>
<p>当你更新主窗口的Text属性时，VS会自动签出任何依赖的文件：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image030(zh-cn,MSDN.10).png" /></p>
<p>这个例子虽然是一个Windows Forms应用程序，但它也支持其他所有的solution/project类型。现在我们对代码改动满意了，在VS的底部选择&#8220;挂起的更改&#8221;标签。</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image031(zh-cn,MSDN.10).png" /></p>
<p>在这个例子中，我们修复了一个Bug，所以点击&#8220;工作项&#8221;图标按钮：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image032(zh-cn,MSDN.10).png" /></p>
<p>选择用来跟踪我们标题错误的Bug#6。我们想要通过这个签入来解决它：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image033(zh-cn,MSDN.10).png" /></p>
<p>添加注释并点击签入，然后点击&#8220;是&#8221;确认。</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image034(zh-cn,MSDN.10).png" /></p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image035(zh-cn,MSDN.10).png" /></p>
<p>如果刷新Bug#6，你会看到现在状态已经变为Resolved，并且历史纪录已经更新了。</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image036(zh-cn,MSDN.10).png" /></p>
<p>请注意&#8220;变更集&#8221;（源码管理改变的集合）已经被自动添加到历史纪录中。</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image037(zh-cn,MSDN.10).png" /></p>
<p>这时候可以按你工程需要继续创建和修复Bug。</p>
<p><strong>其他访问TFS的方法</strong></p>
<p>我前面提到过没必要必须使用VS来访问TFS。我们已经将TFS与其它客户端作了许多深层次的整合，例如网页和Office。举个例子，我可以通过网页浏览器，很简单地用服务器的名字连接到我的服务器（8080是默认端口）：<a id="ctl00_mainContentContainer_ctl04" title="http://jlzb2rel:8080/tfs/" onclick="javascript:Track('ctl00_mainContentContainer_ctl00|ctl00_mainContentContainer_ctl04',this);" href="http://jlzb2rel:8080/tfs/">http://jlzb2rel:8080/tfs/</a></p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image038(zh-cn,MSDN.10).png" /></p>
<p>现在我可以浏览我的集合和工程了。如果你选择我们刚刚新建的AccountsPayable项目，然后点击&#8220;继续&#8221;按钮，会看到更多的信息。在这个例子中，通过导航到Work Items标签，可以找到这个系统中所有的Bug。</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image039(zh-cn,MSDN.10).png" /></p>
<p>这确实是一个浏览你的工程的简单方法。可以在任何一台电脑上，并且不需要安装额外的东西。这些操作在Excel，Microsoft Project等其他软件中也有相关的支持。这种访问方式使该项目中的所有成员一起工作变得更加简单。</p>
<p>此时，你拥有了一套非常有用的工具来轻松完成工作。如果你在使用VSS，仅仅是这些内容就已经令人兴奋了。现在可以放下这个教程，休息会再回来，如果你想要尝试一些高级属性的话，例如测试场景。我会使用beta 1在这个<a id="ctl00_mainContentContainer_ctl05" onclick="javascript:Track('ctl00_mainContentContainer_ctl00|ctl00_mainContentContainer_ctl05',this);" href="http://blogs.msdn.com/jasonz/archive/2009/05/26/vs2010-tutorial-testing-tutorial-step-2.aspx">教程</a>中来演示。</p>
<p><strong>生成支持</strong></p>
<p>工作流程的下一个典型的环节就是自动生成产品。如果遵循Brian的安装说明，那么现在你的机器上就有了TFS基本的本地生成支持。第一步是要导航到团队资源管理器中，右键点击&#8220;所有生成定义&#8221;，选择&#8220;新建生成定义&#8221;：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image040(zh-cn,MSDN.10).png" /></p>
<p>有一系列的定义需要填，就像一个代码项目的属性页：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image041(zh-cn,MSDN.10).png" /></p>
<p>触发页面使我们能够决定生成何时开始。你可以从下列项中选择：</p>
<p>&#183;默认情况下使用手动项。我们必须以这一项开始我们自己的生成。</p>
<p>&#183;每一次签入后，当你想拥有一个新的生成的时候，持续集成是非常有用的。它允许你立刻验证新的签入而不用等很多的签入混合在一起后再验证。</p>
<p>&#183;滚动生成提供了一种批处理改变的方法，当开始生成要花一点时间并且你无法去做每一项时，这种方法很便利。</p>
<p>&#183;封闭签入让你确保所有的签入传入TFS前被生成。并确保你不会对你项目组的其它成员造成生成破坏。</p>
<p>&#183;计划生成为整个团队做每日生成进行了有益的尝试</p>
<p>可以创建和使用多个不同的生成定义，允许您根据不同的目的来使用不同类型的生成。</p>
<p>你可以在空闲的时候查看所有标签(每一项在产品上都完整的文档说明). 但是我们需要提供给生成一个存储新生成的位置来解决默认生成中的黄色警告标志，在这里，我在我的机器上创建了一个公共的UNC：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image042(zh-cn,MSDN.10).png" /></p>
<p>现在可以保存生成定义到TFS。如果回到团队资源管理器，我们可以&#8220;使新的生成入队&#8221;：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image043(zh-cn,MSDN.10).png" /></p>
<p>在跳出的确认对话框中，选择排队：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image044(zh-cn,MSDN.10).png" /></p>
<p>这是我机器上状态页显示的已排队的一个生成：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image045(zh-cn,MSDN.10).png" width="600" /></p>
<p>如果双击队列中的生成，可以得到这个生成的详细状态：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image046(zh-cn,MSDN.10).png" /></p>
<p>从这里你可以看到警告和错误，日志文件，导航到Drop的目录等。例如，如果你选择&#8220;查看日志文件&#8221;，你能看到执行生成的脚本（子集）：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image047(zh-cn,MSDN.10).png" /></p>
<p>如果你选择打开Drop文件夹链接，你会被带到我们drop的位置：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image048(zh-cn,MSDN.10).png" /></p>
<p>现在任何人都可以选择生成来做他们日常测试，或发布给客户等。</p>
<p>此时您已经知道利用了TFS的基本配置所有东西。</p>
<p>将来我会做一个如何安装使用虚拟实验室系统的教程（Visual Studio 旗舰版的一部分），使您能够部署复杂的应用程序到Hyper - V的环境，做自动化测试。</p>
<p><strong>创建一个新的TFS集合</strong></p>
<p>&nbsp;[注意：这部分是完全可选的] 如果你喜欢你可以在一个TFS中存储你所有的工作。如果你是一个Visual Source Safe用户，你可以跳过这一整部分。但是如果你想创建一个新的顶级集合，相当的简单。第一步是启动，然后是团队基础管理控制台：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image049(zh-cn,MSDN.10).png" /></p>
<p>控制台启动后，选择&#8220;团队项目集合项&#8221;， 点击&#8220;创建团队项目集合&#8221;链接：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image050(zh-cn,MSDN.10).png" /></p>
<p>为项目的收集填写一个你想要描述的名称后，点击&#8220;下一步&#8221;：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image051(zh-cn,MSDN.10).png" /></p>
<p>接受数据层的默认值，然后点击&#8220;下一步&#8221;：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image052(zh-cn,MSDN.10).png" /></p>
<p>TFS基本配置不支持实验室管理，因此直接下一步：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image053(zh-cn,MSDN.10).png" /></p>
<p>在这里所有需要的数据都被配置了，你可以选择&#8220;核实&#8221;：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image054(zh-cn,MSDN.10).png" /></p>
<p>验证这些信息主要是为了集合可以顺利的创建：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image055(zh-cn,MSDN.10).png" /></p>
<p>当核实结束后，点击创建：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image056(zh-cn,MSDN.10).png" /></p>
<p>这一步为TFS的每一个配置提供所有需要的东西。点击下一步就完成了：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image057(zh-cn,MSDN.10).png" /></p>
<p>你将会看到一个默认版本的新项目集：</p>
<p><img title="" alt="" align="top" src="http://i.msdn.microsoft.com/ff645221.image058(zh-cn,MSDN.10).png" /></p>
<img src ="http://www.blogjava.net/wealupa/aggbug/332433.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2010-09-19 15:07 <a href="http://www.blogjava.net/wealupa/archive/2010/09/19/332433.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TFS 权限攻略1（默认组的权限）</title><link>http://www.blogjava.net/wealupa/archive/2010/09/16/332194.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 16 Sep 2010 08:14:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2010/09/16/332194.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/332194.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2010/09/16/332194.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/332194.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/332194.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 首先，在TFS 2008中，有三个地方需要设置用户权限。它们分别是：TFS全局权限，TFS项目级权限，代码管理权限。 我们可以看到默认组中的权限是这样给的。 TFS全局权限                                                         　&nbsp;                    ...&nbsp;&nbsp;<a href='http://www.blogjava.net/wealupa/archive/2010/09/16/332194.html'>阅读全文</a><img src ="http://www.blogjava.net/wealupa/aggbug/332194.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2010-09-16 16:14 <a href="http://www.blogjava.net/wealupa/archive/2010/09/16/332194.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Eclipse 3.5使用dropins的插件安装方式</title><link>http://www.blogjava.net/wealupa/archive/2010/09/09/331493.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 09 Sep 2010 03:57:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2010/09/09/331493.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/331493.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2010/09/09/331493.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/331493.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/331493.html</trackback:ping><description><![CDATA[<h5>以前安装Eclipse插件无非两种方式, 直接copy插件到features/plugins目录或者在links目录下创建链接文件. 刚刚发布的Eclipse 3.5又推出另一种新的安装途径, 更加灵活。Eclipse 3.5下有个dropins目录, 只要把插件放到该目录下就可以加载, 有几种格式可以选择。 </h5>
<div class="contenttext">
<p>Eclipse 3.5插件安装方式 <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以前安装Eclipse插件无非两种方式, 直接copy插件到features/plugins目录或者在links目录下创建链接文件. 刚刚发布的Eclipse 3.5又推出另一种新的安装途径, 更加灵活。Eclipse 3.5下有个dropins目录, 只要把插件放到该目录下就可以加载, 有几种格式可以选择。 <br />
<br />
1. 最简单的，直接将jar包放到dropins目录: <br />
<br />
&nbsp;&nbsp;&nbsp; eclipse/ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dropins/ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; com.essiembre.eclipse.i18n.resourcebundle_0.7.7 <br />
<br />
<br />
2. 传统格式，统一放到一个eclipse目录下: <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eclipse/ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dropins/ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eclipse/ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; features/ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; plugins/ <br />
<br />
<br />
3. 按照插件名称区分: <br />
&nbsp;&nbsp;&nbsp; eclipse/ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dropins/ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; resourcebundleeditor/ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; features/ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; plugins/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m2eclipse/ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; features/ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; plugins/ <br />
<br />
4. 类似links方式添加链接: <br />
<br />
&nbsp;&nbsp;&nbsp; eclipse/ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dropins/ <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sysdeo.link <br />
&nbsp;&nbsp;&nbsp; 内容如下： <br />
&nbsp;&nbsp;&nbsp; path=/home/danson/personal-data/software/ide/eclipse-plugins/sysdeo <br />
&nbsp;&nbsp;&nbsp; 其中sysdeo目录下结构为eclipse/plugins/com.sysdeo.eclipse.tomcat_3.2.1 <br />
<br />
<br />
<br />
如果只安装一个Eclipse的话建议采用第三种，否则采用第四种。</p>
<p>强制更新，</p>
<p>使用eclise -clean(命令加参数)起动eclipse.在查看"mamage configuration"时,我碰到去掉的插件还存在显示,或者会有去掉的,然后再加载的重复显示,这情况,可以删除eclipse目录里的 configuration目录下的org.eclipse.update,然后重启eclipse来解决.</p>
</div>
<img src ="http://www.blogjava.net/wealupa/aggbug/331493.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2010-09-09 11:57 <a href="http://www.blogjava.net/wealupa/archive/2010/09/09/331493.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Eclipse入门之插件管理浅谈</title><link>http://www.blogjava.net/wealupa/archive/2010/09/08/331408.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Wed, 08 Sep 2010 08:19:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2010/09/08/331408.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/331408.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2010/09/08/331408.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/331408.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/331408.html</trackback:ping><description><![CDATA[临近毕业了，在一家公司做毕业设计。由于工作上的需要，开始接触Eclipse。<br />
&nbsp;&nbsp;&nbsp; 这篇帖子关于Eclipse插件管理，目的有二：第一，对Eclipse的基本工作要素有一个大致的认识；第二，掌握几种添加Eclipse插件的方法。<br />
&nbsp;&nbsp;&nbsp; Eclipse的特色之一，就是它的插件功能。可以说，Eclipse是一个插件的大集合，所有的模块都以插件的形式存在。那么，究竟什么是插件呢？插件（plug-in），即Eclipse的功能模块。好像一个模型，附加的功能可以自由添加或拆卸。相关的插件构成了特性（feature）。下面让我们来看一下Eclipse<span>的目录结构：<br />
<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 99.1%; padding-right: 5px; height: 55px; font-size: 13px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><font face="Arial"><strong><span style="color: #000000">\eclipse<br />
&nbsp;&nbsp;&nbsp; \features<br />
&nbsp;&nbsp;&nbsp; \plugins</span></strong></font></div>
</span>
<p style="text-indent: 17.95pt; margin: 0cm 0cm 0pt" class="MsoNormal"><span style="font-family: Times New Roman">&nbsp;&nbsp; <br />
</span></p>
<p style="text-indent: 17.95pt; margin: 0cm 0cm 0pt" class="MsoNormal"><span style="font-family: Times New Roman">&nbsp;&nbsp; features</span><span style="font-family: 宋体">目录存放特性，</span><span style="font-family: Times New Roman">plugins</span><span style="font-family: 宋体">目录存放插件。接下来介绍一下如何安装插件。&nbsp; </span></p>
<p>
<p>一、直接安装法<br />
&nbsp;&nbsp;&nbsp; 直接安装最简单，第一种就是将下载的plugin直接拷贝到eclipse的plugin目录下。第二种是在help-&gt;software updates-&gt;find and install中找到插件并安装。这类方法虽然简便，但是缺点也十分明显。两种方法的实质都是将插件拷贝到eclipse的安装目录中一旦copy过去，插件本身就不可能再复用，且各种插件混杂在一起，不利于插件的管理。</p>
<p>二、Manage Configuration法<br />
&nbsp;&nbsp;&nbsp; 将插件存储在eclipse外部，可以使几个版本的Eclipse同时使用插件，也方便插件管理，所以我推荐这种插件安装方式。具体操作如下：<br />
&nbsp;&nbsp;&nbsp; 首先，在插件所在的eclipse目录下创建名为.eclipseextension的文件。如，我要安装EMF的插件，以下是我建立的扩展文件：<br />
</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 99.32%; padding-right: 5px; height: 36px; font-size: 13px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><font face="Arial"><strong><span style="color: #000000">id</span><span style="color: #000000">=</span><span style="color: #000000">org.eclipse.emf&nbsp;<br />
name</span><span style="color: #000000">=</span><span style="color: #000000">EMF<br />
version</span><span style="color: #000000">=</span><span style="color: #000000">2.2</span><span style="color: #000000">.</span><span style="color: #000000">0</span></strong></font></div>
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 你可以根据依据你的插件信息来修改上述参数。注意：.eclipseextension创建时，可以使用Notepad，保存为所有格式，文件名就是.eclipseextension。<br />
&nbsp;&nbsp;&nbsp; 文件创建好后，我们启动Eclipse。运行Manage Configuration：<br />
<br />
<div align="center"><span style="font-family: 'Times New Roman'; font-size: 10.5pt"><img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/bjlimeng/manage_1.png" /></span><br />
</div>
<span style="font-family: 'Times New Roman'; font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-size: 10pt"><br />
&nbsp;&nbsp;&nbsp;&nbsp; 之后，我们选择Add-&gt;Extension Location：<br />
<br />
</span></span>
<div align="center"><span style="font-family: 'Times New Roman'; font-size: 10.5pt"><span style="font-size: 10pt"><img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/bjlimeng/config_1.png" /></span></span><br />
</div>
<br />
&nbsp;&nbsp;&nbsp; 选择你要安装的插件的路径，然后Finish。Eclipse会提示你，restart后才会生效。这样，restart之后，我们的插件就算安装完毕了。你会在new-&gt;project里面看到EMF的相关wizard。<span><span style="font-family: 'Times New Roman'; font-size: 10.5pt"><span style="font-size: 10pt">&nbsp;
<p>三、Link法<br />
&nbsp;&nbsp;&nbsp; 如果我们在插件的eclipse目录中创建了.eclipseextension文件（方法和位置同二），我们还可以在Eclipse的安装目录下建一个文件夹，名为links。在这个目录中，我们可以创建*.link（文件名任意）。扩展名为link的文件应该如下配置：</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><font face="Arial"><strong><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" /><span style="color: #000000">path</span><span style="color: #000000">=</span><span style="color: #000000">d:\\plugins\\emf</span></strong></font></div>
</span><br />
&nbsp;&nbsp;&nbsp; 在windows下，注意要双写反斜杠。指向的目录要是插件的根目录。（如上面：emf目录下应该有eclipse目录）在启动时，Eclipse会自动监测links目录。<br />
&nbsp;&nbsp;&nbsp; 总结：Eclipse的插件安装方法大致可以分为三种，分别是直接安装，通过Manage Configuration安装，利用Links进行安装。其中，我推荐后两种插件安装方法，灵活且便于管理。<br />
<p>
<p>四、向导安装<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第四种方法也很<span style="font-family: 宋体">简单</span>，它主要借助于Eclipse的向<span style="font-family: 宋体">导</span>来安装插件。通<span style="font-family: 宋体">过</span>Help/Software Updates/Find and Install，在<span style="font-family: 宋体">弹</span>出的菜<span style="font-family: 宋体">单</span>中<span style="font-family: 宋体">选择</span>&#8220;Search for new features to install&#8221;，点&#8220;Next&#8221;，在下一菜<span style="font-family: 宋体">单</span>中<span style="font-family: 宋体">选择</span>&#8220;New Local Site&#8221;或&#8220;New Archived Site&#8221;，找到你下<span style="font-family: 宋体">载</span>的插件所在目<span style="font-family: 宋体">录</span>，<span style="font-family: 宋体">选</span>中安装即可。 <span style="font-family: 宋体">这</span>种方法安装插件比<span style="font-family: 宋体">较</span>安全，不易出<span style="font-family: 宋体">错</span>，缺点就是<span style="font-family: 宋体">对</span>于插件的要求也比<span style="font-family: 宋体">较</span>挑剔，所以能<span style="font-family: 宋体">够</span>支持<span style="font-family: 宋体">这</span>种方式安装的插件也比<span style="font-family: 宋体">较</span>少。一般要求插件目<span style="font-family: 宋体">录</span>下不光有plugins和features文件<span style="font-family: 宋体">夹</span>，<span style="font-family: 宋体">还</span>要有site.xml文件（site.xml是<span style="font-family: 宋体">进</span>行自<span style="font-family: 宋体">动</span>安装的配置文件，eclipse会根据文件的信息自<span style="font-family: 宋体">动</span>安装插件）。支持J2ME开<span style="font-family: 宋体">发</span>的EclipseME插件就是通<span style="font-family: 宋体">过这</span>种方式安装的。<br />
<br />
<br />
注释：</p>
<p>eclipse3.5与以前的目录结构不一样，它没有links目录,代替links目录的是dropins目录。</p>
<p>一、建立一个link文件里面用path=插件安装位置.</p>
<p>二、把link文件放到dropins中.</p>
<p>三、把插件里面的stie.xml文件删除掉.</p>
<p>重新启动eclipse即可.</p>
<p><br />
&nbsp;&nbsp;&nbsp; 参考文章：IBM中国《管理Eclipse环境》，《Managing plugins in eclipse》。 </span></span></p>
<img src ="http://www.blogjava.net/wealupa/aggbug/331408.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2010-09-08 16:19 <a href="http://www.blogjava.net/wealupa/archive/2010/09/08/331408.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>类图说明</title><link>http://www.blogjava.net/wealupa/archive/2010/07/27/327236.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Tue, 27 Jul 2010 08:54:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2010/07/27/327236.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/327236.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2010/07/27/327236.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/327236.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/327236.html</trackback:ping><description><![CDATA[<strong>关系</strong><br />
　　<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;常见的关系有：继承（Generalization），关联关系（Association），聚合关系（Aggregation），复合关系（Composition），依赖关系（Dependency）。&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;其中，聚合关系（Aggregation），复合关系（Composition）属于关联关系（Association）。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一般关系表现为继承或实现关系(is a)，关联关系表现为变量(has a )，依赖关系表现为函数中的参数(use a)。 
<img src ="http://www.blogjava.net/wealupa/aggbug/327236.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2010-07-27 16:54 <a href="http://www.blogjava.net/wealupa/archive/2010/07/27/327236.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>控制反转，依赖注入，好莱坞原则</title><link>http://www.blogjava.net/wealupa/archive/2010/07/19/326493.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Mon, 19 Jul 2010 03:21:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2010/07/19/326493.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/326493.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2010/07/19/326493.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/326493.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/326493.html</trackback:ping><description><![CDATA[<p>IoC 或者 DI 或者 &#8230;一大堆的缩写词 <br />
依赖注入和控制反转其实是同一回事，依赖注入最典型的应用就是控制反转</p>
<p>不管是面向对象，还是面向过程，都需要分成许多的块，然后由这些部件协同工作完成任务 <br />
要协同工作就会产生依赖，一个方法调用另一个方法，一个对象包含另一个对象 <br />
如果对象A包含对象B的话，就需要在A里new一个B <br />
依赖注入从具体类B里抽象出接口IB——IB的具体实现可能有很多B,B1,B2&#8230;很多种——这样A可以不用再new具体的B了，而是跟IoC容器说：我要一个IB（getBean("IB")）。然后，由容器根据配置文件来做具体的new的工作。具体new的是哪个，由配置文件从代码外部决定，要更换成B,B1,或是B2&#8230;修改配置文件就能做到，不用再改代码了</p>
<p>例：<br />
假设你编写了两个类，一个是人(Person)，一个是手机(Mobile)。 <br />
人有时候需要用手机打电话，需要用到手机的dialUp方法。 <br />
传统的写法是这样:</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #008000">//</span><span style="color: #008000">code</span><span style="color: #008000"><br />
<img id="Codehighlighter1_26_137_Open_Image" onclick="this.style.display='none'; Codehighlighter1_26_137_Open_Text.style.display='none'; Codehighlighter1_26_137_Closed_Image.style.display='inline'; Codehighlighter1_26_137_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_26_137_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_26_137_Closed_Text.style.display='none'; Codehighlighter1_26_137_Open_Image.style.display='inline'; Codehighlighter1_26_137_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif"  alt="" /></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Person</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_26_137_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_26_137_Open_Text"><span style="color: #000000">{&nbsp;<br />
<img id="Codehighlighter1_66_134_Open_Image" onclick="this.style.display='none'; Codehighlighter1_66_134_Open_Text.style.display='none'; Codehighlighter1_66_134_Closed_Image.style.display='inline'; Codehighlighter1_66_134_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_66_134_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_66_134_Closed_Text.style.display='none'; Codehighlighter1_66_134_Open_Image.style.display='inline'; Codehighlighter1_66_134_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">boolean</span><span style="color: #000000">&nbsp;makeCall(</span><span style="color: #0000ff">long</span><span style="color: #000000">&nbsp;number)</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_66_134_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_66_134_Open_Text"><span style="color: #000000">{&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Mobile&nbsp;mobile</span><span style="color: #000000">=</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Mobile();&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;mobile.dialUp(number);&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000">&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />}</span></span><span style="color: #000000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span></div>
也就是说，类Person的makeCall方法对Mobile类具有依赖，必须手动生成一个新的实例new Mobile()才可以进行之后的工作。 <br />
依赖注入的思想是这样，当一个类(Person)对另一个类(Mobile)有依赖时，不再该类(Person)内部对依赖的类(Moblile)进行实例化，而是之前配置一个beans.xml,告诉容器所依赖的类(Mobile)，在实例化该类(Person)时，容器自动注入一个所依赖的类(Mobile)的实例。 <br />
接口<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #008000">//</span><span style="color: #008000">code</span><span style="color: #008000"><br />
<img id="Codehighlighter1_39_79_Open_Image" onclick="this.style.display='none'; Codehighlighter1_39_79_Open_Text.style.display='none'; Codehighlighter1_39_79_Closed_Image.style.display='inline'; Codehighlighter1_39_79_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_39_79_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_39_79_Closed_Text.style.display='none'; Codehighlighter1_39_79_Open_Image.style.display='inline'; Codehighlighter1_39_79_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif"  alt="" /></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;Interface&nbsp;MobileInterface</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_39_79_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_39_79_Open_Text"><span style="color: #000000">{&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">boolean</span><span style="color: #000000">&nbsp;dialUp(</span><span style="color: #0000ff">long</span><span style="color: #000000">&nbsp;number);<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />}</span></span><span style="color: #000000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span></div>
<br />
Person类：<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #008000">//</span><span style="color: #008000">code</span><span style="color: #008000"><br />
<img id="Codehighlighter1_26_267_Open_Image" onclick="this.style.display='none'; Codehighlighter1_26_267_Open_Text.style.display='none'; Codehighlighter1_26_267_Closed_Image.style.display='inline'; Codehighlighter1_26_267_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_26_267_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_26_267_Closed_Text.style.display='none'; Codehighlighter1_26_267_Open_Image.style.display='inline'; Codehighlighter1_26_267_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif"  alt="" /></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;Person</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_26_267_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_26_267_Open_Text"><span style="color: #000000">{<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;MobileInterface&nbsp;mobileInterface;<br />
<img id="Codehighlighter1_107_156_Open_Image" onclick="this.style.display='none'; Codehighlighter1_107_156_Open_Text.style.display='none'; Codehighlighter1_107_156_Closed_Image.style.display='inline'; Codehighlighter1_107_156_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_107_156_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_107_156_Closed_Text.style.display='none'; Codehighlighter1_107_156_Open_Image.style.display='inline'; Codehighlighter1_107_156_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">boolean</span><span style="color: #000000">&nbsp;makeCall(</span><span style="color: #0000ff">long</span><span style="color: #000000">&nbsp;number)</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_107_156_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_107_156_Open_Text"><span style="color: #000000">{<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">this</span><span style="color: #000000">.mobileInterface.dialUp(number);<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img id="Codehighlighter1_222_265_Open_Image" onclick="this.style.display='none'; Codehighlighter1_222_265_Open_Text.style.display='none'; Codehighlighter1_222_265_Closed_Image.style.display='inline'; Codehighlighter1_222_265_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"  alt="" /><img style="display: none" id="Codehighlighter1_222_265_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_222_265_Closed_Text.style.display='none'; Codehighlighter1_222_265_Open_Image.style.display='inline'; Codehighlighter1_222_265_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;setMobileInterface(MobileInterface&nbsp;mobileInterface)</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_222_265_Closed_Text"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_222_265_Open_Text"><span style="color: #000000">{<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">this</span><span style="color: #000000">.mobileInterface</span><span style="color: #000000">=</span><span style="color: #000000">mobileInterface;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />}</span></span><span style="color: #000000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span></div>
<br />
在xml文件中配置依赖关系<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #000000">//code<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">bean&nbsp;</span><span style="color: #ff0000">class</span><span style="color: #0000ff">="Person"</span><span style="color: #ff0000">&nbsp;id</span><span style="color: #0000ff">="person"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">property&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="mobileInterface"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">ref&nbsp;</span><span style="color: #ff0000">local</span><span style="color: #0000ff">="mobileInterface"</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">ref</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">property</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">bean</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">&nbsp;<br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">&lt;</span><span style="color: #800000">bean&nbsp;</span><span style="color: #ff0000">class</span><span style="color: #0000ff">="Mobile"</span><span style="color: #ff0000">&nbsp;id</span><span style="color: #0000ff">="mobileInterface"</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">bean</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
<img align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif"  alt="" /></span></div>
这样，Person类在实现拨打电话的时候，并不知道Mobile类的存在，它只知道调用一个接口MobileInterface，而MobileInterface的具体实现是通过Mobile类完成，并在使用时由容器自动注入，这样大大降低了不同类间相互依赖的关系。<br />
<br />
<span style="font-family: 微软雅黑">什么叫控制反转呢？ <br style="font-family: " />
套用好莱坞的一句名言就是：你呆着别动，到时我会找你。 <br style="font-family: " />
什么意思呢？就好比一个皇帝和太监 <br style="font-family: " />
有一天皇帝想幸某个美女，于是跟太监说，今夜我要宠幸美女 <br style="font-family: " />
皇帝往往不会告诉太监，今晚几点会回宫，会回哪张龙床，他只会告诉太监他要哪位美女 <br style="font-family: " />
其它一切都交由太监去安排，到了晚上皇帝回宫时，自然会有美女出现在皇帝的龙床上 <br style="font-family: " />
这就是控制反转，而把美女送到皇帝的寝宫里面去就是注射 <br style="font-family: " />
太监就是是框架里面的注射控制器类BeanFactory，负责找到美女并送到龙床上去 <br style="font-family: " />
整个后宫可以看成是Spring框架，美女就是Spring控制下的JavaBean <br style="font-family: " />
而传统的模式就是一个饥渴男去找小姐出台 <br style="font-family: " />
找领班，帮助给介绍一个云云，于是领班就开始给他张罗 <br style="font-family: " />
介绍一个合适的给他，完事后，再把小姐还给领班，下次再来 <br style="font-family: " />
这个过程中，领班就是查询上下文Context，领班的一个职能就是给客户找到他们所要的小姐 <br style="font-family: " />
这就是lookup()方法，领班手中的小姐名录就是JNDI//Java Naming and Directory Interface <br style="font-family: " />
小姐就是EJB，饥渴男是客户端，青楼是EJB容器 <br style="font-family: " />
看到区别了么？饥渴男去找小姐出台很麻烦，不仅得找，用完后还得把小姐给还回去 <br style="font-family: " />
而皇帝爽翻了，什么都不用管，交给太监去处理，控制权转移到太监手中去了 <br style="font-family: " />
而不是皇帝，必要时候由太监给注射进去就可以了 <br style="font-family: " />
看到Spring的美妙了吧，Spring还提供了与多个主流框架的支持 <br style="font-family: " />
可以和其它开源框架集成&nbsp; </span>
<img src ="http://www.blogjava.net/wealupa/aggbug/326493.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2010-07-19 11:21 <a href="http://www.blogjava.net/wealupa/archive/2010/07/19/326493.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DOCTYPE, HTML和XHTML, Strict DTD和Transitional DTD, Quirks Mode和Standard Mode </title><link>http://www.blogjava.net/wealupa/archive/2009/12/10/305383.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 10 Dec 2009 02:49:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2009/12/10/305383.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/305383.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2009/12/10/305383.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/305383.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/305383.html</trackback:ping><description><![CDATA[<p>我们在HTML里面声明DOCTYPE一般会有以下几种：</p>
<p>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt; <br />
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt; <br />
&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"&gt;<br />
&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;</p>
<p>是的，这里有HTML和XHTML，也有Transitional和Strict之分。顾名思义，XHTML是指这个文档是按照XML的格式来书写的，而HTML则表示这个文档是按照HTML的格式来书写的。Transition则表示这个文档达到了Transitional.dtd或者loose.dtd的要求，Strict则表示这个文档达到了strict.dtd的要求。但事实上我们经常会存在以下的误解：<br />
(1) 我的文档是声明为XHTML的，则我的文档肯定完全按照XML的格式。<br />
(2) 我的文档是声明为Strict的，则我的文档肯定是按照Strict Mode的方式来Render的，反之，是以Quirks Mode的方式来Render的。</p>
<p>这两种理解都很直接，然而却是错误的，我们也经常会犯这种的错误。</p>
<p>首先，文档声明为XHTML和HTML，和文档的Parse(即浏览器对文档的分析)是没有直接关联的。事实上，浏览器如何Parse文档取决于服务器以什么格式来提供这个文档。通常情况下，有两种方式，"text/html"和"application/xhtml+xml"。只有以"application/html+xml"方式来提供的文档才能够被按照XML的方式来Parse。然而，因为浏览器的历史原因，并不是所有的浏览器都支持"application/xhtml+xml"格式的文档，IE7之前的版本(包括IE7)就不能够支持这种格式，如果IE7碰到这种格式的文档，它会提示用户另存为其它文件。考虑到IE使用的广泛性，目前绝大部分的文档都是以"text/html"的方式来提供的。以"text/html"方式来提供的文档是按照HTML的语义来Parse的，大家都知道HTML的容错性是非常强的，即使你的文档里面的TAG没有正确地关闭，这个HTML也能够被正确地显示出来。因此如果你的XHTML是以"text/html"的方式来提供的(绝大多数情况下都是)，那么你即使在DOCTYPE里面声明了XHTML，你的文档也不是以XML的格式来Parse的，因此也不能保证你的文档是严格按照XML的规范的。事实上，很多专家都建议如果你的文档不是以"application/xhtml+xml"的方式来提供的，那么你就应该声明为HTML。</p>
<p>其次，浏览器以什么样的方式来Render你的文档，并不以你声明的DTD来决定的。事实上，如果你声明了DOCTYPE和DTD，你的文档就是以Strict Mode(或者称为Standard Mode，很多浏览器还包括Almost Standard Mode的方式，这里不进行区分)方式来Render的。对于没有DOCTYPE的文档，才是以Quirks Mode方式来Render的。因此浏览器的Render模式和你声明的DTD并没有直接的关系。</p>
<p>最后，你声明为Strict.dtd还是Transitional.dtd，在目前的浏览器看来是没有什么区别的。Strict.dtd比Transitional.dtd或者loose.dtd要严格多了，很多元素在strict.dtd里面都不能使用。然而因为浏览器的兼容性，即使你在DOCTYPE里面声明了Strict.dtd，浏览器遇到strict.dtd里面不允许的元素，也还能够正确地显示你的文档。我猜测浏览器并没有将DTD考虑进去。例如iframe这个TAG在strict.dtd里面并不存在，但即使你的DOCTYPE里面声明了strict.dtd，然后使用了iframe这个TAG，浏览器(包括IE7，IE8，FF3.0，Safari 3.0)都能够正确地显示你的文档。浏览器并没有按照你声明的DTD来Parse你的文档。目前能够保证你的文档是符合strict.dtd还是Transitional.dtd的，只能通过一些网上的Validator，如W3C Validator来分析，浏览器并不能够给你很好的支持。当然，实际上如果你能够严格按照你声明的DTD来书写你的文档，那是最好的，这样保证了以后浏览器对DTD严格遵守的时候，你的文档不会产生错误。</p>
<p>因此，</p>
<p>(1) 如果你的文档是以"text/html"的方式来提供的，那么你就应该声明为HTML。假如你想要让IE7能够正确地显示，那么你就更应该这么做了。<br />
(2) 如果你的文档声明为XHTML，那么你应该以"application/html+xml"的方式来提供。<br />
(3) 尽量在你的文档前面声明DOCTYPE和DTD，这样能够保证你不是以Quirks Mode的方式来Render文档的。<br />
(4) 如果你声明了DTD，那么就要严格按照DTD的要求来书写你的文档。特别是如果你声明了Strict.dtd，那么你应该注意哪些元素是不能够使用的。</p>
<p>注意：本文发布于2008.5.20。随着时间的发展，浏览器对HTML和XHTML，Strict.dtd和Transitional.dtd的支持会更好。如果你的浏览器比IE7, IE8, FF 3.0和Safari 3.0要高很多很多的版本，那么你要注意本文的适用性。</p>
<img src ="http://www.blogjava.net/wealupa/aggbug/305383.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2009-12-10 10:49 <a href="http://www.blogjava.net/wealupa/archive/2009/12/10/305383.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>软件开发大概流程</title><link>http://www.blogjava.net/wealupa/archive/2009/04/29/268147.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Wed, 29 Apr 2009 07:39:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2009/04/29/268147.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/268147.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2009/04/29/268147.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/268147.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/268147.html</trackback:ping><description><![CDATA[<span style="font-family: 幼圆; font-size: 12pt"><strong>1 软件定义与软件计划</strong><br style="font-family: " />
1.1 软件定义与可行性研究<br style="font-family: " />
1.2 软件工程开发计划<br style="font-family: " />
<br style="font-family: " />
<strong>2 需求分析<br style="font-family: " />
</strong>2.1 定目标系统的具体要求以及逻辑模型<br style="font-family: " />
2.2 结构化分析步骤、分析和描述系统的逻辑模型<br style="font-family: " />
2.3 需求分析的复审<br style="font-family: " />
2.4 软件需求规格说明<br style="font-family: " />
<br style="font-family: " />
<strong>3 概要设计<br style="font-family: " />
</strong>3.1 软件结构设计<br style="font-family: " />
3.2 数据结构及数据库设计<br style="font-family: " />
3.3 系统接口设计<br style="font-family: " />
3.4 设计测试方案<br />
<br />
<strong>4 详细设计</strong><br />
4.1 用户界面设计<br />
4.2 软件过程设计<br />
<br />
<strong>个人感觉</strong>：用户界面设计在详细设计阶段有点晚，但是用户界面设计要在数据库设计之后进行，数据库设计不应该受页面的影响。<br />
</span>
<img src ="http://www.blogjava.net/wealupa/aggbug/268147.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2009-04-29 15:39 <a href="http://www.blogjava.net/wealupa/archive/2009/04/29/268147.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>概要设计与详细设计的区别(转)</title><link>http://www.blogjava.net/wealupa/archive/2009/04/27/267695.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Mon, 27 Apr 2009 03:07:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2009/04/27/267695.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/267695.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2009/04/27/267695.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/267695.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/267695.html</trackback:ping><description><![CDATA[<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><strong><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt; font-family: 楷体_GB2312">概要设计与详细设计的区别</span></span></span></strong></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp; 概要设计就是设计软件的结构，包括组成模块，模块的层次结构，模块的调用关系，每个模块的功能等等。同时，还要设计该项目的应用系统的总体数据结构和数据库结构，即应用系统要存储什么数据，这些数据是什么样的结构，它们之间有什么关系。&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;详细设计阶段就是为每个模块完成的功能进行具体的描述，要把功能描述转变为精确的、结构化的过程描述。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp; 概要设计阶段通常得到软件结构图 <br />
&nbsp;&nbsp;&nbsp; 详细设计阶段常用的描述方式有：流程图、N-S图、PAD图、伪代码等</span></span></span></span></span></p>
<p><br />
<span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><strong><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt; font-family: 楷体_GB2312">概要设计和详细设计</span></span></span></strong></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp; 在软件设计中，大家经常问到的一个问题是：概要设计应该怎样一个概要法，详细设计应该怎样一个详细法？ <br />
这个问题在公司内部经常有人问。现在陈述一下。 <br />
&nbsp;&nbsp;&nbsp; 我们公司的研发流程是瀑布型的，这个模型中的分析、设计阶段是基于经典的结构化方法。&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;结构化设计方法的基本思路是：按照问题域，将软件逐级细化，分解为不必再分解的的模块，每个模块完成一定的功能，为一个或多个父模块服务（即接受调用），也接受一个或多个子模块的服务（即调用子模块）。模块的概念，和编程语言中的子程序或函数是对应的。<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp; <span style="font-family: 楷体_GB2312"><strong>这样一来，设计可以明显地划分成两个阶段：</strong></span>&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp; 概要（结构）设计阶段：把软件按照一定的原则分解为模块层次，赋予每个模块一定的任务，并确定模块间调用关系和接口。 <br />
&nbsp;&nbsp;&nbsp; 详细设计阶段：依据概要设计阶段的分解，设计每个模块内的算法、流程等。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt"><strong>概要设计阶段：<br />
</strong>&nbsp;<br />
&nbsp;&nbsp;&nbsp; 在这个阶段，设计者会大致考虑并照顾模块的内部实现，但不过多纠缠于此。主要集中于划分模块、分配任务、定义调用关系。模块间的接口与传参在这个阶段要定得 十分细致明确，应编写严谨的数据字典，避免后续设计产生不解或误解。概要设计一般不是一次就能做到位，而是反复地进行结构调整。典型的调整是合并功能重复的模块，或者进一步分解出可以复用的模块。在概要设计阶段，应最大限度地提取可以重用的模块，建立合理的结构体系，节省后续环节的工作量。&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp; 概要设计文档最重要的部分是分层数据流图、结构图、数据字典以及相应的文字说明等。以概要设计文档为依据，各个模块的详细设计就可以并行展开了。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt"><strong>详细设计阶段:<br />
</strong><br />
&nbsp;&nbsp;&nbsp; 在这个阶段，各个模块可以分给不同的人去并行设计。在详细设计阶段，设计者的工作对象是一个模块，根据概要设计赋予的局部任务和对外接口，设计并表达出模块的算法、流程、状态转换等内容。这里要注意，如果发现有结构调整（如分解出子模块等）的必要，必须返回到概要设计阶段，将调整反应到概要设计文档中，而不 能就地解决，不打招呼。详细设计文档最重要的部分是模块的流程图、状态图、局部变量及相应的文字说明等。一个模块一篇详细设计文档。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp; 概要设计文档相当于机械设计中的装配图，而详细设计文档相当于机械设计中的零件图。文档的编排、装订方式也可以参考机械图纸的方法。 <br />
&nbsp;&nbsp;&nbsp; 我们公司对模块的认识和传统定义有所不同，认为是较大的软件功能单元才可以称作模块。这种认识使大家对概要设计和详细设计的分工产生了混乱的理解，降低了文档的可用性，应该予以纠正。 <br />
&nbsp;&nbsp;&nbsp; 概要设计中较顶层的部分便是所谓的方案。方案文档的作用是在宏观的角度上保持设计的合理性。<br />
<br />
&nbsp;&nbsp;&nbsp; 有的项目采用面向对象的分析、设计方法。可能在概要设计、详细设计的分工上疑问更多。其实，面向对象的分析、设计方法并没有强调结构化方法那样的阶段性，因此一般不引入概要、详细设计的概念。如果按照公司的文档体系，非要有这种分工的话，可以将包的划分、类及对象间的关系、类的对外属性、方法及协作设计看做 概要设计；类属性、方法的内部实现看做详细设计。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt; font-family: 楷体_GB2312">&nbsp;&nbsp;&nbsp;1.需求分析--产生软件功能规格说明书,需要确定用户对软件的需求,要作到明确、无歧义。不涉及具体实现方法。用户能看得明白，开发人员也可据此进行下面的工作（概要设计）。&nbsp;<br />
&nbsp;&nbsp; 2.概要设计--产生软件概要设计说明书，说明系统模块划分、选择的技术路线等，整体说明软件的实现思路。并且需要指出关键技术难点等。&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; 3.详细设计--产生软件详细设计说明书，对概要设计的进一步细化，一般由各部分的担当人员依据概要设计分别完成，然后在集成，是具体的实现细节。理论上要求可以照此编码。</span></span></span></span></span></p>
<p><br />
<span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt"><strong style="font-family: 楷体_GB2312">概要设计和详细设计的区别与联系</strong></span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp;软件设计采用自顶向下、逐次功能展开的设计方法，首先完成总体设计，然后完成各有机组成部分的设计。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp; 根据工作性质和内容的不同，软件设计分为概要设计和详细设计。概要设计实现软件的总体设计、模块划分、用户界面设计、数据库设计等等；详细设计则根据概要设计所做的模块划分，实现各模块的算法设计，实现用户界面设计、数据结构设计的细化，等等。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp; 概要设计是详细设计的基础，必须在详细设计之前完成，概要设计经复查确认后才可以开始详细设计。概要设计，必须完成概要设计文档，包括系统的总体设计文档、以及各个模块的概要设计文档。每个模块的设计文档都应该独立成册。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp; 详细设计必须遵循概要设计来进行。详细设计方案的更改，不得影响到概要设计方案；如果需要更改概要设计，必须经过项目经理的同意。详细设计，应该完成详细设计文档，主要是模块的详细设计方案说明。和概要设计一样，每个模块的详细设计文档都应该独立成册。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">&nbsp;&nbsp; 概要设计里面的数据库设计应该重点在描述数据关系上，说明数据的来龙去脉，在这里应该结合我们的一下结果数据，说明这些结果数据的源点，我们这样设计的目的和原因。详细设计里的数据库设计就应该是一份完善的数据结构文档，就是一个包括类型、命名、精度、字段说明、表说明等内容的数据字典。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">&nbsp;&nbsp; 概要设计里的功能应该是重点在功能描述，对需求的解释和整合，整体划分功能模块，并对各功能模块进行详细的图文描述，应该让读者大致了解系统作完后大体的结构和操作模式。详细设计则是重点在描述系统的实现方式，各模块详细说明实现功能所需的类及具体的方法函数，包括涉及到的sql语句等。</span></span></span></span></span></p>
<p></p>
<p><br />
<span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt"><strong style="font-family: 楷体_GB2312">概要设计，详细设计之间的关系是什么？</strong></span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">Q:<br />
我的看法：<br />
&nbsp;&nbsp;&nbsp; 概要设计只说明系统有多少个模块，各模块之间的接口和个模块本身的功能<br />
&nbsp;&nbsp;&nbsp; 详细设计说明某个具体模块如何实现，粒度应该比程序略高一些</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">&nbsp;&nbsp;&nbsp; 但是问题来了，各个模块之间是有层次关系的，也有先后逻辑关系。这就说明，在概要设计中，还必须考虑模块的实现细节，否则，你怎么知道这个模块下面要划分子模块？你怎么知道各子模块的调用顺序？<br />
&nbsp;&nbsp;&nbsp; 这就说明，概要设计和详细设计是重叠进行的，而软件工程书上说的确是顺序进行的，不知道是不是我的理解有问题。</span></span></span></span></span></p>
<p><br />
<span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">举个例子，例如排序程序，如果设计2个模块：<br />
一个主模块用于排序子模块用于交换2个变量，主模块调用子模块，但是子模块是怎么设计出来的呢？肯定是你先想到了用冒泡等排序方式的时候需要交换数据，这已经考虑了主模块足够多的细节，似乎属于"详细设计"了，但是目前进行的是概要设计，这就产生了我所说的重叠的情况。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">A:</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">看看上面的帖子，有意思的居多。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">上面也有朋友说到用建筑的例子来比喻。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">软件的概要设计，主要是建立软件系统的整体架构，也就是我们在盖房子时候，需要先将房子的整个架子构建起来。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">软件的详细设计，主要是将软件系统的各个部分的具体设计方法、逻辑、功能采用文字方式进行表述。这样在实现过程中，Coding人员原则上严格按此进行代码实现即可。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">这样的一个最为简单的例证：我们可以将代码交付第三方来做。验证与跟踪采取设计来。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">我看上面还有一个朋友说：快速做代码。这个本身没有值得批评之处。但只要想一下，你写的代码没有任何设计思想、文档留下的情况，一旦你离开，如何维护？重新设计吗？还是花费几倍人力去研究你写的几千/万，甚至几十万行代码？如果是这样的，你没错，关键是你们老板太对了，钱算什么。</span></span></span></span></span></p>
<p><span style="font-family: 楷体_GB2312"><span style="font-size: 14pt"><span style="font-family: 黑体"><span style="font-family: 新宋体"><span style="font-size: 12pt">另外的一个问题是：中国人如此聪明，但中国为什么没有出现巨型软件产品呢？个人英雄主义依然很严重，老板的短视利益行为大行其道。</span></span></span></span></span></p>
<img src ="http://www.blogjava.net/wealupa/aggbug/267695.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2009-04-27 11:07 <a href="http://www.blogjava.net/wealupa/archive/2009/04/27/267695.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>概要设计和详细设计的区别与联系</title><link>http://www.blogjava.net/wealupa/archive/2009/04/27/267692.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Mon, 27 Apr 2009 03:04:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2009/04/27/267692.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/267692.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2009/04/27/267692.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/267692.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/267692.html</trackback:ping><description><![CDATA[<p><span style="font-family: 隶书"><span style="font-family: 方正姚体"><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;软件设计采用自顶向下、逐次功能展开的设计方法，首先完成总体设计，然后完成各有机组成部分的设计。 </span></span></span></p>
<p class="a" style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial"><span style="font-family: 楷体_GB2312"><span style="font-family: 隶书"><span style="font-family: 方正姚体"><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp; 根据工作性质和内容的不同，软件设计分为概要设计和详细设计。概要设计实现软件的总体设计、模块划分、用户界面设计、数据库设计等等；详细设计则根据概要设计所做的模块划分，实现各模块的算法设计，实现用户界面设计、数据结构设计的细化，等等。<br />
<br />
&nbsp;&nbsp;&nbsp; </span></span></span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial"><span style="font-family: 楷体_GB2312"><span style="font-family: 隶书"><span style="font-family: 方正姚体"><span style="font-family: 宋体">概要设计是详细设计的基础，必须在详细设计之前完成，概要设计经复查确认后才可以开始详细设计。概要设计，必须完成概要设计文档，包括系统的总体设计文档、以及各个模块的概要设计文档。每个模块的设计文档都应该独立成册。<br />
<br />
&nbsp;&nbsp;&nbsp; </span></span></span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial"><span style="font-family: 楷体_GB2312"><span style="font-family: 隶书"><span style="font-family: 方正姚体"><span style="font-family: 宋体">详细设计必须遵循概要设计来进行。详细设计方案的更改，不得影响到概要设计方案；如果需要更改概要设计，必须经过项目经理的同意。详细设计，应该完成详细设计文档，主要是模块的详细设计方案说明。和概要设计一样，每个模块的详细设计文档都应该独立成册。<br />
<br />
&nbsp;&nbsp;&nbsp; </span></span></span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial"><span style="font-family: 楷体_GB2312"><span style="font-family: 隶书"><span style="font-family: 方正姚体"><span style="font-family: 宋体">概要设计里面的数据库设计应该重点在描述数据关系上，说明数据的来龙去脉，在这里应该结合我们的一下结果数据，说明这些结果数据的源点，我们这样设计的目的和原因。详细设计里的数据库设计就应该是一份完善的数据结构文档，就是一个包括类型、命名、精度、字段说明、表说明等内容的数据字典。<br />
<br />
&nbsp;&nbsp;&nbsp; </span></span></span></span></span><span style="font-family: 宋体; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial"><span style="font-family: 楷体_GB2312"><span style="font-family: 隶书"><span style="font-family: 方正姚体"><span style="font-family: 宋体">概要设计里的功能应该是重点在功能描述，对需求的解释和整合，整体划分功能模块，并对各功能模块进行详细的图文描述，应该让读者大致了解系统作完后大体的结构和操作模式。详细设计则是重点在描述系统的实现方式，各模块详细说明实现功能所需的类及具体的方法函数，包括涉及到的sql语句等。</span></span></span></span></span></p>
<p><span style="font-family: 宋体">&nbsp;</span></p>
<img src ="http://www.blogjava.net/wealupa/aggbug/267692.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2009-04-27 11:04 <a href="http://www.blogjava.net/wealupa/archive/2009/04/27/267692.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MyEclipse WebSphere 6.1 调试</title><link>http://www.blogjava.net/wealupa/archive/2008/05/05/198560.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Mon, 05 May 2008 12:54:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2008/05/05/198560.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/198560.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2008/05/05/198560.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/198560.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/198560.html</trackback:ping><description><![CDATA[<p>该文内容是由myeclipse官网上找的文档和自己在实践中总结的内容组成.</p>
<p>1. 下载下websphere6.1安装,在安装的过程中要记住自己设置的node name和cell name.</p>
<p>2.&nbsp;&nbsp; 启动eclipse,在window-&gt;preperences-&gt;myeclipse-&gt;application servers-&gt;websphere6.1</p>
<p dir="ltr" style="margin-right: 0px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 点Browse...选择你eclipse的安装目录.我是安装在D:\webshpere6.1,之后myeclipse会自动的将Profile Root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Directory,Node name,cell name设置好.你需要确认一下.Profile Root Directory就是你的安装目录下Profiles目录下的一个文件夹.我的是D:\webshpere6.0\profiles \AppSrv01.而node name和cell name它会设成以你的机器名命名的名字,应该将cell name改为Profiles RootDirectory下的installedApps目录(D:\webshpere6.0\profiles\AppSrv01 \installedApps)下的文件夹的名字我的是就是localhostNode01Cell,将node name改为cell name去掉后面的cell的名字.选中enable项.点Apple保存.</p>
<p dir="ltr" style="margin-right: 0px">3. 展开websphere6.1,选JDK,将JDK设置为webshpere6.1安装目录下的JDK(D:\webshpere6.0\java).<font color="#ff0000">一定要设置成IBM的JDK要不websphere是不能运行的.</font></p>
<p dir="ltr" style="margin-right: 0px">4. 启动websphere(不是用eclipse,而是用websphere的启动服务器),选管理控制台,点服务器-&gt;应用服务器,选一个服务,一 般为server1.在故障诊断中选记录和跟踪-&gt;JVM 日志,修改两个文件名为console.保存,注销,停止服务.</p>
<p dir="ltr" style="margin-right: 0px">5. 在eclipse中新建自己的<font color="#ff0000">企业工程(一定要是企业工程)</font>如果之前有web工程可以将该企业工程的web modle设置为该web project如没有就自己新建一个.</p>
<p dir="ltr" style="margin-right: 0px">6 发布企业工程(<font color="#ff0000">不是web project</font>)在第一次发布时要选<font color="#ff0000">Packaged Archive</font></p>
<p dir="ltr" style="margin-right: 0px">7. 用eclipse或websphere工具启动websphere,进入控制台,应用程序-&gt;安装新的应用程序,点浏览 在\webshpere6.0\profiles\AppServ01\installableApps下选自己发布的工程名的ear文件(你可能不是 AppServ01)然后next下去就可以了,唯一要注意的就是要设置web模块上下文根和要选上class 类文件和jsp的修改自动装载.</p>
<p dir="ltr" style="margin-right: 0px">8. 退到控制台首页,应用程序-&gt;企业应用程序,选择自己发布的工程,点启动.注销,停止websphere.</p>
<p dir="ltr" style="margin-right: 0px">9. 在eclipse中再点发布,删除刚发布的工程,再点add...选择企业工程,Exploded Archive.选Delete Remote...项.然后发布.以后就可以实时调试了.</p>
<img src ="http://www.blogjava.net/wealupa/aggbug/198560.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2008-05-05 20:54 <a href="http://www.blogjava.net/wealupa/archive/2008/05/05/198560.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>安装sql server vs 的顺序参考</title><link>http://www.blogjava.net/wealupa/archive/2008/04/25/195962.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Fri, 25 Apr 2008 06:33:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2008/04/25/195962.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/195962.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2008/04/25/195962.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/195962.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/195962.html</trackback:ping><description><![CDATA[我安装vs 2003, sql 200, vs 2005,sql 2005的顺序如下 <br />
1。安装sql 2005,安装过程好像去掉了IDE <br />
2。安装vs 2005,去掉sql 2005体验版本（好像是这么写的） <br />
3。安装vs2003 <br />
4。安装sql 2000(默认的一个主机名还是啥的得改，不然和sql 2005冲突) 
<img src ="http://www.blogjava.net/wealupa/aggbug/195962.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2008-04-25 14:33 <a href="http://www.blogjava.net/wealupa/archive/2008/04/25/195962.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Sql server 2005 版本</title><link>http://www.blogjava.net/wealupa/archive/2008/04/25/195808.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Fri, 25 Apr 2008 01:25:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2008/04/25/195808.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/195808.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2008/04/25/195808.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/195808.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/195808.html</trackback:ping><description><![CDATA[<p>SQL2005 分五个版本，如下所列，&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;1.Enterprise(企业版),&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;2.Development(开发版),&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;3.Workgroup,(工作群版)&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;4.Standard,(标准版)&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;5.Express.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;简单的比较一下 Enterprise, Development 和 Express 等三个版本:以功能言，Enterprise 版和 Development 版的功能一模一样。两者的差别，除了授权不同外，最主要的差别是:&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Enterprise版的数据库引擎只能安装在Win2003Server(或其他Server)。&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;如果你想安装在WindowsXP Pro系统上，你应该安装SQL2005Development版(开发版)。&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;什么是「数据库引擎」。数据库引擎是SQL2005的核心，是最主要的数据库管理功能模块。没有它，就不是数据库管理系统了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;因此，如果你是初学者，如果你只是想要在家里学习学习，如果你的环境是 WindowsXP Pro，那么，你应该选择的是 SQL2005Development(开发版)，而不是SQL2005Enterprise(企业版)或SQL2005Express(简易版)。<br />
</p>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;以在生产环境中使用所有版本的 SQL Server 2005，但 SQL Server 2005 Developer Edition 和 SQL Server 2005 Evaluation Edition 除外。以下段落介绍 SQL Server 2005 的多个版本。
<dl>
<dt><strong>SQL Server 2005 Enterprise Edition（32 位和 64 位）</strong>
<dd>
<p>Enterprise Edition 达到了支持超大型企业进行联机事务处理 (OLTP)、高度复杂的数据分析、数据仓库系统和网站所需的性能水平。Enterprise Edition 的全面商业智能和分析能力及其高可用性功能（如故障转移群集），使它可以处理大多数关键业务的企业工作负荷。Enterprise Edition 是最全面的 SQL Server 版本，是超大型企业的理想选择，能够满足最复杂的要求。</p>
</dd></dl>
<dl>
<dt><strong>SQL&nbsp;Server&nbsp;2005 Evaluation Edition（32 位和 64 位）</strong>
<dd>
<p>SQL Server 2005 还推出了适用于 32 位或 64 位平台的 180 天 Evaluation Edition。SQL Server Evaluation Edition 支持与 SQL Server 2005 Enterprise Edition 相同的功能集。可以根据生产需要升级 SQL Server Evaluation Edition。</p>
</dd></dl>
<dl>
<dt><strong>SQL Server 2005 Standard Edition（32 位和 64 位）</strong>
<dd>
<p>SQL Server 2005 Standard Edition 是适合中小型企业的数据管理和分析平台。它包括电子商务、数据仓库和业务流解决方案所需的基本功能。Standard Edition 的集成商业智能和高可用性功能可以为企业提供支持其运营所需的基本功能。SQL Server 2005 Standard Edition 是需要全面的数据管理和分析平台的中小型企业的理想选择。</p>
</dd></dl>
<dl>
<dt><strong>SQL Server 2005 Workgroup Edition（仅适用于 32 位）</strong>
<dd>
<p>对于那些需要在大小和用户数量上没有限制的数据库的小型企业，SQL Server 2005 Workgroup Edition 是理想的数据管理解决方案。SQL Server 2005 Workgroup Edition 可以用作前端 Web 服务器，也可以用于部门或分支机构的运营。它包括 SQL Server 产品系列的核心数据库功能，并且可以轻松地升级至 SQL Server 2005 Standard Edition 或 SQL Server 2005 Enterprise Edition。SQL Server 2005 Workgroup Edition 是理想的入门级数据库，具有可靠、功能强大且易于管理的特点。</p>
</dd></dl>
<dl>
<dt><strong>SQL Server 2005 Developer Edition（32 位和 64 位）</strong>
<dd>
<p>SQL Server 2005 Developer Edition 允许开发人员在 SQL Server 顶部生成任何类型的应用程序。该应用程序包括 SQL Server 2005 Enterprise Edition 的所有功能，但许可用作开发和测试系统，而不用作生产服务器。SQL Server 2005 Developer Edition 是独立软件供应商 (ISV)、咨询人员、系统集成商、解决方案供应商以及生成和测试应用程序的企业开发人员的理想选择。可以根据生产需要升级 SQL Server 2005 Developer Edition。</p>
</dd></dl>
<dl>
<dt><strong>SQL Server 2005 Express Edition（仅适用于 32 位）</strong>
<dd>
<p>SQL Server Express 数据库平台基于 Microsoft SQL Server 2005。它也可以替换 Microsoft Desktop Engine (MSDE)。通过与 Microsoft Visual Studio 2005 集成，SQL Server Express 简化了功能丰富、存储安全且部署快速的数据驱动应用程序的开发过程。</p>
<p>SQL Server Express 是免费的，可以再分发（受制于协议），还可以充当客户端数据库以及基本服务器数据库。SQL Server Express 是独立软件供应商 ISV、服务器用户、非专业开发人员、Web 应用程序开发人员、网站主机和创建客户端应用程序的编程爱好者的理想选择。如果需要更多的高级数据库功能，可将 SQL Server Express 无缝升级到更复杂的 SQL Server 版本。</p>
<p>SQL Server Express 还提供了一些附加组件，这些组件都作为具有高级服务的 Microsoft SQL Server 2005 Express Edition (SQL Server Express) 的一部分提供。除了 SQL Server Express 的功能外，具有高级服务的 SQL Server Express 还包括以下功能：</p>
<ul>
    <li>SQL Server Management Studio Express (SSMSE)，SQL Server Management Studio 的子集。<br />
    <li>支持全文目录。<br />
    <li>支持通过 Reporting Services 查看报表。<br />
    </li>
</ul>
</dd></dl>
<dl>
<dt><strong>SQL Server 2005 Mobile Edition（仅 32 位）</strong>
<dd>
<p>SQL Server Mobile 是简版数据库，将企业数据管理功能扩展到小型设备上。SQL Server Mobile 能够复制 Microsoft SQL Server 2005 和 Microsoft SQL Server 2000 的数据，并且允许用户维护与主数据库同步的移动数据存储。SQL Server Mobile 是唯一为智能设备提供关系数据库管理功能的 SQL Server 版本。</p>
</dd></dl>
<dl>
<dt><strong>SQL&nbsp;Server&nbsp;2005 Runtime Edition（32 位和 64 位）</strong>
<dd>
<p>SQL Server 2005 Runtime Edition 随 Microsoft ISV Royalty Program 提供。根据 SQL Server 2005 Runtime Edition 的最终用户许可协议，如果用户不使用 SQL Server 代码运行任何其他应用程序或者在任何其他上下文中使用 SQL Server 代码，独立软件供应商 (ISV) 可能将 SQL Server 代码嵌入到他们提供的解决方案中。关于 SQL Server Runtime Edition 的详细信息，请参阅 Microsoft 知识库中的文章<a onclick="javascript:Track('ctl00_LibFrame_ctl02|ctl00_LibFrame_ctl03',this);" href="http://support.microsoft.com/kb/917400">如何获取 SQL Server Runtime 许可证</a> (<a href="http://support.microsoft.com/kb/917400">http://support.microsoft.com/kb/917400</a>)。<br />
<br />
<strong><span style="color: red">注意点：</span></strong></p>
<dd>
<p>&nbsp;在XP上不能安装 Enterprise 版本，<br />
<br />
&nbsp;Express版本只能在本地访问，不能进行远程访问。<br />
<br />
&nbsp;Express版本连接时需要在连接字符串中写 ***\SQLExpress<br />
<br />
&nbsp;Developer版本可以进行远程访问，记住要启用TCP/IP连接，同时要设置好防火墙</p>
</dd></dl>
<img src ="http://www.blogjava.net/wealupa/aggbug/195808.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2008-04-25 09:25 <a href="http://www.blogjava.net/wealupa/archive/2008/04/25/195808.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>