123

Architect 201003-by-info q

Embed Size (px)

Citation preview

Page 1: Architect 201003-by-info q

 

 

Page 2: Architect 201003-by-info q

 

 

篇首语    Editor’s letter 

放慢你的脚步 

3 月的北京乍暖还寒,但万物复苏的迹象已势不可挡,君不见小草已展露出嫩绿的枝叶,湖

中的鸳鸯自由地戏水,年轻的朋友结伴出游,生机盎然的春天正向我们悄悄走来。 

作为软件行业的从业者,你是否每天都行色匆匆,“两耳不闻窗外事,一心只想写程序”呢?

在这个信息爆炸的时代,快餐文化似乎成为了社会的主旋律。人们快速地奔走在路上,熙熙

攘攘而来熙熙攘攘而去,不肯作稍稍停留,一个“忙”字几乎成了我们每个人的口头禅。忙

得只顾眼前、忙得天昏地暗、忙得颠倒了白昼、忙得失去了生活...... 

当加班已经成为了习惯,当为了工作而丧失了生活时,朋友,你是否想过这是你想要的么?

费心劳神地去寻找风景,孰不知你就在风景之中?忙忙碌碌地在找寻幸福,岂不知幸福就是

一种感受? 

人生犹如一次漫长的旅行,走的累了,不妨放慢一下你的脚步,换一种心情,休息一下,放

松一下。要知道,追求的意义就在于追求的本身;成功的快乐就隐藏在成功的过程中啊! 

朋友,请放慢你的脚步吧,每天上下班多走一段路,观察一下沿途的风景,体会一下静谧的

心灵,你会发现生活原来还有这么多的乐趣,不需要我们付出多少努力就能获得的乐趣,一

种来自于内心深处的乐趣。 

本期主编:张龙

Page 4: Architect 201003-by-info q

 

 

目      录 

[篇首语] 

放慢你的脚步 .................................................................................................................................. I 

[人物专访] 

IAN ROBINSON和JIM WEBBER谈论基于WEB的整合 ........................................................ 1 

[热点新闻] 

ECLIPSE VIRGO项目获得批准 .................................................................................................13

APACHE BEEHIVE正式退役,迁移到APACHE ATTIC上 ..................................................15

CHROME 4 现已支持HTML 5 WEB SQL DATABASE API .................................................17

FLEX开发者需要知道的 10 件事 ............................................................................................19

CWE/SANS发布 2010 年 25 个最危险的编程错误............................................................22

GOOGLE将不再支持老式浏览器 .............................................................................................24

SOA设计关乎契约还是服务实现?.........................................................................................26

CHROME中 5 大安全增强.........................................................................................................28

AMAZON EC2 因订购过多而导致内部网络延迟?.............................................................31

全景透视ORACLE对SUN的未来规划......................................................................................34

MONOTOUCH已支持APPLE IPAD..........................................................................................40 

[推荐文章] 

类加载器特技:OSGI代码生成 ................................................................................................42

模块化JAVA:声明式模块化.....................................................................................................55

ii 

 

Page 5: Architect 201003-by-info q

 

iii 

 

加密因特网....................................................................................................................................64

SOA访谈和书摘:EBEN HEWITT的新书《JAVA SOA COOKBOOK》...........................77

微型ORM——用VB和C#编写的动态类型ORM,只有 160 行 .......................................83 

[新品推荐] 

NEO4J:基于JAVA的NOSQL图形数据库 ...............................................................................95

GOOGLE发布.NET版YOUTUBE SDK......................................................................................95

RAILS 3 首个BETA版发布.........................................................................................................95

.NET 4 的新特性:图表、SEO及可扩展的输出缓存..........................................................96

IRONJS——面向DLR新的JAVASCRIPT编译器 ...................................................................96

IRONPYTHON与IRONRUBY新RC版发布 .............................................................................96

JAVA EE 6:EJB 3.1 的变化引人注目 .....................................................................................97

SPRING.NET 1.3:VS.NET SOLUTION TEMPLATES、MSTEST支持及SPRING INTEGRATION.NET....................................................................................................................97 

[架构师年度展望] 

2010 年大规模技术架构的思路 ..............................................................................................98

豆瓣首席架构师洪强宁的年度展望 ..................................................................................... 101

凡客诚品架构总监栾义来的年度展望................................................................................. 103

淘宝架构师岳旭强的年度展望.............................................................................................. 105

一个技术观察者的年度展望 .................................................................................................. 108 

[封面植物]

蝴蝶果 ......................................................................................................................................... 111

Page 6: Architect 201003-by-info q

全球发布会

2010年4月12日,Microsoft Visual Studio 2010发布盛典将于北京盛大举行,

2010年全球开发界这一盛事,将令中国开发同仁有幸全球率先领略Visual

Studio 2010全新特性。届时,微软全球资深副总裁张亚勤博士等多位微软高层,

以及来自微软总部的多位研发团队核心成员,将亲临发布会现场,共同

解密微软新一代开发平台的革新之处,实现更完美的Coding梦想。

支持Windows Azure,为微软云计算架构矗立重要里程碑

支持最新C++标准,增强IDE,切实提高程序员开发效率

实践当前最热门的Agile/Scrum开发方法,令团队竞争力

更强,升级的软件测试功能及工具,为软件质量严格把关

搭配Win7与Silverlight4,发挥多核并行运算威力,实现

前端用户界面设计,创建美感与效能并重的新一代软件

北京站 2010.4.12

立即注册上海站 2010.4.14

广州站 2010.4.16

MicroSoft Visual Studio 2010

Page 7: Architect 201003-by-info q

 

 

人物专访    Interview

Ian Robinson和Jim Webber谈论基

于Web的整合 

本采访是在伦敦举行的 QCon2009 上记录的,Ian Robinson 和 Jim Webber 探讨了如何将 Web

作为整合平台以及 REST 在理论上和实践中的好处。 

Ian Robinson 是 ThoughtWorks 的首席咨询师,他的专业领域是设计与交付

面向服务的分布式系统。 

Jim Webber 博士 ThoughtWorks 的全球架构主席,他与客户一起交付可靠的

面向服务的系统。Ian 和 Jim 目前正在合作创作一本关于 Web 友好的企业集成方面的书。 

InfoQ:欢迎大家参加伦敦的 QCon2009,本场是对 Ian Robinson 和 Jim Webber 的采访。根

据惯例,我们首先请二位作一个简单的自我介绍,Jim,你先来好吗? 

JW:我是 Jim Webber,在 ThoughtWorks 英国分部工作,目前,我正在和我的这位朋友 Ian

一起合写一本超级棒的关于使用 Web 进行整合方面的书。 

IR:我叫 Ian Robinson,我也在 ThoughtWorks 工作,是一名开发人员。  我从事分布式互联

系统相关的工作。我也正和 Jim 一起合写一本书。希望我们说的是同一本书! 

JW:嘿,你为什么不为大家多介绍一点那本非常棒的书呢? 

InfoQ:谈到你们提起的这本书,其书名是“基于 Web 的整合”。它和 REST 是一码事吗?能

否简单介绍一下这个书名的含义吗?给我们来个电梯演说? 

JW:当然,REST 是 REST 狂热者的国度里最高祭司的象征,然而,不幸的是,我们还没有被

这一教会所吸纳。我们使用“Web”的原因是它更具包容性,它包含了所有在广义的因特网

上已被使用的技术。其中的一些可能不如 REST 那么让人愉悦、欢喜、那么好的性能、伸缩

性或者合理性,但是这种特定的架构风格却非常有效  。我们更广泛地搜罗了网络中使用的

Page 8: Architect 201003-by-info q

 

有趣技术。 

IR:我认为我们俩都不属于所谓的那种 REST 当权派(restauranteur 本意餐馆老板),某些人看

到 Jim 站起来情绪激昂也许会作此感想,但是我们的方法更广泛。我们所做的工作是在月复

一月的工作中寻找那些实用的解决问题的方法。 

InfoQ:我记得在几年前,当你提到 REST 的时,当时你很看起来的确有些怪异,人们不知道

你在说什么,而在今天这明显变了。至少人们这些天谈论了很多,这些场次很收欢迎,大会

进程排得也很密集。你认为目前人们在项目实施中采用 REST 的状态是怎样的呢?人们真用

它了吗? 

IR:是的,我们使用它。我们用的很多;或者我们所使用的基于 Web 的方法中有一些方法

比其它方法更加 RESTful。REST 不一定要用在我们的所有工作中,相反,我们在一些客户项

目中引入了一些轻量级的使用 Web 的方法,并且久而久之,就形成了我们的——某种类型

的 RESTful 栈,在一开始把事物拆分成资源(resource)并对它们进行定位,然后进行连接,

进而通过超媒体来驱动应用程序。的确,我们在许多领域看到了 REST 的采用。 

JW:同意。我认为这是命运的大逆转(不知你们是否喜欢这个说法),从若干年前,那时 REST

几乎在任何严格传统的企业都会被嘲讽,而且即使是现在,客户将 Web 方式当做缺省的情

况也并不乐观。事实上,我现在的客户,如果我们没有通过一些经验性实验而且找到了同样

非常适合解决它们的问题的更为简单的 Web 方法时,它们就会认为大规模高性能系统就应

该部署在传统的企业中间件上。有了那些实验数据,就对你有一些启发——诸如你会发现

原来 web 方法在一个场景中能够用的很好,然后另一个场景,并且它会当你谈论分布式系

统整合式它就能够成为你的缺省选择。 

InfoQ:这些就是 RESTful 化或者 REST 采用的不同程度吗(如果你也这么称呼它们的话)?

当你向一个公司引进REST或基于Web的整合时也用这个方法吗?你的方法是不是从一点点

REST 的东西开始,然后越来越多逐步扩展? 

JW:当然,我认为 Lenard Richardson 有一个非常很棒的尺度,一张 RESTfulness 级别的表格,

用分贝或 ROY,或其他我不知道的方式进行区分。Leonard 把这张图标分成四个级别,从 0

级到 3 级,0 级是最基础的转型,3 级就是超媒体了,这也是我心中的理想模型。我并不愿

意和人们分析这个模型,因为人们期望运用的技术是固定在“REST 内部的”那些锲而不舍

的人所做的工作。所以,在我设计和构建系统时,我会思考目标的适应性,而且我经常发现

满足目标的东西往往出现在 Leonard 的那张图标的低端。它们对 web 感兴趣,却不一定对以

超媒体为中心的服务感兴趣。 

 

Page 9: Architect 201003-by-info q

 

IR:我认为 Leonard 的模型实际上在我们与客户讨论 REST 时非常有用,因为客户会这样开

始“解决任何问题,最简单的方式就是将它分解成一个个小问题。”  那我们做什么呢?—

—我们仅仅标识出资源并为其定位。因此,咋一听,他并非在谈论 RESTful 的东西,而是在

谈论如何分解问题。继而他会说“如果我们要一次又一次地做相同的事情,那么我们就应该

遵循统一的方式”——这就是他的第二个级别,仅仅使用了统一模型。 

再然后,他第三次说的是“如果我们要做一些有意思或特别的事,那么就要以特别的方式来

做”——这里才是与他谈论多媒体的时机。事实上,你可以跟客户,或其他人,只探讨那

些将问题分解成块,相同的事情若要不断重复做则遵循相同的方式来做,然后必要时特殊对

待。我认为这种交谈方式很好,进一步,还可以谈论一些特别的事物,如 REST 或使用 Web,

这样的交流方式很有效。 

InfoQ:你是否认为有些在人们看来是对 HTTP 的滥用的事情也是通往这个方向(采用 REST

和 Web)的正确步伐呢?这些事情是你必须要做的,还是可以避免?你是否在某些情况下

只能通过 GET 进行函数调用来改变事物,或者你根本无法辩护你的做法? 

JW:在我里面有个愤怒的家伙,他往往藏得不太深,此刻它想跳出来撕碎你的脑袋,并坚

信你的这些想法是多么地可恶。然而,在现实世界中,我们发现有些技术,如转换动词和

URI,它们被使用在某些特定的上下文中,而有时的上下文并不那么的固定,这就比较危险。

当然,在特定的上下文中,那些技术能帮助我快速把解决方案推向市场,我还是乐意使用的。 

我承认这是一种粘合的聚类方法,而且我们常常回到过去并纠正错误。但是我认为,找到那

种我喜欢称之“牛犇架构”的架构并设计出世界上最杰出的 RESTful 超媒体也许不是我们立

刻就能做出来的。也许我们可以采用一些别扭的一点的步骤,比如转换(tunneling),从而

让我们今天转起来,然后随着系统的慢慢扩展,随着需求的不段精细,随着它面对更多的系

统,随着它受到更多的关注,我们就可以考虑(把现有的做法)移植到更符合 RESTFul 的模

式,而新的模式是明确地符合那一类系统的。 

IR:我们的确要探索大规模的基础设施。现在的事情能够成功的原因是因为 Web 已经在那

儿了,而我们还需要开始接受 Web 的一些限制,一些随着 Web 的发展而带来的更多的限制。

那些限制现在就存在,比如浏览器几乎只接受两种动词,GET 和 POST,还有,我们的解决

方案常常不得不遵循哪些限制,而不论我们是否喜欢这种转换的方式。 

JW:这适用于一些媒介——REST 架构被膜拜,好像 Web 是一个完美的乌托邦,在这里所有

事物都理解 HTTP 的统一接口的全部延展,而事实上并非如此。在 Web 上仅有少数几个演员,

他们还不能理解某些动词,尽管 HTTP 认为他们真应该理解。这就是我们要考虑的限制,比

 

Page 10: Architect 201003-by-info q

 

如 Mark Nottingham 很喜欢跟我们讲的缓存成熟度曲线。 

那些限制对我们来说的确是个挑战,因为 Web 的行为并不符合 REST 中所描述的它应该表现

的行为,所以我们不得不采取某些实用的剪裁才能使系统运作起来。REST 是有价值,而让

系统转起来更有价值。 

InfoQ:事实上,我想 Roy Fielding 一定会非常赞同你的观点——HTTP 和现在的 Web 并不是

REST 的最佳实现——他一直都是这么说的。 

JW:很好,不然他的粉丝们会揍扁我的。   

IR:不过,它还是很不错的。我们有一套自己方法。 

InfoQ:直到现在我才注意到我们一直在讲 REST,却没想有对它作出解释。所以,也许有些

人还不知道我们到底在谈论什么,你能否花一分钟的时间解释一下 REST? 

IR:它是“在 Web 上选择自己的路径去探索有趣的业务流程”。我们希望实现某些目标,让

一些不同的事物协作起来,我们通过 HTML 或 XML 为客户和消费者提供服务,对于确定的

一组目标“我想完成这个或那个”,它可以从选择一条通往服务器的路径开始,然后在服务

器返回的表现中找到新的链接,就这样一步一步通往目标。 

JW:这种说法的确很妙,我都想照搬它了,然而我还是要修改一下以让它看起来像是我的

想法。可以这么说,服务器丢下一些面包屑给客户端并让他们跟上。它指引客户端沿着服务

端实现的业务流程前进。我们倾向于使用一致的接口和 HTTP 的方式陷入这个沼泽,而所有

的东西及其核心就是,服务端绅士般地牵着你的手带领你通过业务流程。 

InfoQ:你提到过有一些缺失,它们成了该基础设施的问题,比如浏览器在 GET 和 POST 方

面的限制,然后是缓存、媒介和其他某些事物会忽视或阻塞某些方法。你认为目前在 Web

范围内还有其他缺失的东西吗?为有效使用它,是否有些东西是我们必须要有的呢?如果

有,那会是什么呢? 

JW:尽管 Web 本身是非常成熟的技术,目前最主要的问题依然是经验的缺失。我认为目前

我们仅仅在学习如何驾驭它的某些特征然后进行系统整合。Web 已经成为连接人与人的一

种闪耀的机制,特别是在近几年,人们被带到网络中,通过 pokes 和 tweet 或其他类似的东

西进行交互。 

作为分布式系统工程师,我们仍缺乏某些在计算机之间协同完成工作的经验。例如,我们还

没有找到如何在系统之间扩展超媒体的有效方法。就我而言,我认为这是我心中最关键的缺

失。我很高兴周围有很多基础设施的怪癖和来自社区的不同声音,但是我想我们的确需要做

 

Page 11: Architect 201003-by-info q

 

一些实验并学会如何让它转起来。 

IR:即便在客户端库中,也可以用一种相对通用和标准的方式访问超媒体。我正在想的问题

是,我得到的返回是一个表象,可是我想要的是一个链接查询,它可以让我找到所有的超媒

体,然后此刻我想访问哪个超媒体,我就可以为哪些关联该超媒体的 URL 进行解引用

(dereference)。 

InfoQ:哪些场合适合使用 REST 和 Web,而哪些地方又应该避免使用它们呢? 

IR:只要你希望你的应用是真正可达的,那么就应该优先选择 REST 和 Web 的方式。对于任

何要访问你的应用或与你的应用协同工作的人来说,它们的门槛相对比较低。然而,如果我

们仅需在企业边界内运转的话,姑且不管这是不是一个好主意,那么我们就可以自由发挥了。

如果我们永远不需要向任何人解释我们在做什么,我们甚至可以从头到尾发明一些新东西,

但是当我们希望跨越任何组织边界的时候,我们就应该寻找一些足够精致的方式工作和协

作,而不是只要能完成工作的最低要求即可。 

JW:说得更远一点,当你考虑使用某种技术的时候,应该看看他们所表现出来的代价和优

势。对于 Web,我最喜欢提的问题是:“你愿意牺牲延迟并换来扩展性吗?”。Web 的延迟

不低,但是它提供了非常好的扩展性,特别是网络提供的协同工作。如果你能承受几秒、几

分、或者可能是几小时,几周的延迟,那么 Web 的扩展性就非常棒了。 

但是,如果你不能承受高延迟,那么再考虑 Web 的方案可能就是一个错误的选择。这时上

帝会敲敲我的脑袋说,或许一些毫秒级或更少延迟的私有协议是你需要的方案。然而,我常

常发现某些技术总是强调他们需要毫秒级的传输延迟,而往往没有真正根本上理解它们所面

对的业务问题,而业务问题的要求可能是更为合理的几秒,在这种情况下 Web 就可能成为

这合理的解决问题的低成本的方式。 

像我们这样的电脑迷们承受着虚荣的极大折磨,因为我们总要求最酷、最快、最低延时、最

优的系统节点,而 Web 却不关心这些。Web 是“单调乏对味的前进能咋样就咋样”。如果不

论何时都需要用延迟换取扩展性,或者说是扩展与高延迟并存,那就应该使用 Web。 

IR:我觉得这也是分布式系统开发的一个常见问题。它要求我们对延迟和不一致性多一点耐

心。几个世纪以来,人们一直在致力于协调这些问题。假设我从一个城市策马奔向另一个城

市,这个中间过程中就可能会发生不测。人们已经发明了能够处理这些问题的业务协议,而

且,我认为这些工作推动了我们去关注它们并帮助这些协议语义再次浮出水面,而并非总是

想着依赖于那些低延迟的技术并用它们来做所有的工作。 

 

 

Page 12: Architect 201003-by-info q

 

JW:这相当有趣,因为作为分布式平台的 Web,它所强调的一定是分布式。从这么多年的

计算机科学的发展来看,我们得到的教训是抽象是个极好的事物,而且,我们应该把所有艰

难的计算科学的东西交由科学家们去处理,而在活跃快活的业务网站中忘却这些痛苦。实际

上,你再也不会像多年前 Waldo 告诉我们的那样可怜地被计算社区所轻视,相反,如果你

决定使用基于 Web 的分布式系统,Web 不会向你隐瞒分布式,而是给你一些有用的信息去

协调分布式交互,再举个例子来说吧,用信马(messenger‐horse)打个比方,当你的马在高

速公路上被某个警察抓住时,你可以采取合适的行动去挽回。作为过去的事务追求者,我看

到的 Web 是一个庞大的协作平台——两阶段同意的事务会让人发疯。 

IR:刚从你不能上帝的眼睛去观察自己的成功的失落中缓过来了吧。 

JW:离 Tim 大师远一点……他可以随时看到整个 Web。我不是开玩笑哦,你发一篇博客,他

是知道的,他正看这你呢,他正通过一个网络摄像机监视着你呢。 

InfoQ:正好你提到事务,我听到关于 REST 的最多的批评之一就是它缺少很多企业级的特征。

使用 Web 服务时,你能使用一些事务相关的协议,提供原子性事务的 WS‐Coordination 以及

WS‐Business Activity 等等。你认为这是一种缺陷吗?我们使用基于 HTTP 的 REST 时需要一事

务相关的协议吗? 

JW:不,下一个问题吧,我不赞同这种说法。我认为我们正在学习 Web 提供的处理事务的

方式,经典的两阶段事务实际上并不适用。任何听过 Gregor Hohpe 谈论最终一致性(eventual 

consistency)、读过 Gregor Hohpe 写的关于 Starbucks 为何不使用两阶段提交的文字、任何真

正对这个问题有过即使是转瞬即逝的思考的人都会理解两阶段事务无法用在 Web 上。你是

在用一致性换取扩展性,而 Web 着眼与扩展性,潜在地支持最终一致性的技术。 

我不是公然宣传我的书,其实在这本书的第 12 章有相关的讨论。实际上,现在我们已经煎

熬地完成到第 11 章了,我们努力雕刻那些章节以至于可以跟上 Stefan 多产的步伐,他正在

写一本等同的德语版的书。我们实际上很煎熬,如果你们愿意听,我们为了安全、事务、消

息可靠性等方面使用了 WS‐*的技术。  我们在简单古老的 Web 的 HTTP 世界里展示了等价的

模式和策略。我们并不宣称我们的方法是 RESTFul 的,拿事务打比方,我们只说你并不真正

需要它,因为 Web 会给无时无刻不在为你提供这种协作。 

作为一种同步的逐步推进式基于文本的协议,Web 不应该立足于全局范围的[事务],这似乎

有悖常理,然而这是事实,因为在每此关于某个 Web 上资源的交互,我会得到一些元数据,

它告诉我这次交互是否成功。因此,我可能选择继续冒险的路径——如果我愿意的话——

这样我会继续访问后续的资源并往前走,或者因为该元数据传递给我的信息是我正在进行的

 

Page 13: Architect 201003-by-info q

 

事情可能失败,我也可能通过一组已链接的资源走后其他流程走向另一条路径,这就是另一

种前进方式。对我来说,这才是处理意外输出的更合理的解决方式,尽量把所有的事情包装

在 Web 的更大的事务中。 

IR:“你面对的是一个拿着斧头的侏儒,你会怎么用他?”  我的意思是,即使有 WS‐*协议,

我也不认为我们在任何情况下都要把它用在有许多服务参与的事务语义之间的协作。虽然我

们跨越 Web 以 RESTFul 的方式把服务的内部实现暴露出来,但是也许你真正要用的却是在粗

粒度的边界背后的内部实现,它们可能依赖于一些更底层的协议。我认为这没有错。如果我

们已经准备好承受锁住许多资源的代价,我们正在寻求一种粗粒度的边界,而事实上在这个

层次上我们不一  定需要它。 

JW:那也是有代价的,对吧?这一定需要更灵活的设计才能保证正确,因为在最底层,如

果你正在使用的是一种遗留的关系型数据库,你就要必须考虑这  些事情——是的,我这么

说过而且也一直这么做的——但是你一定要明确地设计出来,而且要小心对待那些容易被

无意中忽略的细节的抽象边界。如果你的失误走漏到 Web 中,你就搞砸了。 

IR:一旦你把后门钥匙给了某人,他将来就会从后门进入你的房间。 

InfoQ:现在我们已经讨论了事务,那么你觉得在 REST 中加入类似 BPM/BPEL 的东西怎样呢?

你认为我们需要这样的东西吗? 

JW:Web 的链接不是已经提供了这样的功能了吗?:) Web 有这样的免费的编排功能。 

InfoQ:是吗?我不好确定。这是个真诚的问题,我指的是引擎……姑且不管它是使用哪种语

言编写的,但那些引擎可以处理这样的事情,它们可以将不同的请求搭配到不同系统中,而

响应是异步返回的,它们又将这些响应搭配回原请求并做其他工作。这听起来是个很有价值

的功能,难道 RESTFul 的世界不需要类似的能力吗? 

JW:的确很有价值。从得知特定的输入得到什么输出这个角度来看,使用某些规则来实现

也是很好的。而只有把它捆在让人恼火的 BPM 语言一起使用时,才会让我不爽,原因是在

使用时有很多负担。我们看到过很多可以通过点选方式建模的 BPM 产品,而使用他们时我

们往往发狂,这是因为用它们很危险。  使用 Web 时最困难的事情就是让客户端协作起来。

如果我们可以解决该问题,那么 Web 将是更容易驾驭的方案,但是我完全同意我们需要客

户端协作,可我并不认为一定要我们今天所看到相同的产品线和解决方案。而类似于 Prolog

或规则引擎,也许是实际上处理和编排 Web 上的处理的更好的方式。 

IR:这是一个客户端或服务端的内部实现的问题,不管他们在交互中扮演的是什么角色。按

你的说法,为了实现一个目标可能需要一步接着一步最后达到目标,这也是无可厚非的。而

 

Page 14: Architect 201003-by-info q

 

如果服务端返回给你的是一个表象,它为你提供了一组选择,你可以应用某些智能的方法去

选择你的路径,这也反映了一种带外(out of band  )机制,这样我们也能像你所预期的那

样交互。它提供某种标准的合理的食物的解释方式,如“rel”属性等。 

JW:这种带外只能可以是一种微格式(Microformat),而且可能应该是,因为他们轻便而生

动。 

IR:是的,但是很多流程都是很简单的,顺序的,或者由事件驱动的。用最简单的方式去实

现它们相对比较简单,而且没有必要非要依赖于规则引擎或某些工作流引擎等工具。 

InfoQ:让我们谈一些切实的东西吧,我们已经谈了很多理论方面的好处,所以现在我们谈

谈实际的。对于那些接受了 REST 的人们,他们想搞点 RESTful 的东西,你推荐哪些工具?

从我们已有的不同的技术领域,你在构建 HTTP 上的 RESTful 系统时最喜欢用什么工具? 

JW:我承认我最喜欢的都是简单的工具。目前我正在做的是一些非常高性能的系统,用的

是 Java,它挺好。当然,即便是 Java,我们也有很多选择,  我们可以选择 Restlet,也可以

选择 JAX‐RS 服务端实现,二者都是非常完善的框架,提供了很多的工具。在这种情况下,

我们使用 servlet,因为他们已经足够我们以一种轻便的方式完成工作。相反,比方说如果你

在使用.NET 平台,那你就能用 WCF 中的 WebInvoke 和 WebGet 等工具,或者你也可以仅仅

使用 HTTP 句柄(handler)。 

IR:或者也可以是 HTTP 监听器,实际上在自托管的 HTTP 中 WCF 使用的就是它。你也可以

使用它,而且,在其之上写程序相当简单。 

JW:更狡猾的回答是你自己做主。如果你喜欢使用高度抽象的框架,如 WCF 或这 JAX‐RS,

如果与驾驭像 servlet 这样极度以 HTTP 请求/响应为中心的事物相比,你觉得把这些框架放

在你的应用域中你感到更轻松,那你就这么用。用你认为最舒服的工具就好! 

IR:我一直不断探索的一件事情是,如何在应用协议的周边进行交互,我喜欢用测试的方式

来做。测试是很有用的一种文档方式。我想通过应用协议向你描述你可以通过什么方法让我

的服务作出反应。比如,如果你想这个端点提交这个表象,调用这个方法,你就可能获得这

中表象的返回,这种媒体类型,这些状态码  ,这个 HTTP 头。所有这些只是应用协议的一

部分,我们是在与自己建立某些微不足道的合约。比如,你可以在 AtomPub 规范中看到很

多这类的东西。   

我喜欢做的事情是把所有的断言都放在一个测试中。我常常在探索,能否不需要每次都开启

一个服务实例,或者不需要通过线上的交互,就能完成测试。因此我常常在寻找一种非常轻

量级的抽象,这样我就可以在不需要启动服务的实例就能为所有的 HTTP 构件创建测试预期。

 

Page 15: Architect 201003-by-info q

 

我记得你曾用 Spring 中的模拟上下文(mock context)干过这事。 

JW:通过 sevlet 和一些 Spring 的模拟的确是一个很好的方式,你不需要等待 20 个小时等待

Tomcat 完全把服务启动,的确很轻便,很实用。 

IR:而我偶尔做的是创建一层很轻薄的封皮(  wrappers  )把请求和响应封装起来。我能使

用它们独立地代理任何我使用的运行时,然后,我基本就可以写一些测试程序去测试它们,

或者模拟那些请求和响应的实例。 

InfoQ:你们提到了“契约”这个词。你们怎么看待 REST 相关的契约?因为在 Web 服务的

世界里,契约的确是所有事物的核心。据我所知,Jim 是那些极棒的 WSDL  描述文件的狂热

粉丝之一,它真正非常正式,非常完全地描述了服务所暴露的方法。你们根据什么去和一个

没有正式描述的服务进行交互呢?没有 WSDL 文件,你们是第怎么工作的呢? 

JW:你可以有一个非正式的描述,然后就会有一大批 Ian 的绝妙的客户驱动的契约。 

IR:我常常认为媒体类型(media type)表达了一些契约信息,从它身上你可以得知将返回

给你的是那种表象。更加有趣的媒体类型实际上也包含了很多那些与协议相关的规则。还有,

我觉得像 AtomPub 这样的,它不仅告诉你,你将得到什么返回,而且他还会告诉你,你能

访问哪些方法以及调用这些方法将得到状态码。这里是有协议的,他们只是被传来传去,而

且我认为我们应该探索媒体类型,它们能清楚地告诉我们:我们能做什么,我们能怎么查询

和浏览这些超媒体表象,以及它是如何将我们同超媒体联系起来推进应用的。 

InfoQ:可以说是超媒体格式承担了契约的角色吗? 

JW:没错,笼统地说,是这样的。事实上,我们的一个朋友,也是过去的同事,George Malamidis

曾对我说过:“Web 已有一种契约语言,它叫 HTML。”  直  到今天当我说这句话的时候我还

是很害怕。George 是这些圈子里面非常深邃的思想者,但是我还是相信他是对的,我只是

害怕一下子站到他的高度。 

InfoQ:让我们假设你已经说服了某人,REST 是个好东西,但是现在轮到他们去说服他们的

同事去实际使用它,你有和建议?你在你们公司是如何宣扬 REST 的呢?最好的方法是什

么? 

JW:我不会宣传它。我认为它必须作为某个环境中解决访问的方法出现。大概在去年左右,

我曾参与过一个系统,该系统最初的设计是基于 JMS 的。这很好,我也喜欢用 JMS  ,它是

一个很好的想法,但是最初的设计是在没有整体考虑该系统将要部署的环境下完成的。JMS

虽然很好,但也有它的复杂性。最后通过用几天的时间完成的一个桩,我们发现实  际上该

 

Page 16: Architect 201003-by-info q

 

系统所要求的负载是 HTTP 就足够胜任的。 

从我们不断改进软件交付的角度说,HTTP 具有很多的好处:它要快得多;较之 JMS,写 HTTP

程序要简单得多;你可以容易地使用类似于 Poster 或者 Curl 这样的工具进行测试。当时那

的个系统的交付非常好,房间后面的一个人开心地笑了,他也是我们中的一员,HTTP 的确

很棒。而且,我想如果当初我们沿着 JMS 的方向走下去的话,那我们会辛苦很多。事实是,

QA  人员可以用带有 Poster 插件的 Firefox 对该系统进行测试,或者是一些高级的容易理解

的探索性测试,他们以我们没有相像到的非常好的方式破坏我们的系统,因为系统表面对他

们是开放的。这让我很开心! 

IR:最后赢得到更多的支持者,对吧? 

JW:是的,所以这又是一个有影响的事情。 

IR:很多人对于系统如何运行,或者系统如何向外界暴露服务都有自己显见的理解,并且人

们习惯于使用自己所熟悉的方式去查看,比如浏览器,Poster 或类似的东西。这非常奇妙:

事实上,我们也是从我们所喜欢的东西开始,我们更喜欢谈论 Web,Web 相关的事物以及

REST,进而更多地谈论 REST,我认为在一个组织里宣传 REST 有时并不合适。我常常在人们

说“我要 SOA”时就非常崩溃。SOA 是另一个应该被删除的单词之一。我们的谈话应该从我

们要做什么开始,并且用人们所熟悉的方式去讨论它,而现在不熟悉 Web 的人几乎没有了  。

我们可以仅仅从一些 Web 可以做的简单的事情开始,并说“想想,你的应用是不是也能这

样工作呢?” 

JW:SOA 的危险之一就是它经常和产品绑在了一起,以至于常常变成“我可以卖给你 SOA”

——“不,你不能”,而且我看到 REST 的名字也使用到某些软件产品之中了。这有时候给

人们的谈话带来疑惑,因为人们想他们可以将 REST 插入到他们的应用之中,他们可以购买

REST 平台,然后就变得 RESTful 了,然后,他们做的所有的事情就认为“包含 REST”了。他

们不会批判地思考它(REST)为什么对业务有帮助。这仅仅是高级 IT 决策者或者提供商们

的结论,而不一定是出于对业务最好的角度,而且几乎不会出于开发团队的角度考虑,而开

发团队才是实现服务的真正主体。 

IR:通过插入某种适配器就可以将一个WS‐*的应用程序从外表上包装成一个RESTFul的应用,

还希望它能成为一个丰富有用的 RESTFul 的应用,这几乎是不可能的。   

JW:这样的应用是一个危险的 REST 应用,因为其底层实现的设计就没有这样一层表面或以

这种方式加载,因为其底层实现是以消息为中心或 RPC 的方式设计的。 

 

10 

 

Page 17: Architect 201003-by-info q

 

IR:这区别大了去了,而且从其本身思考,假设在一个资源之上套上一个更大的资源,而这

个更大的资源是在一个完全不同的泛型中设计的。你就会失去发现业务及流程的有趣点的机

会。谈到资源,它常常展现了事物内在的固有价值。搜索结果的进进出出对于 Google 这样

的公司非常有价值,这就是他们用来挣钱的方式之一,把搜索结果展现成资源是思考和探讨

的一种很好的手段。 

InfoQ:观众提问:REES 位于 HTTP 之上,HTTP 是一种非常古老的规范了,我们使用它也已

经有很多年了,有没有可能 REST 会后退到 HTTP 规范所规定的范围之内呢,不论在过去的

20 年内我们是如何使用 HTTP 的,现在我们是以更有趣的方式在使用 HTTP 了,而且,我们

仍然有一些没有完全实现 HTTP 规范的客户端或浏览器。比如,大家都知道,将 FLEX 和 REST

用在一起非常困难,那是相当恐怖!你是如何看待的呢?你是否觉得我们应该需要一个新的

规范,或这更新,这样我们才可以解决哪些我们以前使用 HTTP 时没有碰到过的哪些问题,

也许现在我们需要更多的 HTTP 能力?或者,你是否认为在将来的 1‐2 年内所有的浏览器会

实现当前的 1.1 规范供我们在未来的 20 年愉快地使用呢? 

JW:浏览器不支持所有的 HTTP 动词的原因主要是 HTML 不支持,所以我们留下了 GET 和

POST,这是非常有限的。我并担心,原因是对我而言浏览器已死。它是最常使用但却是最

没意思的 Web 代理。我更感兴趣的是计算机间的交互,而不是人和浏览器之间的交互,而

且现在,在人们对它(浏览器)施压时,它已经嘎吱嘎吱苟延残喘了,但是对于人们互相 

facebook 或做任何小孩子们做的事情来说,它还是能足够胜任的,所以我并不担心它。真正

让我担心的是 W3C 中的一些工作组正在前进的一些未来方向,它们将更有效地重织网络。 

现在的 Web 基础设施,在世界的各个角落都可以访问,它也走到了自己的神奇的临界点

(tipping point)。 

我担心如何 W3C 的伙计们会带来一个新东西,比如 HTML5.0 并将它推广开来,那就会出现

一个怪异的悖论——网络中一半是原有的 Web,另一半是新的,他们各自拥有 Web 套接字,

而  且都很困惑,网络中不在只有扩展标记语言,这是我想到的最大的麻烦。目前,我正在

等待浏览器提供商的创新,我没有什么意见,对此我没有什么兴趣,但也觉得尚可。我希望 

W3c 能以更加发展的方式来滋润网络,而并不希望看到某人成为 Tim 先生(万维网之父)

第二,不幸的是,我担心 W3C 中可能有人会想这么干。 

InfoQ:观众提问:最近我们看到,即使在现在的大会上,在编程上,很久以前我们有了 Lisp,

然后我们有了更多的抽象以及对象或更大的组件,现在我们看到人们又回到了函数式  编程

上了。Web 中也发生着类似的事情,我们曾有简单的 HTTP 规范,然后我们又有了很多抽象,

如 SOAP 和 BPEL,然后我们又回归简单,到了 REST。这是否意味这一种走向简单的趋势呢?

11 

 

Page 18: Architect 201003-by-info q

 

又或者这是软件一直以来的方式,风水轮流转? 

JW:回答这个问题我还不够资格,呵呵。Ian 经历过多次这样的轮回,所以他应该有合适的

答案。 

IR:从怀旧驱动的发展的观点看,每个文字开始时就很好,回到古老的方式并没有什么不好。

你谈到了简单性和趋向简单性的趋势,我觉得对于 REST 推行者来说,在推行的时候,  简单

性并不是他们要强调的优点,而是限制,让限制再次浮出水面并意识到他们。围绕这 Web

有很多应用,而这些应用往往滥用了 Web 的基础设施及其使用方式。好的 REST 推行者会  强

调和展现哪些限制并告诉你,如果你在这些限制之内工作,你就可能实现更可达,高性能。

这是我钟爱的回答。 

JW:是的。我们的确为分布式系统做了一层又一层的抽象,但是你知道吗?这些抽象并没

有带来什么好处。世界上一些最大最复杂的分布式系统并没有那么大和那么复杂,然后这  些

蹩脚的协议出现了,它们强调同步,强调文本驱动并且全球范围内推广。这让我们工程师们

很惊诧而且觉得没意义。这是 Web 的悖论:这是世界上最垃圾的东西,但是很广泛。对  于

我来说这已经是尽头了,因为我们是完全支持基于 XML 的协议并且干的都是这类时髦的事

情。 

我把我的名字放在一些 OASIS 的项目以及其他事情上——希望上帝会阻止坏事的发生——

公平地说,我们认为我们有最佳的意图,我们认为这些东西会有用,并且在某个特定领  域

内有用,但是 Web 和 HTTP 已经向我们证明了,如果你要扩展和广泛可达,你必须要做一些

简单的事情。这些简单的协议是让每个人能够交互并且让这种交互能成为 21 世纪早期计算 

领域的核心的基准线。所以,没错,回到根本! 

原文链接: 

 http://www.infoq.com/cn/interviews/robinson‐webber‐rest‐cn 

相关内容: 

加密因特网 

HTTPS连接最初的若干毫秒 

Facebook架构师QCon北京 2010 演讲:扩展Memcached实战 

Erich Gamma确定QCon北京演讲:设计模式 15 年 

提高架构质量的 10 个观点 

12 

 

Page 19: Architect 201003-by-info q

马上报名

http://www.adobechinadeveloper.com/FlashPlatformSummit/index.htm

如果您来参会

北京国际会议中心(二层)

2010年4月21日~22日 中国 - 北京

奥多比平台技术峰会是由奥多比公司举办的面向中国应用软件开发者的综合技术研讨会。旨在为中国的开发者们介绍和讲解有关Adobe Flash平台技术及其应用开发的相关知识和开发技巧,以及Adobe Flash平台技术的发展趋势以及其它热门的技术议题等。

-�>�1J?�4���7'�=30/520N�C30�&=Flash Builder 4 =0;,NHE!.!L" ����<Flash'�/5�*:I=$�@)<N���7 ������=D9/5�#GBK%K=�8N�1F46�A+�(��M

Page 20: Architect 201003-by-info q

 

 

热点新闻    News

Eclipse Virgo项目获得批准 

作者 Alex Blewitt 译者 张龙 

近日Glyn Normington宣布Eclipse Virgo项目通过了项目创建的评审,现在只等代码导入了;

同时VMWare也开始了与Eclipse基金会的合作。 

Eclipse Virgo将成为SpringSource dm Server(最近发布了 2.0 版)的下一版本。基本想法是在

适当的代码重构(包括对org.eclipse.virgo包的重命名)后发布 2.1 版,同时可能会有一些变

化。 

dm Server和Eclipse Virgo之间主要的区别在于前者基于GPL 3.0,而后者基于EPL 1.0,这么做

会扩大项目的应用范围,Adrian说到: 

虽然JavaScript最初出现在 1995 年,但直到过去几年,由于Prototype和JQuery这样目

前的dm Server基于OSGi和Spring Dynamic Modules(现在已经标准化为OSGi Blueprin

Service)编程模型为模块化的企业级应用开发提供了极佳的服务器平台。企业级OSGi

与dm Server已经取得了长足的进步,但实事求是地说,在企业应用开发中采用OSGi

还是需要付出很高的代价的。就像很多新技术一样,一开始的投资需要随着时间的推

移才能得到回报。Hal Hildebrand在其最近的一篇博文中

谈到了当前的OSGi价值。   

目前的企业 OS

“ 

Gi 和 dm Server 引起了很多人的兴趣,围绕其的创新也一刻没有停止

过。这种兴趣尤其以早期的使用者以及那些需求符合 OSGi Service Platform 动态模块

特性的项目为甚。但对于主流的开发团队来说(只希望尽快构建好企业应用,麻烦越

少越好),目前采用企业 OSGi 的代价可能会超出其短期的收益。在企业 OSGi 成为主

流的企业应用开发方式事实上的标准前需要重点考虑这个问题。 

请注意这里我说的是企业应用开发,如果你编写的是基础设施软件并且需要创建

“stackless stack(Kirk Knoerschild、James Governor)”,那么OSGi已经成为事实上的

法了,得到了dm Server和与之相关的dm kernel子项目的完全支持。   

13 

 

Page 21: Architect 201003-by-info q

 

Adrian的评论被一些人断章取义了,他们认为模块化对于复杂的系统非常奏效,但对于简单

o

o

的Hell  World式的应用却没什么必要,然而OSGi可以帮助我们解决复杂性问题,Kirk 

Kn erschild在OSGi DevCon London 2010 上的演讲中说到: 

软件的复杂度呈现出指数级的增长。你知道么:   

在上世纪 90 年代,一共有 1200 亿行代码;在本世纪

代码行数每过

前十年,一共有 2500 亿行代码;

7 年将会发生哪些事情。在 2010~2017 年间,我

我们需要一些东西帮助自己理解复

虽然 V Helios train(将于今夏发布)的一部分了(因为时间上

以及协议的变化)会扩大该产品的应用范围么? 

d

7 年就增长一倍;50%的开发时间花在了理解代码上面;90%的软件

用花在了维护和演化上面。   

根据以上这些数据我们来看看未来

“ 

们所编写的代码量将超过现有的所有代码总量! 

除了上面这些因素以外,还有其他一些主要考虑。

杂系统、管理复杂性、简化维护的代价、处理软件系统的自然演化、当系统变大时能

处理自然架构变迁。长久以来,我们都缺乏一种中心架构,但这种情况不会持续太久,

因为企业将要使用 OSGi 了! 

irgo 已经不太可能成为 Eclipse 

来不及),但新版的 dm Server 即将发布,如果赶不上 3 月份的 EclipseCon 2010,那应该会在

Helios 发布前后。 

你认为项目的迁移(

原文链接:http://www.infoq.com/cn/news/2010/02/eclipse‐virgo‐approve  

pdate:NetBeans与OSGi

相关内容: 

Bundle.u  

微软将向Eclipse开发者提供大量工具 

回顾 IBM developerWorks十周年:精彩内容  

、 SpringSource宣布将dm Server移交给Eclipse.org Virgo项目将基于EPL协议 

Eclipse插件Top30,而你会喜欢哪个IDE? 

 

 

14 

 

Page 22: Architect 201003-by-info q

 

 

热点新闻    News

Apache Beehive正式退役,迁移到Apache Attic上 

作者 Gilad  Manor  译者  张龙 

上个月,Apache Beehive项目的众多提交者投票表决停止该项目,原因是项目太不活跃了。

Apache Beehive的上一个版本是1.0.2,还是在 2006 年十月份发布的。 

Beehive项目的代码基最初是由BEA编写的,作为WebLogic Workshop项目的一部分,以此吸

引人们使用WebLogic 7.0 和 8.1。最后,这部分代码基被BEA以开源的方式捐献出来,形成了

现在的Beehive。Beehive通过 3 个核心组件来简化Java EE的开发: 

NetUI——这是一个自动化层,覆盖了Apache Struts 1.x以简化对应用流的管理。   

Controls framework——该框架会生成大量的样板代码以供使用旧版本 Java EE EJB 与 Web 

Services API 的项目所用。   

Web Service Metadata——该组件可以通过注解自动生成Web Services API,它实现了JSR‐181,

后来被纳入到Java EE 5 中。   

Henri Yandell在本月 10 日发布的声明中给出了其他一些选择以替代上面提到的 3 个组件: 

使用Struts2或Spring Web Flow替代NetUI——Spring Web Flow是Spring基础设施的一部分,

重点解决导航规则和会话(conversation)状态管理等问题,它有力地保证了系统的模块

化和重用性。Struts 2 基于WebWork,能构建可重用的UI模板,如表单控件、UI主题、国

际化、映射到JavaBean上的动态表单参数以及客户端/服务器端验证等等。   

使用Spring Framework替代Controls framework——借助于Spring可以从应用的Web层访问

本地或远程的EJB。   

使用Axis2 JSR‐181实现替代Web Services Metadata——Apache Axis是个Web Services、

SOAP以及WSDL引擎,可以通过注解生成Web Services,同时还支持Web Services的客户

端与服务器端。   

15 

 

Page 23: Architect 201003-by-info q

 

希望继续使用Beehive项目的用户可以根据上面这些建议进行调整,同时Beehive的项目站点

和代码基将迁移到Apache attic上。 

原文链接:http://www.infoq.com/cn/news/2010/02/apache-beehive-attic

相关内容: 

Web Profile会将Web开发者吸引到“Enterprise Java”上么? 

Jave EE 6 特性:依赖注入、Bean验证和EJB增强 

Spring 3.0 发布:基于Java5,添加了新的表达式语言和对REST的支持 

简化持久性实体的传递 

修剪Java EE 

16 

 

Page 24: Architect 201003-by-info q

 

 

热点新闻    News

Chrome 4 现已支持HTML 5 Web 

SQL Database API 作者 Abel Avram 译者 张龙 

近日Google宣布将支持HTML 5 Web SQL Database API,其他浏览器厂商也表示将紧随其后提

供该支持,有的甚至已经开始支持该API了;但同时,HTML 5 规范的制订却遇到了阻碍,因

为所有的参与者都已选择了SQLite作为底层数据库,要想实现标准化还得考虑多个不同的实

现。 

作为HTML 5 的一部分,W3C组织正在制订Web SQL Database API草案,该规范主要用于解决

如何通过SQL存储及访问数据的问题。文档中所使用的SQL语言是SQLite 3.6.19。网页可以使

用这个API与嵌入式的客户端数据库进行交互,这对于那些想要在本地存储数据或是离线浏

览的应用来说价值非常大。 

Google已经在其最新的浏览器Chrome 4 中通过SQLite提供对Web SQL Database的支持了,这

个举动可以看作是向标准化迈进的一大步,因为Google Gears中已经拥有了一个Database 

API,也是基于SQLite。Gears API为所有主流浏览器提供了结构化的数据存储功能,包括IE、

Firefox以及Safari,但现在Google已经停止Gears的开发工作了。 

Firefox 3 拥有一个嵌入式SQLite数据库,目前主要用于存储书签和历史记录,但可能不久后

就将支持Web SQL Database API。当前的开发工作正在WebKit(Safari所用的渲染引擎)上进

行以向Web开发者提供Web Database API。现在谁也不知道微软对于IE和HTML 5 Database API

的计划到底是什么。 

虽然一些公司已经实现了 Web Database API,另一些也正在实现当中,但根据草案的制订情

况来看,规范还是遇到了一些障碍,因为所有的参与者都已经选择使用 SQLite 了: 

规范进入到了一个僵局当中:所有的参与者都不约而同地使用了相同的 SQL 后端(SQLite),

17 

 

Page 25: Architect 201003-by-info q

 

但我们需要多个独立的实现来继续标准化之路。除非有其他实现者想要实现该规范,否则对

SQL 语言的描述仍将停留在 SQLite 上,这对于标准来说是不可接受的。你想要实现独立的

SQL 后端么?请联系规范的编辑,他可以为该 SQL 语言编写一个规范,只有这么做才能推进

规范的不断发展。   

在这种“僵局”下,谁也不清楚到底是规范将会推进实现抑或是还有其他解决之道。目前,

Google 正加快浏览器开发的节奏,没有哪个浏览器厂商愿意等到标准全部制订完成后才开

始实现自己的 Web SQL Database API 支持。 

原文链接:http://www.infoq.com/cn/news/2010/02/Web‐SQL‐Database 

相关内容: 

8.8.8.8——用于快速浏览的DNS服务器 

Google正制订一项新协议,旨在替换掉HTTP 

HTML 5 通过sandbox属性提升iFrame的安全性 

YouTube发布HTML 5 视频,但并不支持FireFox 3.6 

ASP.NET的未来:简化开发,HTML 5 及性能提升 

18 

 

Page 26: Architect 201003-by-info q

 

 

热点新闻    News

Flex开发者需要知道的 10 件事   

作者 张龙    

不久前,Michael Portuesi发表了一篇博文,谈到了Flex开发者需要知道的 10 件事。文章介绍

了每个进入Flex领域的开发者都需要掌握的基本知识与技能。 

Michael Portuesi 给出的 10 个条目中,有些是开发者需要了解的简单细节信息;有些则揭示

了 Flash/ActionScript/Flex 与其他开发环境之间的差别。 

如果你了解 HTML/CSS 并熟悉 JavaScript,但却对 ActionScript 或 Flex 一无所知的话,那么应

该花些时间学习一下面向对象编程,因为 ActionScript 是一门完全的面向对象编程语言,而

Flex 则是一个面向对象的框架。 

1.  再简单的东西也是异步的 

Flex 是一个异步框架,因此我们绝对不能指望代码调用后就能立刻执行。事实上,我们是无

法预知方法的调用序列的。 

2.  搞清楚 Flex 组件的样式与属性 

Flex UI 组件(按钮、菜单等等)既有属性(通过 ActionScript 语言指定)也有样式(通过 Flex

框架指定)。搞清楚他们之间的区别是非常重要的,因为组件的某些可视化效果可以通过属

性指定,但另一些却只能通过样式设定。通过属性指定: 

button.width = 100;

button.height = 50;

通过样式指定: 

<mx:Style>

Button {

color: #cc0000;

textRollOverColor: #ccff00;

19 

 

Page 27: Architect 201003-by-info q

 

fontFamily: Trebuchet MS;

}

</mx:Style>

<mx:Button id="setupB" text="Click Me" click="onSetup()" />

3. Flex 中的样式与 HTML 中的不尽相同 

可以使用标准的 CSS 样式表来为 Flex 组件添加样式,也可以在 Flex 应用中包含 CSS 样式表。

虽然标准 CSS 使用连字符(例如 text‐font)格式来定义样式名称,但是 Flex 使用驼峰式的命

名格式(例如 textFont)。这是因为连字符不能出现在 XML 的属性中,所以不能用这样的名

字作为 MXML 标签的属性。 

当然了,如果把样式定义在外部的 CSS 文件中或者 Style 标签中,也可以使用连字符格式的

样式名。此外,Flex 还定义了很多 HTML 中不存在的 CSS 样式。 

4.  尽管看起来不同,但 MXML 和 ActionScript 本质上是一回事 

在 Flex 中声明的所有 MXML 标签都会被 Flex 编译器转换为 ActionScript 代码;当然了,也可

以在 MXML 文件中嵌入内联的 ActionScript 代码。既可以使用 MXML 也可以使用 ActionScript

创建新组件。 

5.  理解 Flex 的 Code‐behind 模式 

虽然 MXML 和 ActionScript 本质上是一样的,但他们各司其职。一般来说,MXML 负责显示

界面,而 ActionScript 用来完成功能。Code‐behind 用于解耦 MXML 和 ActionScript,这样设

计师可以直接修改 MXML 而无需阅读代码,程序员则可以更好地组织和重用功能。 

6.  理解 Flex 组件的生命周期 

Flex 通过状态机机制定义了一套完美的生命周期模型,用于组件的创建、运行和销毁,还定

义了一些“入口”,开发者可以借此完成定制化的工作。没有透彻理解组件的生命周期可能会

导致错误的编程模型。 

7.  理解 Flash 运行时所使用的“跑道”模型 

理解 Flash Player 的渲染和代码执行机制非常重要的。在执行了改变界面的指令时,Flash 

Player 并不是立刻把你要的内容显示在屏幕上,它根据一定的周期来刷新屏幕,而代码的执

行则是另一回事。这和 Java 正好相反,Java 总是等待程序主动告诉它什么时候重绘屏幕。 

8.  理解数据绑定与查看器(Watcher) 

20 

 

Page 28: Architect 201003-by-info q

 

Flex 提供了一种数据绑定机制。简单地说,就是将一个源属性绑定到一个目标属性上,当源

属性发生变化时,目标属性也会随之变化。不仅仅可以绑定到属性,还可以绑定到函数。甚

至可以为某个属性创建一个 Watcher,当属性变化时会获得事件通知。 

9.  数据封装与松耦合非常重要 

对于 Flex 和 AIR 项目来说,代码组织与高层结构非常重要。有些人竟然在一个文件中编写了

1000 多行代码,这导致的问题就是牵一发而动全身。 

10.  理解 ActionScript 中的弱引用与强引用 

不管使用何种语言与开发环境,内存管理始终是一个重要的问题,ActionScript也不例外。如

果不理解运行时环境的内存管理,那么很容易就会出现内存泄露与内存碎片问题。请阅读这

篇博文及文章来深入了解ActionScript的垃圾收集机制。 

原文链接:http://www.infoq.com/cn/news/2010/02/Flex‐ten‐things 

相关内容: 

使用Flash Builder 4 beta提升开发生产率 

开源的ActionScript调试器——De Monster 

Flash CS5 新功能提前曝光 

HTML5、H.264 及Flash综述 

Adobe终于为Flash的大bug致歉 

21 

 

Page 29: Architect 201003-by-info q

 

 

热点新闻    News

CWE/SANS发布 2010 年 25 个最危险的编程错误 

作者 张凯峰    

CWE/SANS 发布的 2010 年度 25 个最危险的编程错误,是一个传播最为广泛而且会导致严重

软件缺陷的关键编程错误列表。这些错误通常易于发现并被利用。之所以危险,是因为它们

会频繁地被攻击者利用,来完全接管软件、偷取数据,甚至阻碍软件的运行。 

这个错误列表是SANS研究中心、MITRE和许多来自美国和欧洲的顶级软件安全专家共同协作

的结果。它参考的经验包括:SANS的20 个攻击导向、MITRE的普遍缺陷列表(  Common 

Weakness Enumeration )。MITRE在美国国土安全部网络安全  部门的支持下维护着CWE网站,

对这 25 个最危险的编程错误提供了详细的说明,以及对如何减轻和避免错误给出了权威的

指导。CWE站点包括了超过 800 个  的编程错误、设计错误以及架构错误,这些错误可能导

致软件安全上的缺陷而被攻击者利用。 

根据 CWE 站点的信息: 

这个列表可以作为教育程序员的工具,通过识别和避免非常普遍的错误,在软件发行之前防

止各式各样一直折磨软件行业的软件不安全因素。软件客户可以通过同样的列表来要求更加

安全的软件。研究软件安全的人们可以把研究的重点放在这 25 个范围更小但更重要的软件

安全缺陷子集上。最后,软件经理和 CIO 们可以使用这个列表来衡量软件产品安全化工作的

进度。 

2010 年度的这个列表是对 2009 年列表的重要提高,今年的 25 个错误是根  据来自超过 20

家不同的组织的数据进行了优先级划分,而且引入了重点的分类方法,来允许开发者和其他

用户选择自己最关心的 25 个错误中的一部分。另外,新的列表还添加了一套最有效的

“Monster Mitigations”,来帮助开发者减少或者消除所有 25 个错误,以及CWE记录的其他 800

个不安全因素。 

下面是排在前五名的编程安全错误: 

22 

 

Page 30: Architect 201003-by-info q

 

1. 没有保护 Web 页面结构  (XSS,跨站点脚本攻击)   

2. SQL 命令中特殊元素的不合理处理(SQL 侵入)   

3. 未检查输入大小的缓存拷贝(经典的缓存  溢出)   

4. 跨站点请求伪造(CSRF)   

5. 错误的访问控制(授权)   

原文链接: http://www.infoq.com/cn/news/2010/02/cwe‐sans‐top25 

相关内容: 

处理.NET中的内存泄露 

严重内存泄漏困扰WPF 

.NET内存泄漏 

JProbe 8.0:Java代码、内存及覆盖率分析王者回归 

使用BleakHouse发现Rails应用的内存泄漏 

23 

 

Page 31: Architect 201003-by-info q

 

 

热点新闻    News

Google将不再支持老式浏览器 

作者 Abel Avram 译者 张龙 

近日Google宣布将不再支持老式、安全性差的浏览器,如IE 6、Firefox 2.x、Chrome 3 以及Safari 

2,从下个月 1 号开始Google Docs和Google Sites editor就将率先履行这一决定。 

近日Google Apps的管理员们收到了来自Google的一封邮件,信中说到Google将逐步放弃对几

个老式浏览器的支持。虽然很多人都认为Google这么做是剑指IE 6,但实际上Google指的是

所有的老式浏览器。今后,Google将只支持IE 7+、Firefox 3+、Safari 3+以及Chrome 4+。在用

户使用老式浏览器访问Google Docs或Sites时就会收到浏览器将不再被支持的通知“之后,这

些应用的某些功能可能会在老式浏览器中反映缓慢,或者干脆就无法正常运作”。今年晚些

时候,GMail和Google Calendar也将不再支持老式浏览器,但这并非表示用户仅仅只会收到

一条警告消息而已。根据Google发言人所述,使用老式浏览器的用户只能查看信息而无法对

其进行编辑。 

根据Comscore的调查,目前GMail的用户高达一亿四千六百万,仅次于Hotmail和Yahoo位列

第三位。只有不到 1%的用户使用旧版本的Firefox或Chrome,从全球来看,IE 6 用户仍然占

据了 20%,此外IE 6 还占据了 60%的企业浏览器市场。这样,Google的这个举动将会产生很

大的影响,尤其是对一些企业来说更是如此,他们要么放弃IE 6,要么不再使用Google服务。 

其他公司也已经对IE 6 采取了行动。37signals(知名的Web软件公司)早在 2008 年就开始逐

步淘汰IE 6 了;Youtube在 2009 年不再支持IE 6。到目前为止,I Dropped IE6站点上已经有 787

个公司宣布不再支持IE 6。 

Digg也曾考虑不再支持IE 6,但却发现使用IE 6 访问其站点的大多数用户都是干正事的,因此

IE浏览器,但却并没有强制公司也这么做。IE团队经理Dean 

他们决定“给用户一个消息:嘿,快点升级吧!”但这么做实在是毫无意义。与之类似,InfoQ

在对访问其站点的用户浏览器进行分析后发现,IE 6 占据了整个Internet Explorer的 41%(而

IE7 和IE8 各占据 27%)。 

微软早已推荐用户升级到新版

24 

 

Page 32: Architect 201003-by-info q

 

Hachamovitch谈到了微软没有终止IE 6 的原因: 

对于 PC 用户来说,是否升级软件是他们自己的事儿。 

很多 PC 并不属于个人,而是公司的。公司里负责这些机器的人会决定如何处理他们。

他们要根据预算决定购买多少台 PC。对于这些人来说,软件费用并不仅仅是指购买的价

钱,还包括部署、维护的费用,同时还要确保软件能与公司的 IT 基础设施协同工作。 

我们无法放弃对IE 6 的支持,因为要在产品的生命周期内对Windows上的IE提供支持。我

们要履行自己的承诺。 

近来已经有几个公司开始尝试说服Web站点停止对IE 6 的支持,同时可能会有更多的小公司

‐Old‐Browsers

开始跟随Google的脚步,自信地宣布不再支持老式浏览器。 

原文链接: http://www.infoq.com/cn/news/2010/02/Google‐Stop‐Support  

”运动

相关内容: 

“拒绝IE6  

hrome Frame运行HTML 5 IE中使用Google C  

.NET安全漏洞波及Firefox

IE和火狐将使用DirectX进行呈现

Silverlight监测工具:Silverlight Spy 

25 

 

Page 33: Architect 201003-by-info q

 

 

热点新闻    News

SOA设计关乎契约还是服务实现? 

作者 Boris Lublinsky 译者 胡键       

大量的出版物都在描述 SOA 实现的设计,但却对接口(契约)设计鲜有关注,这让人不由

得产生一种“实现的设计更重要而且更值得关注”的感觉。对此的一个常见理由是契约会随着

时间改变,预先把过多的时间花在它们的定义上跟敏捷开发方法相抵触。 

Steve Jones在他最近的贴子里对这一普遍误解提出了异议,说道: 

在我看来,这种看法就像那种不愿意写文档的伪敏捷人士,他们根本就是狗屁不通,

而不是因为他们已经开发出了具备自描述能力的质量极高的组件。这基本上就是在

说任何人都要等到系统可运行了之后你才能知道它的功能。这等于让需求改变适应

实现。我现在并不是说需求不能改变,也不是鼓吹瀑布模型,而想说明 SOA 编程中

的时间分配问题:在确定规格说明和设计过程中,大部分时间应该花在服务间的契约

和交互上,至于关注如何设计这些服务满足契约,则可以少花些时间。   

“ 

为什么契约是 SOA 实现中的最重要部分,Steve 列举了以下原因: 

1. 其他组件依赖的是契约而不是设计。因其错误而导致的成本跟提供者的数量成指数关

系。一旦契约正确就位,那么人们就可以并行开发,这可以大大加速交付时间,减少风

险。   

2. 测试是围绕契约而不是设计进行的。契约是正式的规格说明,设计必须满足它,而且各

种形式的测试也都应该使用它。   

3. 设计可以在契约的边界内悄悄地改变。   

契约的重要性这一概念并不是新鲜事物。按照Dimuthu Leelarathne的说法:如果你没有首先

设计服务间的契约,服务间复杂的集成问题就会出现。 

实际上,创建好的服务契约并不是件易事,要求很好地理解契约核心业务。虽然已有一些服

务接口设计的公认方法,但是更多的时候它还是艺术而非科学。结果,开发者和软件厂商都

26 

 

Page 34: Architect 201003-by-info q

 

典型地把注意力放在了他们受到的培训(和要卖的东西)上——服务实现的设计和编码。在

Steve看来: 

……IT 的重点……太少地放在了确保外部接口至少在一段时间内保持正确的上面。契约

可以演变,我有意地使用了这个术语,但大多数时候,旧的契约在人们迁移到新版

本的过程中还要被支持。这意味着契约比设计拥有的生命跨度要长得多……契约是大

事,设计则微不足道。   

“ 

随着我们继续提倡将SOA用于业务/IT对齐,与业务需求对齐的服务契约的作用会越来越明

显。 

原文链接:http://www.infoq.com/cn/news/2010/02/servicecontructs 

相关内容: 

解耦应用与依赖注入框架 

孰轻孰重:运行时SOA治理还是设计时SOA治理? 

对SOA实施者的实践忠告 

有效的SOA治理一定需要注册与存储吗? 

SOA生态系统

27 

 

Page 35: Architect 201003-by-info q

 

 

热点新闻    News

Chrome中 5 大安全增强 

作者 Abel Avram 译者 马国耀 

为了让浏览更安全,Google最近为Chrome增加了 5 项安全增强:跨文档消息递送、

Strict‐Transport‐Security、Origin、X‐Frame‐Options以及反射XSS过滤器。其中某些特性在其他

浏览器中已经实现或即将实现。 

消息递送 

出于安全和隐私的原因,浏览器禁止隶属于不同域的文档之间的交互。HTML5 引入了一个

新方法,称为postMessage(),该方法允许独立的iFrame中的文档之间的交互。该方法签名如

下: 

window.postMessage(message, [ports,] targetOrigin)

这样,浏览器就即能获得 iFrames 提供的安全又能实现跨文档的交互。 

Strict­Transport­Security 

HTTPS是用于连接网站并传输需要被保护的敏感信息的一种安全的方式。但是浏览器并非总

是强制使用HTTPS,比如,如果某网站提供的安全证书有问题,那么浏览器会发出一个警告,

而用户可以继续在半安全的连接上浏览该网站。PayPal已经成功地建议向HTML5 的规范中引

入  Strict‐Transport‐Security (STS)这个HTTP头。当服务端返回了包含STS的HTTP头时,实现

了该特性的浏览器应该: 

1. 当任何安全传输错误或警告产生时(包括由网站使用自签名的证书而引起的),UA [User 

Agent]结束所有的安全连接。 

2. 在解引用之前,UA [User Agent]将指向STS服务器的不安全URI引转换成  安全的URI引用。 

28 

 

Page 36: Architect 201003-by-info q

 

在 Web 服务器或用户代理认为安全必要时,该特征强制使用 HTTPS。在网络繁忙的场所使

用无线连接之上的不安全的 HTTP 连接为窃听打开了大门,而结果就可能会导致个人访问网

站的私有信息被窃取。STS 可以保护其不被窃取。 

目前,Paypal实现了该特征。Chrome 4 也实现了STS,此外还有Firefox的安全插件  NoScript,

它也拥有相同的功能。FireFox自身的STS实现正在进行当中。 

Origin 

跨站请求伪造(Cross‐site request forgery或CSRF)  攻击的方式是通过在不知不觉中欺骗一个

网站让其向  另一个网站提供私密信息。Origin是HTML 5 中包含的一个HTTP头,就可以通过

让用户代理去指定请求源的方式来解决这个问题。当一个恶意网站将请求重定向到另一个网

站时,浏览器将会在该请求中包含“Origin”头,目标网站将会根据该“Origin”是否可信来决定

是否执行相应的操作。 

Google和Mozilla都在他们各自的浏览器中实现该特征。W3C的  规范提供了更多的细节信息。 

X­Frame­Options 

另一个HTTP头字段X‐Frame‐Options可被用于防范ClickJacking攻击。这类攻击是通过在网页的

的浏览器

输入控件上覆盖一个不可见的框(frame)的手段完成的,当用户点击该控件时,他实际上

是在其之上的不可见的框(frame)中输入。网站可以通过指定  “X‐Frame‐Option: deny”  的

方式防范ClickJacking攻击,支持该特性的浏览器会决绝呈现框(fram)中的内容从而阻止了

ClickJacking攻击。 

IE 8 是第一个实现该特性 ,Chrome和Safari继之。 

反射XSS过滤器 

跨站脚本攻击(Cross‐site scripting或XSS)是又一利用安全弱点进行攻击的手段,也是最难对

付的攻击之一。IE 8和Firefox的NoScript控件中有反射XSS过滤器,该特性是被Google添加到

WebKit并用在Chrome 4 中。该过滤器校验将要运行的网页中的脚本是否也存在于请求该页

的请求信息中,如果是,则极可能意味着该网站正在受到该脚本的攻击。 

 

原文链接:http://www.infoq.com/cn/news/2010/02/Chrome‐Security‐Enhancements 

29 

 

Page 37: Architect 201003-by-info q

 

相关内容: 

代号Gazelle,微软研发浏览器上的操作系统 

IE8 脚本引擎JScript 5.8 增强 

Google发布基于全新JavaScript引擎的开源浏览器 

L 使用Gestalt直接在HTML中嵌入Python、Ruby和XAM  

HyperSpace:一个精巧的浏览环境 

30 

 

Page 38: Architect 201003-by-info q

 

 

热点新闻    News

Amazon EC2 因订购过多而导致内部网络延迟? 

作者 Dionysios G. Synodinos 译者 侯伯薇 

近来在Amazon EC2 用户社区中,有各种各样的报道,说他们的实例遭遇到性能很差的情况,

而这是由很高的内部网络延时所导致的。这导致有人推测对Amazon的云的订购可能超过限

度了。 

aw2.0 公司的Alan Williamson撰写了一篇报道,主要是关于他在Amazon EC2 上的体验的,他

抱怨说,Amazon是公司唯一使用的云提供商,看起来它在开始时能够适应得很好,但是有

一个临界点: 

在开始的日子里Amazon的表现非常棒。实例在几分钟内启动,几乎没有遇到任何问

题,即便是他们的小实例(SMALL INSTANCE)也很健壮,足以支持适当使用的MySQL

数据库。在 20 个月内,Amazon云系统一切运转良好,不需要任何的关心和抱怨。    

…… 

“然而,在最后的八个月左右,他们“盔甲”内的漏洞开始呈现出来了。第一个弱点前兆

是,新加入的 Amazon SMALL 实例的性能出现了问题。根据我们的监控,在服务器场

中新添加的机器,与原先的那些相比性能有所下降。开始我们认为这是自然出现的怪

现象,只是碰巧发生在“吵闹的邻居”(Noisy Neighbors)旁边。根据随机法则,一次

快速的停机和重新启动经常就会让我们回到“安静的邻居”旁边,那样我们可以达到目

的。 

…… 

然而,在最后的一两个月中,我们发现,甚至是这些“使用高级 CPU 的中等实例”也遭

受了与小实例相同的命运,其中,新的实例不管处于什么位置,看起来似乎都表现得

一样。经过调查,我们还发现了一个新问题,它已经悄悄渗透到到 Amazon 的世界中,

那就是内部网络延迟。   

   

31 

 

Page 39: Architect 201003-by-info q

 

类似地,cloudkick也报告了实例的高网络延时: 

在几周之前,我们发现在 Cloudkick 上的 ping 操作的延时图看起来非常奇怪。   

…… 

我们在 EC2 上的监控节点会对位于 Slicihost 上的四个不同的服务器进行 ping 操作。

结果到处都是平均 ping 延时。 

“ 

…… 

结论是什么?Alan Williamson关于EC2 被过多订购的帖子看起来非常合理。支持EC2

的网络看起来遭遇了不定期发生的延时问题。   

甚至在AWS论坛上也有来自于EC2 客户的帖子,他们也遭遇了网络问题: 

今天上午 9:15,我们有个实例开始变得没有任何响应。有时你能够登录上去,有时

登录不了。这种情况还没有自动解决,另一个实例(假定在那个实例上有硬件问题)

出现了同样的问题。我认为可能存在网络的问题。   “ 

我可以登录一两次,有时会变得一切正常,然后又变得没有响应了。有谁知道什么原

因? 

实例的 ID 是 i‐c4921fad  和 i‐a0e3d7c8。当试图从位于另一个 EC2 区域的计算机连接

我们的计算机的时候,我也发现了同样的网络问题。   

Alan报告说,在出现紧急情况的时候,他试图通过快速部署新实例来解决,但是没起作用: 

在特别的“救火模式”中,我们花费了至少一个小时来启动新的实例,然后停止它们,

直到找到对我们的网络流量确实有反应的节点。   

 “ 

在虚拟化的环境中,特别是在“吵闹的邻居”的情况下,你恰好位于一个节点,它相邻的实例

的计算量都非常大,这看起来不是好事儿,因为有这样的趋势,EC2 会为相同的一组计算机

分配新的实例(PDF)。 

你可以找到关于云计算和Amazon EC2更多的信息,就在InfoQ中文站。 

原文链接:http://www.infoq.com/cn/news/2010/02/ec2‐oversubscribed 

相关内容: 

亚马逊协助.NET开发人员使用其云计算平台 

32 

 

Page 40: Architect 201003-by-info q

 

REST在IT/Cloud管理中的角色——API的对比 

AWS Toolkit for Eclipse发布了 

Clojure近况:分布式、数学运算与构建的新动向 

遗留应用在云中漫步并非易事 

33 

 

Page 41: Architect 201003-by-info q

 

 

热点新闻    News

全景透视Oracle对Sun的未来规划 

作者 Dionysios G. Synodinos 译者 张龙 

在经过了将近 9 个月的漫长等待后,Oracle终于获得欧盟的批准成功完成对Sun的收购。近

日Oracle宣布了对Sun技术与平台的未来规划。 

Java、JVM及JVM上的各种语言 

Oracle 产品开发高级副总裁 Thomas Kurian 说,Oracle 计划集成 Sun HotSpot 与 Oracle JRockit 

Java 虚拟机;他又补充到,Oracle 打算”振兴“Java 开发者社区并将 Java 编程模型的触角延伸

到新近涌现的应用开发范式上来。比如说,Oracle 计划增加模块化特性、为 Java SE 增加多

核处理支持、为 Java ME 增加新的特性,如多点触摸等。 

InfoQ联系到了Allex Miller以了解Oracle对JVM的规划: 

“我感觉 Oracle 想将 BEA LiquidVM ”JVM on a hypervisor“技术中的精华部分整合到现有

的 HotSpot 代码中;当然了,虚拟化是 JRockit JVM 中最有意思,也是最棒的部分,

非常迎合当前的虚拟化、云、集群等趋势,可以通过这些手段管理计算机资源,相

对于 IBM J9 JVM 来说,这些内容也是极具竞争力的。 

 

我也觉得移除 permgen 并使用 thread‐local 的 GC 非常好。thread‐local 的 GC 指的是对

逃逸分析(escape analysis)和堆栈分配(stack allocation)的优化,而 Hotspot 已经

在这方面做了很多工作。大多数程序所创建的临时对象都用在单独的线程上下文中,

很少被其他线程所用。这样,我们就可以直接在栈上为这些对象开辟内存空间(这么

做更快),无需使用堆,也不必使用常规的 GC 手段进行对象检测与移除了(这么做

会降低 GC 的次数,进而提升效率)。 

 

对 permgen 的改进亟须解决一个问题:像 Groovy 或是 JRuby 这样的语言会在执行期

动态生成大量的小类(small classes)以提供动态特性,而随着 JVM 上动态语言的不

 

34 

 

Page 42: Architect 201003-by-info q

 

断增多,该问题也变得越来越严重。这些类污染了 Java 内存中特定的“permgen”部分

而且难以回收,导致了严重的内存问题。JSR 292 的 invokedynamic 就是为了解决该问

题的:动态语言可以通过该指令在运行期直接链接到调用地址上,因此避免了生成大

量内部类的烦恼。 

 

我认为最好的处理方式并不是消灭掉这些 JVM,而是取其精华,弃其糟粕。这些工程

团队都有一些优秀的人才,他们做出了很多创新性的工作,我希望他们能在这个领域

继续做下去,只有这样 JVM 才能继续充当老大的角色,吸引众多具有开创性的新语

言,如 Scala、Clojure、Groovy 及 JRuby 等。   

Oracle对JCP的未来及其在Java 7 中所扮演的角色所谈甚少,来自RedMonk的Stephen O'Gra

指出: 

dy

我觉得 Oracle 对 JCP 的态度要比 Sun 此前的做法更注重实效,但现在还很难预测未

来的走向。 

 “ 

MySQL 

Oracle 首席开源架构师 Edward Screven 说公司将会一如既往地支持 MySQL 数据库的发展,

Oracle 将 MySQL 看作是对其核心数据库技术的有益补充而非竞争对手。Oracle CEO Larry 

Ellison 强调说,公司将会做出更大的努力改进 MySQL,力度甚至会超过 MySQL 以前的投入,

但却没有提到 Sun 和开源社区。Oracle 将为 MySQL 建立一个独立的销售团队,同时增强其

与 Oracle 其他软件应用之间的兼容性。 

JavaFX与RIA技术 

Oracle 在声明中再一次强调将会加大对 JavaFX 的投入力度,同时 DHTML、JavaScript、Java

及 JavaFX 的整合也是未来的一个重中之重。 

此前Oracle曾终止了BEA打算绑定Adobe Flash/Flex开发工具的计划,现在的这个声明终于填

补了该沟壑,来自ZDNet的Tony Baer指出: 

“我们不难发现 JavaFX 在 Oracle RIA 计划中所占据的重要地位;它填平了 Oracle 终止

BEA 绑定 Adobe Flash/Flex 开发工具计划所导致的 RIA 鸿沟。实际上,Oracle 对 RIA

的态度着实令人迷惑,因为 ADF 可以支持任何框架的客户端显示,而 JavaFX 现在却 

35 

 

Page 43: Architect 201003-by-info q

 

变成了 Oracle 自己的东西。 

JavaFX的拥护者,同时也是开发者Jim Weaver对Oracle支持JavaFX平台的举措信心十足: 

今天的声明更令我坚信 JavaFX 将会继续发展下去,会有越来越多的应用选择 JavaFX

作为 RIA 平台的。目前 JavaFX 至少面临三个大的挑战,我相信 Oracle 会全力以赴迎

接这些挑战的。 “ 

NetBeans 

InfoQ曾报道过此次收购后NetBeans的未来将变得扑朔迷离。 

Tony Baer确信相对于JDeveloper来说,NetBeans将变成二等公民了: 

对于NetBeans来说,玩玩还是没问题的,Oracle中间件领导 Thomas Kurian将NetBeans

定义为“轻量级的开发环境”;但如果真的想为 Oracle 平台开发企业级应用,那还得

使用 JDeveloper,JDeveloper 主要面向的是 Oracle 的 ADF 框架,后者则是 Oracle 数据

库、中间件及各种应用的根基。这与 Oracle 对 BEA Eclipse 开发工具所持有的态度是

一样的。事实上,令我们感到惊讶的是 Oracle 并没有草草地将 NetBeans 解决掉并免

费送给别人——比如捐献给 Apache 或是其他开源组织。 

“ 

Stephen O'Grady也持有同样的观点:Oracle并不打算在Sun的IDE上做太多投资: 

声明中提到了 NetBeans 以及 OpenOffice.org,我们推测 Oracle 并不打算在这个时候就

干掉他们。是的,他们还会留存于世,不过将要退居二线了,把头把交椅让给

JDeveloper。 “ 

GlassFish 

Oracle 产品开发高级副总裁 Thomas Kurian 说到,Oracle 将会继续支持 Sun 的 Web 应用服务

器,但这么做仅仅是一种部门解决方案,Oracle 自己的 WebLogic Server 将继续担当企业解

决方案的角色。 

Stephen O'Grady觉得Oracle将不会再资助GlassFish了: 

“根据 Oracle 所述,GlassFish 将变成参考实现。除此之外,Oracle 并没有承诺其他任

何东西。早上有人对我说,Oracle 并没有为 GlassFish 安排任何销售团队和市场部门,

和 MySQL 的下场一样。这里有两种解读方式:首先,如评论所说,“Oracle 认为捆绑 

36 

 

Page 44: Architect 201003-by-info q

 

销售 GF+WLS 将会获得更多的机会,进而满足不同项目的需求”。另一方面,Oracle

认为捆绑销售产品会破坏其 WebServer 产品线,因此会通过组织的变更慢慢地将

GlassFish 扼杀掉。WebLogic 销售的那帮家伙怎么会推出一个更便宜的 WebLogic 替代

品呢? 

Cloud 

Oracle 首席架构师 Edward Screven 说到,Oracle 并不会支持 Sun 规划许久的 Cloud 服务。Sun

此前宣布将通过 Sparc 刀片服务器、应用于 x64 刀片服务器的 Xeon 与 Opteron 处理器以及

开源的产品 ZFS 和 Crossbow 开发出 Amazon 风格的云,提供计算和存储服务并支持 Sparc 和

x64 机器上的 Linux、Windows 和 Solaris。 

Sun 的 Cloud initiative 计划最初是用于网格计算的(Network.com),后来没有吸引多少客户,

结果在 Cloud 的背景下被淘汰掉了。 

Stephen O'Grady对Oracle不支持Sun Cloud的结果给出了自己的看法: 

众多客户都不再需要虚拟或是物理设备了,这有利于提供所谓的最佳架构。尽管

Ellison 非常讨厌 Cloud,但 Cloud 还是有其用武之地的。Ellison 讨厌 Cloud 的原因在

于他认为 Cloud 并不是什么新玩意儿。Cloud 不过是通过网络交付价值的数据库和中

间件而已。公平的说,他的观点还是有一定价值的,尤其在当今这个世界上,厂商不

断地抛出“Cloud”这个词儿,好像它马上就要过时了一样。换句话说,从大众拥抱 Cloud

这个事实以及“Cloud”术语所暗示的那样,无论你认为 Cloud 是新东西还是老古董都无

所谓,至少它简化了设备的销售。我想说的是,Oracle 并没有过多地谈及 Cloud,但

这并不意味着 Cloud 已死,只不过是 Ellison 对 Sun 业务的未来规划而已。 

 

Sun 的很多开源项目都没有达到预先的期望,无论从竞争力还是回报角度来说都是如

此,他们将不得不面临退出历史舞台的命运结局。Oracle 是一个更加注重利润的公司,

这一点要远远超过 Sun,单凭这一点,那些没什么搞头的开源项目也将面临着停业谢

客的结局。 

 “

Open Source 

由于 Sun 过去曾在开源产品开发与开源社区建设等方面投入了大量的资源,因此人们普遍认

为 Oracle 的此次收购对开源是个巨大的打击。 

37 

 

Page 45: Architect 201003-by-info q

 

来自RedMonk的Stephen O'Grady对Sun开源社区的前景也持悲观的态度: 

坦率地说,Oracle的声明并没有过多地提到开源。单词open倒是出现了不少,但 source

却并没有一同出现。从宏观角度来看,我认为这会对开源社区造成消极的影响,因

为此次收购是从一个非常注重开源的公司到对开源并不是那么热衷的公司的转变。

但实际上,我觉得有必要一个一个地谈谈这些开源社区,就拿 Java 来说吧,它肯定

没什么问题。Oracle 的举措定会让 Java 社区欢天喜地。但 MySQL 注定要成为一个孤

独的人了,而 OpenSolaris 的命运则充满了变数。 

“ 

来自ZDNet的Dana Blankenhorn也认为Oracle的这种做法会对开源社区造成非常消极的影响: 

Oracle 掌握着任何开源业务底层代码的版权,他的名声注定了利润最大化才是

来自Re Sun那样对开源运动进行大量投入了

现在

追求的唯一目标:圈地、拉拢客户这些事情 Oracle 都干的出来。此次收购有一点值

得我们关注:Oracle 不再支持个人或是小公司可以通过社区的形式迎战业界巨头的做

法了,因此那些巨头会轻松将你击垮。 

dMonk的Michael Coté觉得Oracle不会再像

“ 

: 

裁员 

就Sun去年的裁员一事,Oracle CEO Larry Ellison说到,未来几个月内,公司还将裁员不到 2,000

取利润)关注 LAMP、开源、“lesscode”这些东西的。Ellison 对 Java 的态度还是非常

友好的:Java 并不需要直接为公司创造利润,它只要能为整为公司的其他业务添砖加

瓦就够了。Oracle 相信其“闭源”的产品(Oracle DB、WebLogic 等)要“好过”那些开源

的对手(MySQL、GlassFish 等),只要开源产品不搞出什么麻烦出来,那就没什么事。 

“ 

非你有预算并确实需要高性能的硬件和中间件,否则 Oracle 是不会(就是为了赚

人,同时还会再招聘 2,000 多人从事工程、销售和其他业务。当然了,他并没有排除未来还

会继续裁员的可能。Ellison又补充到,他希望Sun CEO Jonathan I. Schwartz能够自觉离开公司,

并希望Sun的联合创建者与主席Scott G. McNealy能够留下来,但头衔和职位还没有确定。

Jonathan Schwartz在Twitter中提到其最后一篇博客是“likely his last blog at Sun”。 

读者可以观看Webcast来了解Oracle与Sun的产品策略。 

还在访问Sun网站的各位读者朋友,是不是已经发现了什么变化呢? 

译者的话:在翻译完这篇新闻后,心情久久不能平静,一个伟大的技术公司就这样倒下了,

难道这真的是“纯技术”公司的宿命么?公司的目标都是获取利润,而 Oracle 则将这一理念发

38 

 

Page 46: Architect 201003-by-info q

 

挥到了极致:凡是与利润不相干的一律干掉,原文用“ruthlessly profit focused”来形容 Oracle

对利润的渴求。当然了,对利润的追逐本身无可厚非,可能我还是太傻太天真:‐)。再也看

不到 Sun 的首页了,感觉 Oracle 的首页给人一种冷冰冰的感觉。 

InfoQ的各位读者,您想对Sun说些什么呢?发表在这里吧,我们想倾听各位的心声。 

Sun再一次将 Java 之父 James Gosling 博文中的图片发布在这里,以悼念年仅 28 岁的伟大的

公司。 

 

文链接: http://www.infoq.com/cn/news/2010/02/sunset原  

:OSGi现状

相关内容: 

Bundle.update  

日 NetBeans社区庆祝十周年生  

Java SE 5 服务周期已终结 

Amazon RDS: 作为云服务的MySQL数据库 

亚马逊开始提供MySQL服务 

39 

 

Page 47: Architect 201003-by-info q

 

 

热点新闻    News

MonoTouch已支持Apple iPad 

作者Abel Avram  译者  张龙 

就在Apple发布iPad平板电脑 24 小时后,MonoTouch团队就发布了MonoTouch 1.9(alpha),

该版本致力于辅助.NET开发者编写iPad应用。 

近日Apple发布了万众期待的平板电脑iPad以填平移动设备(比如移动电话)与笔记本之间

的沟壑。iPad看起来像是放大了的iPod Touch,和上网本也有类似之处,但有一个重要的区

别:iPad没有外置鼠标和键盘,输入只能通过多点触摸实现,这意味着单击、双击和右键变

成了敲、捏以及捻这三个动作。 

使用Mono创建iPad应用的方式类似于iPhone;MonoTouch包含了iPhone SDK,该SDK也支持

iPad。值得注意的是:虽然从理论上来说,我们可以在Windows或是Linux上开发iPad应用,

但实际上,Mac OS X Leopard或是Snow Leopard系统还是必备的,因为目前iPad Simulator(

件模拟器)和Interface Builder(用于构建UI的可视化工具)只能运行在Mac上。除此之外,

Apple要求MonoTouch团队

只能在安装了iPhone SDK的电脑上安装MonoTouch。这意味

者只能使用Mac开发环境。完整的要求列举如下: 

着开发

运行 Mac OS X 10.5 或 10.6 的 Intel Mac 计算机   

Apple iPhone SDK 3.2   

最新的 Mono   

MonoTouch 1.9 Alpha   

MonoDevelop 2.2.1(该项虽不是强制要求,但对开发却很有帮助)   

目前通过 iPhone SDK 所创建的应用还无法同时运行在 iPhone 和 iPad 上,但不久之后就可以

了,同样 MonoTouch 也将增加相应的支持。 

iPhone开发的限制(当然也适用于iPad了)包括:有限的泛型支持、由于缺少iPhone OS的支

持所导致的无法进行动态代码生成、不能进行远程访问、无COM绑定、无JIT。MonoTouch

40 

 

Page 48: Architect 201003-by-info q

 

包含很多基础的程序集,但没有一个是与客户端界面相关的,这样就无法使用Silverlight、

WPF或是WinForms创建界面了,而只能使用基于Apple Cocoa Touch的Interface Builder。 

InfoQ上的文章MonoTouch: .NET Development for the iPhone可以作为iPad的开发指南,因为无

论是iPhone还是iPad使用的都是同样的iPhone SDK。 

原文链接:http://www.infoq.com/cn/news/2010/02/MonoTouch‐iPad 

相关内容: 

Mono发布了面向Visual Studio的工具包 

Mono C#编译器进入一个新的里程碑 

Mono迈上新台阶:Mono 2.6、MonoDevelop 2.2 和Moonlight 2 发布 

MacRuby 0.5 Beta增加JIT、AOT、GCD支持,删除GIL 

MonoDevelop正式迈入跨平台时代 

41 

 

Page 49: Architect 201003-by-info q

我们的使命:成为关注软件开发领域变化和创新的专业网站

我们的定位:关注高级决策人员和大中型企业

我们的社区:Java、.NET、Ruby、SOA、Agile、Architecture

我们的特质:个性化RSS定制、国际化内容同步更新

我们的团队:超过30位领域专家担当社区编辑

……

讨 论 组:groups.google.com/group/infoqchina编辑电邮:[email protected]广告合作:[email protected]

时刻关注企业软件开发领域的变化与创新

每日要闻

迷你书

企业软件开发

深度文章

视 频

Page 50: Architect 201003-by-info q

 

 

推荐文章    Articles

类加载器特技:OSGi代码生成 

作者Todor Boev 译者 曹云飞   

把大型系统移植到 OSGi 架构上常常意味着解决复杂的类加载问题。这篇文章专门研究了面

向这个领域最难问题的几个框架:有关动态代码生成的框架。这些框架也都是些超酷的框架:

AOP 包装器,ORM 映射器以及服务代理生成器,这些仅仅是一些例子。 

我们将按照复杂性增加的顺序考察一些类加载的典型问题,开发一小段代码来解决这些问题

中最有趣的一个。即使你不打算马上写一个代码生成框架,这篇文章也会让你对静态定义依

赖的模块运行时(如 OSGi 系统)的低级操作有比较深入的了解。 

这篇文章还包括一个可以工作的演示项目,该项目不仅包含这里演示的代码,还有两个基于

ASM 的代码生成器可供实践。 

类加载地点转换 

把一个框架移植到OSGi系统通常需要把框架按照extender模式重构。这个模式允许框架把所

有的类加载工作委托给OSGi框架,与此同时保留对应用代码的生命周期的控制。转换的目标

是使用应用bundle的类加载来代替传统的繁复的类加载策略。例如我们希望这样替换代码:

ClassL

 

oader appLoader = tContextClassLoader();

s("com.acme.devices.SinisterEngine");

Loader appLoader = ...

s("com.acme.devices.SinisterEngine");

Thread.currentThread().ge

Class appClass = appLoader.loadClas

...

Class

Class appClass = appLoader.loadClas

替换为: 

42 

 

Page 51: Architect 201003-by-info q

 

Bundle appBundle = ...

.acme.devices.SinisterEngine");

美而正确的

载应用代码的标准方式,我们在此对其多说两句。当前

Class appClass = appBundle.loadClass("com

尽管我们必须做大量的工作以便 OSGi 为我们加载应用代码,我们至少有一种优

方式来完成我们的工作,而且会比以前工作得更好!现在用户可以通过向 OSGi 容器安装/

卸载 bundle 而增加/删除应用。用户还可以把他们的应用分解为多个 bundle,在应用之间共

享库并利用模块化的其他能力。 

由于上下文类加载器是目前框架加

OSGi没有定义设置上下文类加载器的策略。当一个框架依赖于上下文类加载器时,开发者需

要预先知道这点,在每次调用进入那个框架时手工设置上下文类加载器。由于这样做易于出

错而其不方便,所以在OSGi下几乎不使用上下文类加载器。在定义OSGi容器如何自动管理上

下文类加载器方面,目前有些人正在进行尝试。但在一个官方的标准出现之前,最好把类加

载转移到一个具体的应用bundle。 

适配器类加载器 

class BundleClassLoader extends ClassLoader {

delegate) {

erride

s<?> loadClass(String name) throws dException {

我们可以把这个适配器传给转换的框架代码。随着新 bundle 的增减,我们还可以增加

有时候我们转换的代码有外部化的类加载策略。这意味着框架的类和方法接收明确的

ClassLoader  参数,允许我们来决定他们从哪里加载应用代码。在这种情况下,把系统转换

到 OSGi 就仅仅是让 Bundle 对象适配 ClassLoader API 的问题。这是一个经典的适配器模式的

应用。 

public

private final Bundle delegate;

public BundleClassLoader(Bundle

this.delegate = delegate;

}

@Ov

public ClasClassNotFoun

return delegate.loadClass(name);

}

}

现在

43 

 

Page 52: Architect 201003-by-info q

 

bundle 跟踪代码来创建新的适配器  ——  例如,我们可以“在外部”把一个 Java 框架适配到

OSGi,避免浏览该框架的代码库以及变换每个单独的类加载场所。下面是将一个框架转换到

使用 OSGi 类加载的示意性的例子: 

...

Bundle app = ...

appLoader = new BundleClassLoader(app);

viceSimulationFramework simfw = ...

erEngine", appLoader);

桥接类加载器 

许多有趣的 Java 框架的客户端代码在运行时做了很多花哨的类处理工作。其目的通常是在

例如,一个传递给应用代码的服

LIB)产生。一旦

的方法。我们必须找到一个好方法来调用

  ‐  增强类从框架和应用 bundle 混入类,这种加载类的方式对于 OSGi 容器

BundleClassLoader

De

simfw.simulate("com.acme.devices.Sinist

...

应用的类空间中构造本不存在的类。让我们把这些生成的类称作增强(enhancement)。通

常,增强类实现了一些应用可见的接口或者继承自一个应用可见的类。有时,一些附加的接

口及其实现也可以被混入。 

增强类扩充了应用代码  -  应用可以直接调用生成的对象。

务代理对象就是这种增强类对象,它使得应用代码不必去跟踪一个动态服务。简单的说,增

加了一些 AOP 特征的包装器被作为原始对象的替代品传递给应用代码。 

增强类的生命始于字节数组 byte[],由你喜爱的类工程库(ASM,BCEL,CG

我们生成了我们的类,必须把这些原始的字节转换为一个 Class 对象,换言之,我们必须让

某个类加载器对我们的字节调用它的 defineClass()方法。我们有三个独立的问题要解决: 

类空间完整性  ‐  首先我们必须决定可以定义我们增强类的类空间。该类空间必须“看到

足够多的类以便让增强类能够被完全链接。   

可见性  ‐ ClassLoader.defineClass()是一个受保护

它。   

类空间一致性

来说是“不可见的”。作为结果,增强类可能被暴露给相同类的不兼容的版本。   

44 

 

Page 53: Architect 201003-by-info q

 

类空间完整性 

增强类的背后支持代码对于生成它们的 Java 框架来说是未公开的  ‐  这意味着该框架应该会

把该新类加入到其类空间。另一方面,增强类实现的接口或者扩展的类在应用的类空间是可

见,这意味着我们应该在这里定义增强类。我们不能同时在两个类空间定义一个类,所以我

们有个麻烦。 

因为没有类空间能够看到所有需要的类,我们别无选择,只能创建一个新的类空间。一个类

空间等同于一个类加载器实例,所以我们的第一个工作就是在所有的应用 bundle 之上维持

一个专有的类加载器。这些叫做桥接类加载器,因为他们通过链接加载器合并了两个类空间: 

public class BridgeClassLoader extends ClassLoader {

private final ClassLoader secondary;

public BridgeClassLoader(ClassLoader primary, ClassLoader secondary) {

super(primary);

}

@Override

protected Class<?> findClass(String name) throws ClassNotFoundException {

return secondary.loadClass(name);

}

}

现在我们可以使用前面开发的 BundleClassLoader: 

/* Application space */

Bundle app = ...

ClassLoader appSpace = new BundleClassLoader(app);

/*

* Framework space

* We assume this code is executed inside the framework

*/

ClassLoader fwSpace = this.getClass().getClassLoader();

45 

 

Page 54: Architect 201003-by-info q

 

/* Bridge */

ClassLoader bridge = new BridgeClassLoader(appSpace, fwSpace);

这个加载器首先从应用空间为请求提供服务  ‐  如果失败,它将尝试框架空间。请注意我们

仍然让 OSGi 为我们做很多重量工作。当我们委托给任何一个类空间时,我们实际上委托给

了一个基于 OSGi 的类加载器  ‐  本质上,primary 和 secondary 加载器可以根据他们各自

bundle 的导入/导出(import/export)元数据将加载工作委托给其他 bundle 加载器。 

此刻我们也许会对自己满意。然而,真相是苦涩的,合并的框架和应用类空间也许并不够!

这一切的关键是JVM链接类(也叫解析类)的特殊方式。对于JVM链接类的工作有很多解释: 

简短的回答:JVM 以一种细粒度(一次一个符号)的方式来做解析工作的。 

的描述。它只

 

冗长的回答:当 JVM 链接一个类时,它不需要被连接类的所有引用类的完整

需要被链接类真正使用的个别的方法、字段和类型的信息。我们直觉上认为对于 JVM 来说,

其全部是一个类名称,加上一个超类,加上一套实现的接口,加上一套方法签名,加上一套

字段签名。所有这些符号是被独立且延迟解析的。例如,要链接一个方法调用,调用者的类

空间只需要给类对象提供目标类和方法签名中用到的所有类型。目标类中的其他许多定义是

不需要的,调用者的类加载器永远不会收到加载它们(那些不需要的定义)的请求。 

正式的答案:类空间 SpaceA 的类 A 必须被类空间 SpaceB 的相同类对象所代表,当且仅当:

SpaceB存在一个类B,在它的符号表(也叫做常量池)中引用着A。   

OSGi 容器已经将 SpaceA 作为类 A 的提供者(provider)提供给 SpaceB。该联系是建立

在容器所有 bundle 的静态元数据之上的。   

例如:假设我们有一个 bundle BndA 导出一个类 A。类 A 有 3 个方法,分布于 3 个接口中: 

 BndB,其有一个类 B。类 B 中有一个引用  A a = ……和一个方法调

IX.methodX(String)   

IY.methodY(String)   

IZ.methodZ(String)   

还假设我们有一个 bundle

用 a.methodY("Hello!")。为了能够解析类 B,我们需要为 BndB 的类空间引入类 A 和类 String。

这就够了!我们不需要导入 IX 或者 IZ。我们甚至不需要导入 IY,因为类 B 没有用 IY ‐  它只

用了 A。在另一方面,bundle BndA 导出时会解析类 A,必须提供 IX,IY,IZ,因为他们作为

被实现的接口直接被引用。最终,BndA 也不需要提供 IX,IY,IZ 的任何父接口,因为他们

也没有被直接引用。 

46 

 

Page 55: Architect 201003-by-info q

 

现在假设我们希望给类空间 BndB 的类 B 呈现类空间 BndA 的类 A 的一个增强版本。该增强

须桥接的不是框架和应用空间,而是框架空间和增强类的空间  ‐  所以,我们

k the app to resolve the target class */

.loadClass("com.acme.devices.SinisterEngine");

*/

idge(targetSpace);

ClassLoaderCache {

eference<ClassLoader>> cache;

类需要继承类 A 并覆盖它的一些或全部方法。因此,该增强类需要看到在所有覆盖的方法

签名中使用的类。然而,BndB 仅当调用了所有被覆盖的方法时才会导入所有这些类。BndB

恰好调用了我们的增强覆盖的所有的 A 的方法的可能性非常小。因此,BndB 很可能在他的

类空间中不会看到足够的类来定义增强类。实际上完整的类集合只有 BndA 能够提供。我们

有麻烦了! 

结果是我们必

必须把策略从“每个应用空间一个桥”变为“每个增强类空间一个桥”。我们需要从应用空间到

一些第三方 bundle 的类空间做过渡跳接,在那里,应用导入其想让我们增强的类。但是我

们如何做过渡跳接呢?很简单!如我们所知,每个类对象可以告诉我们它第一次被定义的类

空间是什么。例如,我们要得到 A 的类加载器,所需要做的就是调用 A.class.getClassLoader()。

在很多情况下我们没有一个类对象,只有类的名字,那么我们如何从一开始就得到 A.class?

也很简单!我们可以让应用 bundle 给我们它所看到的名称“A”对应的类对象。然后我们就可

以桥接那个类的空间与框架的空间。这是很关键的一步,因为我们需要增强类和原始类在应

用内是可以互换的。在类 A 可能的许多版本中,我们需要挑选被应用所使用的那个类的类

空间。下面是框架如何保持类加载器桥缓存的示意性例子: 

...

/* As

Bundle app = ...

Class target = app

/* Get the defining classloader of the target */

ClassLoader targetSpace = target.getClassLoader();

/* Get the bridge for the class space of the target

BridgeClassLoaderCache cache = ...

ClassLoader bridge = cache.resolveBr

桥缓存看起来会是这样: 

public class Bridge

private final ClassLoader primary;

private final Map<ClassLoader, WeakR

public BridgeClassLoaderCache(ClassLoader primary) {

this.primary = primary;

47 

 

Page 56: Architect 201003-by-info q

 

this.cache = new WeakHashMap<ClassLoader,

lic synchronized ClassLoader resolveBridge(ClassLoader

r bridge = null;

= cache.get(secondary);

(bridge == null) {

assLoader(primary, secondary);

ridge));

urn bridge;

防止保留类加载器带来的内存泄露,我们必须使用弱键和弱值。目标是不在内存中保持

点”。这是

可见性 

好的,我们终于有了自己的外来的桥接类空间。现在我们如何在其中定义我们的增强类?如

WeakReference<ClassLoader>>();

}

pubsecondary) {

ClassLoade

WeakReference<ClassLoader> ref

if (ref != null) {

bridge = ref.get();

}

if

bridge = new BridgeCl

cache.put(secondary, new WeakReference<ClassLoader>(b

}

ret

}

}

为了

一个已卸载的bundle的类空间。我们必须使用弱值,因为每个映射项目的值

(BridgeClassLoader)都强引用着键(ClassLoader),于是以此方式否定它的“弱

WeakHashMap javadoc规定的标准建议。通过使用一个弱缓存我们避免了跟踪所有的bundle

而且不必对他们的生命周期做出反应。 

前所述问题,defineClass()是 BridgeClassLoader 的一个受保护的方法。我们可以用一个公有

方法来覆盖它,但这是粗野的做法。如果做覆盖,我们还需要自己编码来检查所请求的增强

类是否已经被定义。更好的办法是遵循类加载器设计的意图。该设计告诉我们应该覆盖

findClass(),当 findClass()认为它可以由任意二进制源提供所请求类时会调用 defineClass()方

法。在 findClass()中我们只依赖所请求的类的名称来做决定。所以我们的 BridgeClassLoade

必须自己拿主意: 

48 

 

Page 57: Architect 201003-by-info q

 

这是一个对“A$Enhanced”类的请求,所以我必须调用一个叫做"A"的类的增强类生成器!然

后我在生成的字节数组上调用 defineClass()方法。然后我返回一个新的类对象。 

这段话中有两个值得注意的地方。 

我们为增强类的名称引入了一个文本协议  ‐  我们可以给我们的类加载器传入数据的单

独一项  ‐  所请求的类的名称的字符串。同时我们需要传入数据中的两项  ‐  原始类的名

称和一个标志,将其(原始类)标志为增强类的主语。我们将这两项打包为一个字符串,

形式为[目标类的名称]"$Enhanced"。现在 findClass()可以寻找增强类的标志$Enhanced,

如果存在,则提取出目标类的名称。这样我们引入了我们增强类的命名约定。无论何时,

当我们在堆栈中看到一个类名以$Enhanced 结尾,我们知道这是一个动态生成的类。为

了减少与正常类名称冲突的风险,我们将增强类标志做得尽可能特殊(例如:

$__service_proxy__)   

增强是按需生成的  ‐  我们永远不会把一个增强类生成两次。我们继承的 loadClass()方法

首先会调用 findLoadedClass(),如果失败会调用 parent.loadClass(),只有失败的时候它才

会调用  findClass()。由于我们为名称用了一个严格的协议,保证 findLoadedClass()在第二

次请求相同类的增强类时候不会失败。这与桥接类加载器缓存相结合,我们得到了一个

非常有效的方案,我们不会桥接同样的 bundle 空间两次,或者生产冗余的增强类。   

这里我们必须强调通过反射调用defineClass()的选项。cglib使用这种方法。当我们希望用户

给我们传递一个可用的类加载器时这是一种可行的方案。通过使用反射我们避免了在类加载

器之上创建另一个类加载器的需要,只要调用它的defineClass()方法即可。 

类空间一致性 

到了最后,我们所做的是使用 OSGi 的模块层合并两个不同的、未关联的类空间。我们还引

入了在这些空间中一种搜索顺序,其与邪恶的 Java 类路径搜索顺序相似。实际上,我们破

坏了 OSGi 容器的类空间一致性。这里是糟糕的事情发生的一个场景: 

1. 框架使用包 com.acme.devices,需要的是 1.0 版本。   

2. 应用使用包 com.acme.devices,需要的是 2.0 版本。   

3. 类 A 直接饮用 com.acme.devices.SinisterDevice。   

4. 类 A$Enhanced 在他自己的实现中使用了 com.acme.devices.SinisterDevice。   

49 

 

Page 58: Architect 201003-by-info q

 

5. 因为我们搜索应用空间,首先 A$Enhanced 会被链接到 com.acme.devices.SinisterDevice 

2.0 版,而他的内部代码是基于 com.acme.devices.SinisterDevice 1.0 编译的。   

结果应用将会看到诡异的 LinkageErrors 或者 ClassCastExceptions。不用说,这是个问题。 

唉,自动处理这个问题的方式还不存在。我们必须简单的确保增强类的内部代码直接引用的

是“非常私有的”类实现,不会被其他类使用。我们甚至可以为任何我们可能希望使用的外部

API 定义私有的适配器,然后在增强类代码中引用这些适配器。一旦我们有了一个良好定义

的实现子空间,我们可以用这个知识来限制类泄露。现在我们仅仅向框架空间委托特殊的私

有实现类的请求。这还会限定搜索顺序问题,使得应用优先搜索还是框架优先搜索对结果没

有影响。让所有的事情都可控的一个好策略是有一个专有的包来包含所有增强类实现代码。

那么桥接加载器就可以检查以那个包开头的类的名称并将它们委托给框架加载器做加载。最

终,我们有时候可以对特定的单实例(singleton)包放宽这个隔离策略,例如

org.osgi.framework ‐  我们可以安全的直接基于 org.osgi.framework 编译我们的增强类代码,

因为在运行时所有在 OSGi 容器中的代码都会看到相同的 org.osgi.framework ‐  这是由 OSGi

核心保证的。 

把事情放到一起 

所有关于这个类加载的传说可以被浓缩为下面的 100 行代码: 

public class Enhancer {

private final ClassLoader privateSpace;

private final Namer namer;

private final Generator generator;

private final Map<ClassLoader , WeakReference<ClassLoader>> cache;

public Enhancer(ClassLoader privateSpace, Namer namer, Generator generator) {

this.privateSpace = privateSpace;

this.namer = namer;

this.generator = generator;

this.cache = new WeakHashMap<ClassLoader , WeakReference<ClassLoader>>();

}

50 

 

Page 59: Architect 201003-by-info q

 

@SuppressWarnings("unchecked")

public <T> Class<T> enhance(Class<T> target) throws ClassNotFoundException {

ClassLoader context = resolveBridge(target.getClassLoader());

String name = namer.map(target.getName());

return (Class<T>) context.loadClass(name);

}

private synchronized ClassLoader resolveBridge(ClassLoader targetSpace) {

ClassLoader bridge = null;

WeakReference<ClassLoader> ref = cache.get(targetSpace);

if (ref != null) {

bridge = ref.get();

}

if (bridge == null) {

bridge = makeBridge(targetSpace);

cache.put(appSpace, new WeakReference<ClassLoader>(bridge));

}

return bridge;

}

private ClassLoader makeBridge(ClassLoader targetSpace) {

/* Use the target space as a parent to be searched first */

return new ClassLoader(targetSpace) {

@Override

protected Class<?> findClass(String name) throws ClassNotFoundException {

/* Is this used privately by the enhancements? */

if (generator.isInternal(name)) {

return privateSpace.loadClass(name);

}

51 

 

Page 60: Architect 201003-by-info q

 

/* Is this a request for enhancement? */

String unpacked = namer.unmap(name);

if (unpacked != null) {

byte[] raw = generator.generate(unpacked, name, this);

return defineClass(name, raw, 0, raw.length);

}

/* Ask someone else */

throw new ClassNotFoundException(name);

}

};

}

}

public interface Namer {

/** Map a target class name to an enhancement class name. */

String map(String targetClassName);

/** Try to extract a target class name or return null. */

String unmap(String className);

}

public interface Generator {

/** Test if this is a private implementation class. */

boolean isInternal(String className);

/** Generate enhancement bytes */

byte[] generate(String inputClassName, String outputClassName, ClassLoader context);

}

Enhancer 仅仅针对桥接模式。代码生成逻辑被具体化到一个可插拔的 Generator 中。该

Generator 接收一个上下文类加载器,从中可以得到类,使用反射来驱动代码生成。增强类

名称的文本协议也可以通过 Name 接口插拔。这里是一个最终的示意性代码,展示这么一个

增强类框架是如何使用的: 

...

52 

 

Page 61: Architect 201003-by-info q

 

/* Setup the Enhancer on top of the framework class space */

ClassLoader privateSpace = getClass().getClassLoader();

Namer namer = ...;

Generator generator = ...;

Enhancer enhancer = new Enhancer(privateSpace, namer, generator);

...

/* Enhance some class the app sees */

Bundle app = ...

Class target = app.loadClass("com.acme.devices.SinisterEngine");

Class<SinisterDevice> enhanced = enhancer.enhance(target);

...

这里展示的Enhance框架不仅是伪代码。实际上,在撰写这篇文章期间,这个框架被真正构

建出来并用两个在同一OSGi容器中同时运行的样例代码生成器进行了测试。结果是类加载正

常,现在代码在Google Code上,所有人都可以拿下来研究。 

对于类生成过程本身感兴趣的人可以研究这两个基于ASM的生成器样例。那些在service 

dynamics上阅读文章的人也许注意到proxy generator使用ServiceHolder代码作为一个私有实

现。 

结论 

这里展现的类加载特技在许多 OSGi 之外的基础框架中使用。例如桥接类加载器被用在

Guice,Peaberry 中,Spring Dynamic Modules 则用桥接类加载器来使他们的 AOP 包装器和服

务代理得以工作。当我们听说 Spring的伙计们在将 Tomcat适配到OSGi方面做了大量工作时,

我们可以推断他们还得做类加载位置转换或者更大量的重构来外化 Tomcat 的 servlet 加载。 

感谢 

这篇文章中的许多例子都是摘自Stuart McCulloch为Google Guice和Peaberry所写的出色代码。

工业强度的类桥接的例子请看BytecodeGen.java from Google Guice和

ImportProxyClassLoader.java from Peaberry。在那里你会看到如何处理其他方面的问题,例如

安全,系统类加载器,更好的延迟缓存和并发。谢谢Stuart! 

53 

 

Page 62: Architect 201003-by-info q

 

作者还要感谢Peter Kriens的Classy Solutions to Tricky Proxies。希望在本文中的对JVM链接的解

释对于Peter的工作有用。谢谢你Peter! 

关于作者 

Todor Boev作为ProSyst一名雇员已经在OSGi方面工作了 8 年。他热衷于将OSGi发展为JVM的

一个通用编程环境。目前他既在专职研究这一领域,又是Peaberry项目的一名贡献者。他在

rinswind.blogspot.com维护着一个博客。 

原文链接:http://www.infoq.com/cn/articles/code‐generation‐with‐osgi。 

相关内容: 

书摘与采访:依赖注入 

解耦应用与依赖注入框架 

Java EE 6 的依赖注入终于达成一致了 

模块化Java:动态模块化 

Anissa和Judy谈Glassfish的开发与测试 

54 

 

Page 63: Architect 201003-by-info q

 

 

推荐文章    Articles

模块化Java:声明式模块化 

作者Alex Blewitt 译者  宋玮 

在模块化 Java 系列文章的第 4 篇里,我们将介绍声明式模块化,描述如何定义组件并将它

们组织在一起,而无需依赖于 OSGi API 进行编程。 

前一篇文章,《模块化Java:  动态模块化》描述了如何通过使用服务(service)给应用程序带

来动态模块化特性。它们是通过输出的一个(或多个)可以在运行时被动态发现的接口而实

现的。尽管这种方式使得client和server完全解耦,但是又带来一个如何(何时)启动服务的

问题。 

启动顺序 

在彻头彻尾的动态系统里,服务不仅可以在系统运行的时候装卸,还可以以不同的顺序启动。

有时,这是个大问题:无论 A 和 B 的启动顺序如何,在系统达到就绪状态并准备好接收事

件之前,如果没有事件(或线程)出现,那么哪个服务先启动都无大碍。 

可是,有很多情况都不符合这一简单假设。经典的例子就是 logging:  通常,服务在启动和做

其他操作的时候,就要连接并开始写日志了。如果日志服务此时还不可用,那会有什么后果? 

假定服务在运行时能够动态装卸,client 应该能够应对服务不存在时的情况。在这种情况下,

它也许能聪明地转移到另一种机制(如输出到标准输出),或者处于阻塞状态等待服务可用

(对 logging 系统来说不是好的答案)。可是,让服务启动之前就可用是不切实际的。 

启动级别 

OSGi 提供了一种机制来控制 bundle 启动时的顺序,即使用启动级别(start levels)。这一概

念是基于 UNIX 运行级别的概念:系统以级别 1 启动,然后单调递增,直到达到目标启动级

别。每个 OSGi 容器都提供了不同的默认目标级别:Equinox 默认值是 6;而 Felix 是 1。 

55 

 

Page 64: Architect 201003-by-info q

 

启动级别可被用来创建 bundle 间的启动顺序,让关键 bundle 服务(比如 logging)的启动级

别比那些需要用它的 bundle 更低。可是因为可  用的启动级别值是有限的,而且安装程序倾

向于选择单一数字作为启动级别,因此它并不能确保你仅通过启动顺序就能解决问题。 

另一点值得注意的是,具有相同启动级别的 bundle 是各自独立启动的(可能并行),因此,

如果你有一个与 log 服务具有相同启动级别的 bundle,谁也不能保证 log 服务能够在需要的

时候已经就绪。换句话说,启动级别可以解决大部分问题,但不能解决所有问题。 

声明式服务 

解决这一问题的一个方案是 OSGi 的声明式服务(以下称为 DS——declarative services)。用这

一方法,各个组件是由外部 bundle 将他们组织在一起并决定他们什么时候可用。声明式服

务是通过在一个 XML 配置文件组织在一起的,文件中描述了需要(消费)或提供什么服务。 

在上篇文章最后一个例子中,我们使用ServiceTracker去获得服务,如果必要则需等待服务可

用。如果我们把创建shorten命令延迟到shortening服务可用之后会很有用。 

DS 定义了一个组件(component)概念,其是比 bundle 更细粒度的概念,但是比服务的概

念粒度更大一些(因为一个组件可以消费/提供多个服务)。每个组件都有一个名字,对应一

个 Java 类,并可以通过调用该类的方法使其激活或失效。与 OSGi Java API 不同,DS 允许用

纯 Java POJO 来开发组件,根本不需要从程序上依赖 OSGi。其附带的好处是让 DS 更加易于

测试和模拟(test/mock)。 

为了说明这一方法,我们将继续使用前面的例子。我们需要两个组件:一个是 shortening 服

务本身,另一个是调用它的 ShortenComand。 

第一项任务是用 DS 配置并注册 shorten 服务。我们可以让 DS 在服务启动时注册它,而不是

通过 Bundle‐Activator 注册该服务。 

那么 DS 怎么知道要激活并连接谁呢?我们需要给 Bundle 的 Manifest 头增加一个条目,其指

示了一个(或多个)XML 组件定义文件。 

Bundle-ManifestVersion: 2

...

Service-Component: OSGI-INF/shorten-tinyurl.xml [, ...]*

这个  OSGI‐INF/shorten‐tinyurl.xml 组件定义文件内容如下: 

<?xml version="1.0" encoding="UTF-8"?>

56 

 

Page 65: Architect 201003-by-info q

 

<scr:component name="shorten-tinyurl" xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">

<implementation class="com.infoq.shorten.tinyurl.TinyURL"/>

<service>

<provide interface="com.infoq.shorten.IShorten"/>

</service>

</scr:component>

当 DS 处理这一组件时,其效果与代码context.registerService( com.infoq.shorten.IShorten.class.getName(), new 

com.infoq.shorten.tinyurl.TinyURL(), null );基本一样。Trim()服务需要类似的声明,在下面的源

代码中包含着这部分内容。 

如果需要的话,一个单一组件可以基于不同接口提供多个服务。一个 bundle 也可以包含多

个组件,使用相同或不同的类,每个都提供不同的服务。 

消费服务 

要消费该服务,我们需要修改 ShortenCommand,这样它就绑定到 IShorten 服务的一个实例

上: 

package com.infoq.shorten.command;

import java.io.IOException;

import com.infoq.shorten.IShorten;

public class ShortenCommand {

private IShorten shorten;

protected String shorten(String url) throws IllegalArgumentException, IOException {

return shorten.shorten(url);

}

public synchronized void setShorten(IShorten shorten) {

this.shorten = shorten;

}

57 

 

Page 66: Architect 201003-by-info q

 

public synchronized void unsetShorten(IShorten shorten) {

if(this.shorten == shorten)

this.shorten = null;

}

}

class EquinoxShortenCommand extends ShortenCommand {...} 

class FelixShortenCommand extends ShortenCommand {...} 

注意,不像上一次,这次没有对 OSGi API 产生依赖;mock 一个实现来检验其是否工作正常

也很轻松。那个 synchronized 修饰符确保了在服务 get/set 时不会产生竞争情况。 

为了告诉 DS 需要把 IShorten 服务实例绑定到我们的 EquinoxShortenCommand 组件上,我们

需要定义其所需的服务。当 DS 实例化你  的组件时(用默认构造器),它将通过调用定义在

bind 属性里的方法(setShorten())来设置 IShorten 服务。 

<?xml version="1.0" encoding="UTF-8"?>

<scr:component name="shorten-command-equinox" xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">

<implementation class="com.infoq.shorten.command.EquinoxShortenCommand"/>

<reference

interface="com.infoq.shorten.IShorten"

bind="setShorten"

unbind="unsetShorten"

policy="dynamic" cardinality="1..1"

/>

<service> <provide interface="org.eclipse.osgi.framework.console.CommandProvider"/> </service>

</scr:component>

无论 bundle 的启动顺序如何,一旦 IShorten 服务可用,该组件就将被实例化并连接到这个

服务。有关策略(policy)、基数性(cardinality)和服务(service)的内容在下一节再做解释。 

58 

 

Page 67: Architect 201003-by-info q

 

策略和基数性 

策略(policy)可被设为 static 或 dynamic。static 策略表示一旦设置,服务不会变化。如果

服务不可用了,组件也就失效了;如果一个新服务出现,那么就创建一个新的实例,并将该

服务重新绑定。这显然比我们就地更新服务要费劲得多。 

使用 dynamic 策略,当 IShorten 服务改变时,DS 将对新服务调用 setShorten(),随后对老服

务调用 unsetShorten()。 

DS 在 unset 之前调用 set 的原因是维持服务持续性。如果替换服务时先调用 unset,shorten

服务就有可能短暂为 null。这也就是为什么 unset 方法还带个参数,而不是把服务设置为 null

的原因。 

服务的基数性(cardinality)默认为 1..1,其可取下列值之一: 

0..1  可选的,最多 1 个   

1..1  强制的,最多 1 个   

0..n  可选的,多个   

1..n  强制的,多个   

如果不满足基数性(例如,设置为强制,但是没用 shortening 服务),那么组件是失效的。

如果需要多个服务,那么每个服务都调用一次 setShorten()。相反,对每个要卸载的服务都

要调用 unsetShorten()。 

这里并没有展示组件在进入运行状态时对每个实例进行定制的能力。 

在 DS 1.1 里,组件元素也有 activate 和 deactivate 属性,在组件激活(启动)和失效(停止)

过程中相应方法被调用。 

最后,这一组件还提供一个CommandProvider服务的实例。这是一个Equinox特定的服务,允

许提供控制台命令,而这以前是在bundle的Activator中实现的。这种模式的好处是,只要依

赖服务可用,CommandProvider服务将自动被发布;除此之外,代码本身不需要依赖任何OSGi 

API。 

还需要针对Felix特定实现采用类似解决方案;因为到目前为止,OSGi command shell还没有

标准。OSGi RFC 147是一个正在进行中的规范,允许命令在不同控制台执行。我们的例子源

代码中包含了shorten‐command‐felix组件的完整定义。 

59 

 

Page 68: Architect 201003-by-info q

 

启动服务 

上面所述方法让我们可以以任何顺序供给(及消费)shortening 服务。一旦 command 服务

启动了,它将绑定到可用的最高优先级的  shortening 服务上;或者,如果没有指定优先级,

则绑定到拥有最低服务级别的服务上。我们现在不去考虑次高优先级服务随后是否应该被启

动,而是继  续使用目前已绑定到的服务。可是,如果服务卸载,我们就要重新绑定,以维

持最高优先级 shortening 服务对 client 不会中断。 

为运行这个例子,这两个平台都需要下载并安装一些额外的 bundle: 

Felix   

Config Admin (org.apache.felix.configadmin‐1.2.4.jar)   

SCR Declarative Services (org.apache.felix.scr‐1.2.0.jar)   

Equinox:   

org.eclipse.equinox.ds   

org.eclipse.equinox.util   

org.eclipse.osgi.services   

截止目前,你应该已经熟悉安装和启动bundles的过程了;如果没有,请参考静态模块化那

篇文章。我们需要安装上述bundle,以及我们的shortening服务。下面是在Equinox环境下的

操作过程,其中bundle放在/tmp目录下: 

$ java -jar org.eclipse.osgi_* -console

osgi> install file:///tmp/org.eclipse.osgi.services_3.2.0.v20090520-1800.jar

Bundle id is 1

osgi> install file:///tmp/org.eclipse.equinox.util_1.0.100.v20090520-1800.jar

Bundle id is 2

osgi> install file:///tmp/org.eclipse.equinox.ds_1.1.1.R35x_v20090806.jar

Bundle id is 3

osgi> install file:///tmp/com.infoq.shorten-1.0.0.jar

Bundle id is 4

osgi> install file:///tmp/com.infoq.shorten.command-1.1.0.jar

60 

 

Page 69: Architect 201003-by-info q

 

Bundle id is 5

osgi> install file:///tmp/com.infoq.shorten.tinyurl-1.1.0.jar

Bundle id is 6

osgi> install file:///tmp/com.infoq.shorten.trim-1.1.0.jar

Bundle id is 7

osgi> start 1 2 3 4 5

osgi> shorten http://www.infoq.com

...

osgi> start 6 7

osgi> shorten http://www.infoq.com

http://tinyurl.com/yr2jrn

osgi> stop 6

osgi> shorten http://www.infoq.com

http://tr.im/HCRx

osgi> stop 7

osgi> shorten http://www.infoq.com

...

当我们安装并启动我们的依赖后(包括 shorten 命令),shorten 命令仍不能在控制台显示结

果。只有当我们启动针对 shorten 命令所注册的 shortening 服务时才行。 

当地一个 shortening 服务停止时,实现自动转移至第二个 shortening 服务。第二个服务也停

掉的话,shorten command 服务则自动清除注册。 

注意 

声明式服务让连接 OSGi 服务更加容易。可是还有几点需要注意。 

DS bundle需要安装并启动,以把组件连接起来。这样,DS bundle作为OSGi框架启动部分

的一部分来安装,比如Equinox的osgi.bundles或Felix的felix.auto.start。   

DS 通常有其他依赖需要安装。以 Equinox 为例,要包括 equinox.util bundle。   

声明式服务是OSGi Compendium Specification的  一部分,而不是核心规范的一部分,因

此对于服务接口通常需要由一个独立的bundle提供。在Equinox环境下,是由osgi.services

61 

 

Page 70: Architect 201003-by-info q

 

提  供,但在Felix环境下,接口由SCR(Service Component Registry——服务组件注册)

bundle自身输出。   

声明式服务可以用properties来配置。通常利用OSGi Config Admin服务;尽管这是可选的。

因此DS的有些部分需要运行Config Admin;实际上,Equinox 3.5 有一个bug,如果要用

Config Admin,它需要在DS(Declarative Services)之前启动。这往往要求使用start‐up  属性,

以确保满足正确的依赖。   

OSGI‐INF 目录(与 XML 文件一起)需要被包含进 bundle 中,否则 DS 看不到它。你还需

要确保 Service‐Component 头在 bundle 的 manifest 中存在。   

还可能要用 Service‐Component: OSGI‐INF/*.xml 来包含所有组件而不是逐个罗列其名字。

这也允许 fragment 给一个 bundle 增加新组件。   

bind和unbind方法需要synchronized以避免潜在的竞争情况出现,尽管在Atom

之上使用

icReference

compareAndSet()还可以被用作单个服务的non‐synchronized占位符。   

DS 组件不需要 OSGi 接口,这样,它可以在其他控制反转模式(如 Spring)里被模拟来

XML命名空间;DS 1.1  增加了 

测试或使用。可是 Spring DM  和 OSGi Blueprint 服务都可用来组织服务,这就留作将来

的话题吧。   

DS 1.0  没有定义默认的

http://www.osgi.org/xmlns/scr/v1.1.0命名空间。如果文件

其兼容DS 1.0。   

中没有出现命名空间,就认为

总结 

本文中,我们讨论了如何将我们的实现与 OSGi API 解耦,并使用哪些组件的声明式描述。声

的 OSGi 服务层以便通信。因此,一

明式服务提供了组织组件和注册服务的能力,帮助避免启动顺序依赖。另外,动态本质意味

着当我们的依赖服务起停时,组件/服务也随之起停。 

最后,无论使用 DS 还是手动管理服务,都使用的是相同

个 bundle 可以通过手动方法提供服务,另一个可以用声明式服务来消费它(反之亦然)。我

们应能够混合并匹配 1.0.0 和 1.1.0 实现,并且它们应能透明地工作。 

本文所讲例子的可安装 bundle 罗列如下(包含源代码): 

com.infoq.shorten‐1.0.0.jar   

com.infoq.shorten.command‐1.1.0.jar   

62 

 

Page 71: Architect 201003-by-info q

 

com.infoq.shorten.tinyurl‐1.1.0.jar   

com.infoq.shorten.trim‐1.1.0.jar   

原文链接:http://www.infoq.com/cn/articles/modular‐java‐declarative‐modules 

pdate:NetBeans与OSGi

相关内容: 

Bundle.u  

at及企业级Java的未来 Rod Johnson谈Spring、OSGi、Tomc  

Intellij IDEA 9:Java EE 6、OSGi、Flex及更多 

SpringSource 宣布将 dm Server 移交给 Eclipse.org、Virgo 项目将基于 EPL 协议 

Bundle.update:模块化的一年 

63 

 

Page 72: Architect 201003-by-info q

 

 

推荐文章    Articles

加密因特网 

作者 Satyajit Grover, Xiaozhu Kang, Michael Kounavis andFrank Berry  译者  马国耀 

因特网的发展带来了企业或个人之间大量的信息交换。信息本身既包含公共信息也包含私有

信息,而且大部分信息是以非安全的方式通过超文本传输协议(HTTP  )进行传输的。而少

量信息是通过 HTTP 之上的安全套接字层(SSL)进行传输的,即 HTTPS。HTTPS 是一种安全

的密码协议,它在 HTTP 之上提供了加密和消息认证的功能。SSL 的引入大大提高了服务提

供者的流通处理的成本,其原因是有时需要投资昂贵的终端加速设备。在本文中,我们将展

示新技术并显示出使用通用硬件完成大量 HTTPS 传输的实惠。我们的方法分成三段,首先,

介绍新 CPU 指令,展示如何使用它们大大加速基本密码操作,包括对称加密和消息认证。

其次,展示 RSA 算法的新软件实现的结果,它加速了 HTTPS 协议中的另一个计算密集的部

分,也就是公钥加密。第三,展示如何在一个支持  SMT(并发多线程)技术的处理器上均

衡 Web 服务器及公钥密算法之间的负载,从而提高 Web 服务器的效率。最后,我们展示这

些先进技术能够为 Web 服务提供强大工具,为它们在 HTTP 之上的所有传输大大降低 HTTPS

实施成本。 

介绍 

到 2009 年 1 月为止,因特网大约连接了 625,000,000 台主机。这些主机之间每秒钟都要进

行海量的信息交换,这些数据包含公共信息也包含私有信息,而私有信息往往是机密的并需

要受到保护。为信息提供保障的安全协议往往使用在银行和电子商务中,而因特网上的私有

信息通常并未受到保护。这些私有信息(除银行和电子商务之外的)包括个人邮件、即时消

息、(在网络中)出现、位置、视频流、查询及各种在线社区网络的交互等等,这种忽视主

要从经济因素考虑的。安全协议依赖于密码算法,而这些算法都是计算密集的。最后,保护

私有信息还要求在线服务的提供者在计算资源上进行很大投入,本文中展示的新技术能够降

低在线安全交互的成本,因此可以作为大量服务的选择。 

HTTP之上很多私有数据都是以不安全的方式进行传输的。HTTP位于 TCP/IP协议栈的应用层,

64 

 

Page 73: Architect 201003-by-info q

 

SSL(Secure Sockets Layer  ,安全套接字层)以及后来的 TLS  (Transport Layer Security,传

输层安全)都是应用层上的安全技术。在文本中,我们只谈论 HTTP 层的 SSL/TLS,也就是

HTTPS。由于先前的 Web 服务器硬件无法处理高流量的 HTTPS 传输中所增加的密码算法的开

销,HTTPS 的引入大大提高了 Web 服务提供者处理传输的成本。为了处理这些高流量传输,

Web 服务提供者不得不增加昂贵的 SSL/TLS 终端加速设备,这些附加的成本使得 HTTPS 成为

Web 服务提供者的一个备选(或者是高级)方案。结果,大量私有信息的传输都是不安全

地进行的,所以,在传输过程中可能被篡改或截获。本文将展现一些新技术,为该问题提供

解决的一个途径并显示使用当前的通用硬件完成高流量的 HTTP 传输已成为可能。 

本文的组织结构 

我们旨在降低已启用了 SSL 的 HTTP 负载的解决方案分成三段。第一,我们讨论了新的处理

器指令,并演示了如何使用他们实现基本密码操作的成倍的提速,这极大地降低了 HTTPS

中大规模数据传输时的服务器负载。第二,我们展现了 RSA 非对称密码算法的新实现的结果,

它提升了 HTTPS 协议中计算最密集阶段的处理:即,服务器对大量客户端发过来的握手消

息进行解密的阶段(下一节描述了 HTTPS 的握手过程的几个阶段)。第三,我们分析了 Web

服务器,分析显示,通过使用了 SMT 技术的处理器均衡 Web 服务器的负载和密码算法的负

载可以提高其性能,基于此,我们展示了将密码运算与长延迟时间的内存访问并行执行就能

掩盖密码处理所消耗的时间。 

随后,我们详细阐述了无处不在地部署 HTTPS 的动机及愿景。首先,我们深入研究了 SSL

过程及其所需资源,然后描述了我们的三段式策略,实验及结果。 

动机 

我们的研究背后的动机主要是使得 HTTPS 的广泛使用及访问成为可能。这为服务提供者和

用户之间建立互信互赢的关系至关重要。信任的一个重要方面来自于他们了解私有沟通是机

密的,并且依附于提供者和用户之间建立的原则之上。对于用户,有必要告知并辅导他们,

HTTPS 对于在线沟通隐私的益处所在。而服务提供者应该广泛采用 HTTPS 以确保他们能遵守

自己的承诺。使用并不昂贵的投资实现 HTTPS 对于创建这样的关系非常重要。 

HTTPS 为数据私密及认证提供了一个端到端的解决方案。它保证了当用户从他们的设备向服

务提供者传送消息时,他们的消息不会被中间人窃听到。由于任何时间在因特网上传输的消

息包都是在不安全的网络上进行的,所以以上保证极为重要。尽管大部分路由设备能躲过直

65 

 

Page 74: Architect 201003-by-info q

 

接观察,但是躲不过蓄意窃听者。而那些可公开访问的遍布全球的无线访问点更容易被偷听,

这些访问点向他们管理的所有设备广播信息。如果没有端到端的安全解决,这些交互很容易

被网络邻居窃听。对于安全问题,还有其他解决办法,比如三层虚拟私有网络(VPN),但

是 VPN 往往仅限于中心管理的网络,在这样的网络中用户与其他用户的交互都经过网络中

心,即多用户单提供者。在这种情况下,网络提供者已经通过培训的方式向用户传达了严格

的数据私密及安全方面的策略。比如,企业内的电子邮件通常仅能通过企业管理的 VPN 进

行访问。对于更大的因特网,用户与许多提供者连接。此外,近些年我们看到有利于 HTTP

协议的现象——很多其他交互协议(如 FTP)使用的下降。在这种情况下,HTTPS 是在数量

巨大并不断增长的用户和提供者之间提供私密又安全的交互最可行的途径。 

将来,HTTPS 的应用可能包括广泛的电子邮件加密、视频流安全、即时消息安全及网络搜索

的加密等,这些 HTTPS 的应用在目前并不广泛。此外,一年又一年用户放到网络上的个人

私有信息越来越多。云计算使得他们可以在任何地点通过各种设备访问他们的信息。我们相

信用户要求他们的提供者用 HTTPS  来保护他们的所有交互是不可避免的。出于为那一天做

准备,我们研究和开发了本文中描述的技术。我们展望,有了这些增强,在今天由任何设备

发出的基于  HTTP 的交互在不久的将来都可以基于 HTTPS,我们把这称为无处不在的 HTTPS 

(“https://everywhere”)。 

安全套接字层(SSL)会话剖析 

安全套接字层 

安全套接字层(SSL,其后来版本称为传输层安全 TLS)包含了一个握手阶段和加密数据交换

阶段。图 1 展示了 SSL 握手的整个过程。在图中,第一阶段,  握手过程开始,客户端向服

务端发送一组它可以支持的算法列表和一个随机数,该随机数用作密钥生产过程的输入之

一。 

66 

 

Page 75: Architect 201003-by-info q

 

 

图 1 安全套接字(SSL)握手(来源:Intel 公司,  2009) 

第 2 阶段,服务端选择其中的一个加密算法回送给客户端,附带包含该服务器公钥的证书,

证书用于证明服务器的身份。顺便提一下,服务器的域名也可以通过证书进行校验(这样可

以消除钓鱼站点)并向用户表明他们正在与正确的服务端(或服务)进行交互。另外,服务

端还提供了第二个随机数,该随机数也作为密钥生成过程的输入之一。第 3 阶段,客户端验

证服务端的证书并提取出服务器的公钥。然后,客户端产生一个随机的秘密字符串并使用服

务器的公钥对它进行加密,机密后的字符串被称为预主密钥,它被发送给服务器。第 4 阶段,

服务器通过 RSA 算法对客户端发过来的加密串进行解密,这是 SSL 交互过程中服务器上的计

算最重的过程之一。随后,客户端和服务端各自产生他们的会话密钥,生成密钥的过程中使

用预主密钥调用密钥生成函数(key derivatioin function,KDF)两次(该过程中使用了第 1,

2 阶段的随机数)。在第 5 和第 6 阶段,SSL 握手以交互双方向对方发送认证码而结束,认证

码由所有原始握手消息计算而成。 

在 SSL 中,数据以记录的方式传输。记录协议将数据流分解成一组数据段,每一段单独被保

护并传输。换言之,在 IPSec 中,数据是以一个 IP 包为基础进行保护的,而在 SSL 中,数据

67 

 

Page 76: Architect 201003-by-info q

 

以段为单位进行保护。在段被传输之前,通过计算消息的认证码进行信息保护。段认证码附

加在段内容后面,形成消息负载并用服务器(在第 2 阶段)选择的加密算法进行加密。最后,

在此负载上加上消息头,消息头与加密的消息体合起来形成记录。 

安全的 web 服务器显然是一个极耗内存的应用,对于 SSL 连接而言,其最显著的部分就与密

码算法相关,包括使用对称密钥进行包加密、提供消息认证支持以及通过 RSA 建立会话(前

文已述)。下面的章节中,我们将更为详细地描述本文中要加速的两个加密算法:高级加密

标准(Advanced Encryption Standard,AES)及 RSA(Rivest Shamir Adleman)。 

高级加密标准和RSA算法 

高级加密标准 

AES 是美国政府的对称加密算法标准,它定义在 FIPS  出版物第#197 (2001) [2, 3]中并广泛应

用在具有高吞吐量,高安全需求的应用中。在 HTTPS 中,它可用于为因特网上传输的信息

提供机密性。AES 是一个对称加密算法,也意味着在加密和解密消息的时候,使用的是相同

的密钥。AES 的结构如图 2 所示: 

 

图 2 AES 的结构(来源:Intel 公司,2009) 

AES 首先将密钥(可能是 128 位,192 位或 256 位)扩展成密钥排序表,密钥排序表由 128

字节的轮密钥构成,轮密钥用于加密过程中。加密过程本身就是一组被称为 AES 轮的数学转

换的演化。 

在每个 AES 轮中,输入数据(input)首先与密钥排序表中的其中一个轮密钥进行异或运算。

异或运算也可以看成是没有进位的加法。 

在该轮加密的下一步,每个 16 字节的 AES 状态经过 S 盒的非线性转换被替换成另一值。AES

的 S 盒包括两个阶段,第一阶段是反转,它不是正常整数算法,而是基于 GF(28)的有限

68 

 

Page 77: Architect 201003-by-info q

 

域算法。第二个阶段是仿射变换。在加密过程中,输入的 x 被看成 GF(8)上的元素,  即

一个 8 比特向量,它先被反转,然后对反转的结果应用仿射图。在解密的过程中,输入 y

先通过反向仿射图,然后在 GF(8)中反转。  前面提到的 GF(8)反转是在 GF(28)中进

行的,它是由不可约多项式定义的,即 p(x) = x8 + x4 + x3 + x + 1  或者  0x11B。 

然后,被替换的字节值经过两个线性转换,分别是 ShiftRow 和 MixColumn。ShiftRow 仅仅做

字节置换,MixColumn 转换操作在 AES 状态的矩阵表示的列上进行。每一列由一个矩阵乘法

得到的值进行替换,加密过程中所使用的转换如方程 1 所示,在该方程中,根据 GF(28)

的规则进行矩阵与矢量的乘法,使用的是 S 盒中相同的不可约多项式,即是,i>p (x) = x8 + x4 

+ x3 + x + 1。 

 

解密过程中,反向 ShiftRow 跟在反向 MixColumn 之后,反向 MixColumn 转换的如方程 2 所

示。 

 

注意到 MixColumn 转换用 1,1,2 和 3 与每列中的字节相乘,而方向 MixColumn 用的则是

0x9, 0xE, 0xB, and 0xD。根据密钥大小(128,192,256 比特)的不同,相同的过程要进行

10,12,或 14 轮。最后一轮 AES 省略 MixColumn 转换。 

RSA 算法 

RSA 是一种公钥密码算法设计。公钥算法背后的主要想法是加密技术可以有后门的存在。后

门的意思是指,密码只需要交互的一方知道,这样可以简化加密流程。在公钥算法中,消息

通过公钥加密,而一个公钥对应一个私钥。在不知道私钥的情况下,很难解密消息,类似地,

攻击者也很难发现信息原文。 

为了进一步解释公钥算法,我们以 RSA 算法做例子来说明。在该算法中,交互双方选择两个

随机的大数 p 和 q,为了安全的最大化,  p 和 q 长度应该相同,然后交互双方如下计算: 

69 

 

Page 78: Architect 201003-by-info q

 

 

对于某些 l,D 和 E 可以互换使用,也就是说可以使用 D 加密,而使用 E 进行解密。 

RSA 的典型实现使用中国剩余理论,它可以将一个模数的取幂运算减低成对长度是它的一半

的两个数的取幂操作,以此类推,通过使用平方乘的技术可以将取幂操作化解成模数平方及

模式乘运算的序列。平方乘运算还可以增强,并使用某些视窗法降低模数乘运算的次数。最

后,模数平方和乘运算可以通过如  Montgomery 或 Barrett [4, 5]这样的简约算法简化成大数

的乘法运算。 

加速技术 

我们正在研究成倍提升 HTTPS 会话速度的方法来实现加密因特网的愿景。下一代微系统结

构新增的指令可能会将对称加密算法提速 3‐10 倍。这些指令不仅提供了更好的性能,还能

保护应用免受边道攻击(side‐channel attack)的威胁。其次,我们已开发出改进的整数运算

软件,它可以将密钥交换及构造过程提速达 40‐100 倍。 

70 

 

Page 79: Architect 201003-by-info q

 

第三,Intel® Core™ i7 微体系结构再次将 SMT 技术引进 CPU 中,对于将计算密集的公钥加密

软件的运算周期隐藏在网络应用内存查找的延迟时间内 SMT 是非常理想的。 

新处理器指令 

下一代 Intel 处理器将引入一组新指令,它们将支持高性能及安全的轮加密和轮解密。这些

指令是 AESENC(AES 轮加密),和  AESENCLAST(AES 最后一轮加密),AESDEC(AES 轮解密)

以及 AESDECLAST(AES 最后一轮解密)。还引入了另外两个用于实现密钥排序表转换的指令,

AESIMC 和  AESKEYGENASSIST。 

这些新处理器指令的设计基于 AES 的结构。AES 这样的系统包括复杂的数学操作,比如有限

域乘法与反转[6](前文已述)。这些操作用软件实现需要消耗更多的时间及内存,但是用组

合逻辑实现时则更快,且更加节能。另外,有限域操作的操作数能够适合 IA 体系结构的 SIMD

寄存器。本文中,我们讨论使用组合逻辑将整个 AES 轮实现为单个 IA 处理器指令的概念。

一个 AES 轮指令比等同的基于表查找的软件程序要快很多,并且可以流水化,所以有可能在

一个时钟周期内计算出一个独立的 AES 轮的结果。 

这些 AES 指令可以看成是密码算术的原语,它们不仅可用于 AES 的实现,还可以用于广泛的

密码算法。例如,最近的 HIST SHA‐3 哈希函数竞赛中就有不少提案使用了 AES 轮作为计算密

码哈希值的基础元件。另外,指令调用的合并还可以用于创建更加通用的有限域计算的原语。

这些新指令在相同的平台上与最好的软件实现相比,在处理相同的数学操作的情况下要快

3‐10 倍。 

与这些 AES 指令一起,Intel 将提供另一个新指令用于支持无进位乘法(carry‐less 

multiplication),称为 PCLMULQDQ。该指令执行两个 64 位四个字的无进位乘法运算。这两

个操作数是根据中间字节值选择出来的第一和第二个乘数。 

无进位乘法,又称为 Galois 域(GF)乘法,在该操作中对两个数进行相乘是不产生和传递

进位。在标准的整数乘法中,第一个操作数移动的次数等于第二个操作数中值为“1”的比特

位的个数,每次移动的距离就是“1”在第二个操作数中的位置。两个数的执行结果由所有移

动后的第一个操作数相加而来的。在无进位乘法中,过程依然相同,但是相加时不产生进位

也不传递进位。这样,比特加操作就相当于逻辑操作中的异或(XOR)。 

无进位乘法是很多系统和标准(包括时钟冗余校验,CRC,Galois/计数模型,GCM 和二进制

椭圆曲线等)的计算的一个非常重要的组件,该操作在当今处理器上用软件实现时效率极为

低下。所以,加速 Carry‐less 乘法的指令对于 GCM 和所有依赖于它的交互协议[8]来说相当

重要。 

71 

 

Page 80: Architect 201003-by-info q

 

改进的密钥构造软件 

我们还开发了整数算法软件  ,他至少可加速大数乘以及模数减运算达 2 倍。这些程序不仅

用于 RSA 公钥加密,还可用于 Diffe Hellman 密码交换以及椭圆曲线密码算法(ECC)。使用

了我们的软件在 Intel® Core i7 处理器上 RSA 1024 的性能可以从大概每秒处理 1500 个签名

(OpenSSLv.0.9.8g)或者 2000 个签名(OpenSSL v.0.9.8.h)提升到每秒 2900 个签名。类似地,

我们还可以加速其他流行的密码模式,如 RSA 2048、和基于 NIST B‐233 曲线的椭圆曲线加密

Diffie‐Hellmn。 

RSA 的性能可以通过提升大数乘法的速度而提升,因为它是该算法中计算最密集的部分。我

们的实现使用了优化的背包大数相乘算法。RSA 算法是计算非常密集的算法,它要消耗数百

万的时钟用于执行 64 位数的乘法,加法和减法。然而,RSA 所存储的状态却很小,只包含

一些关键信息及 16 至 32 个能够放入  Intel CPU 的一级缓存(cache)中的乘数。使用了我们

的软件,RSA 1024 解密操作在 Intel® Core i7 处理器上只消耗了 99 万时钟,而相应的 RSA 2048

解密操作消耗了 673 万时钟。这个速度比 OpenSSL(v. 0.9.8h)执行相同操作要快 40%。 

下图中列出的代码描述了主要思想,它通过对中间数(check)利用寄存器回收技术将乘法

和加法操作合并起来。在代码 1 中,“a”和“b”保存了相乘的两个大数,结果存在“r”中。这些

操作对所有输入不断重复,并产生中间数,这些中间数相加后得到大数相乘的结果。 

72 

 

Page 81: Architect 201003-by-info q

 

 

代码 1 RAS 实现(来源:Intel 公司,2009) 

我们还研究了其他大数相乘的技术,包括类 Karatsuba 构造,但是我们发现这个背包算法实

现是最快的[9,10]。 

并发多线程技术 

最新的 Intel® Core i7 微体系结构再次引入了超线程(现在被称为并发多线程或 SMT)的技术。

SMT 是该处理器与此前的核心微体系结构的最大差别,因为这些核心都是单线程的。作为研

究的一部分,我们演示了 SMT 可以为一类特定的工作负载带来根本性性能提升,这些工作

负载与安全 Web 事务相关。我们提出了一种新的编程模型  ——使用一个计算密集的线程只

进行 RSA 公钥加密操作,另一线程进行内存存储密集的操作。我们发现当使用 SMT 时,RSA

线程可以作为四个典型的内存存储密集的工作线程的理想伙伴,并可以带来 10%至 100%的

潜在性能提升。 

73 

 

Page 82: Architect 201003-by-info q

 

当执行独立内存查找的线程与 RSA 线程相伴执行时系统可获最多益处。内存线程的吞吐率几

乎翻倍,达到了没有 RSA 伴随情况下的值。对该结果的另一种解释是  RSA 计算几乎没有消

耗时间,这都功因于 SMT。在现实中,RSA 计算被隐藏在内存线程的长延迟时间期间。我们

还观察到当 SMT 开启,当一个内存线程与另一个内存线程相伴执行时,单个内存线程的吞

吐量大约提高了 30%,而当与 RSA 算法相伴执行时,吞吐率翻倍。这些结果指明 RSA 算法

比第二个内存线程更适合作为陪伴线程,原因是一个工作是内存访问密集型,而另一个是计

算密集型。当一个 RSA 线程与一个内存线程相伴执行时,SMT 开启时 RSA 的性能比 SMT  关

闭时性能提升 21%[11]。 

为了进一步验证我们的观点——SMT 特别有助于密码工作负载,我们创建测试了一个运行

SpecWeb* 2005 的测试台。测试台的组成是一台 Intel® Core i7 处理器的服务器,连接到两台

客户机,在上面一共运行了四个客户端引擎。我们测量了 SMT 开启和关闭时的服务器处理

的 Banking(HTTPS)和  Support(HTTP)工作负载的能力。实验表明 SMT 对整体系统性能至少提

升了 10%,而 Banking 工作负载比 Support 工作负载提高的更多。该结果与我们前面的实验

相吻合,并且也表明了密码工作负载也能利用 SMT 的优势。 

我们的密码算法加速技术的整体影响如图 3 所示,第一栏是 230K 字节的 SSL 交易运行在今

天的 Intel® Core i7 处理器上的负载。加密模式使用了 AES‐256 的反模式(counter mode)。第

二栏显示了使用新指令实现 AES 时获得的加速效果。第三栏展示了使用我们的 RSA 软件及

SMT 之后的加速结果。最后一栏展示了将 SHA1 替换成 GCM 后的结构。GCM 是一种提供了

与 HMAC‐SHA1 相同功能的消息认证模式。在图中可以明显看到,我们的加速技术从根本上

减低了密码工作负载并带来了性能及效率显著提高。 

 

图 3  密码加速技术的影响(来源:Intel 公司,2009) 

74 

 

Page 83: Architect 201003-by-info q

 

结论 

总之,Intel 正在研究提供成倍提升密码算法速度的新技术。我们描述了可以提升 AES 对称

加密速度的新处理器指令,该提升从根本上减低了 HTTPS 处理大块数据传输时的服务器负

载。我们还展现了 RSA 非对称密码算法的新实现,它加速了 HTTPS 协议的计算密集型阶段,

即服务器必须解密来自大量客户端的握手消息的阶段。第三,我们分析了 Web 服务器并展

示了一些初期实验,结果表明,通过在支持 SMT 技术的处理器上均衡 Web 服务器负载和密

码算法负载可以提升服务器的效率,它显示了密码算法负载可以隐藏在并行处理的内存访问

的长时间延迟期间。我们的最终目标是使通用处理器能够高速处理及转发加密的信息传输,

从而让因特网逐步转变成为完全安全的信息交付基础设施。我们还相信这些技术有益于其他

使用模型,比如硬盘加密和存储等。 

参考 

[1] R.L. Rivest, A. Shamir, and L. M. Adleman. “A Method for Obtaining Digital Signatures and Public‐Key Cryptosystems.” Communications of the ACM, 21,2, pages 120–126, February 1978. 

[2] V. Rijmen. “Efficient Implementation of the Rijndael S‐box.” At http://www.google.com 

[3] “Advanced Encryption Standard.” Federal Information Processing Standards Publication 197. At http://csrc.nist.gov 

[4] P. Montgomery. “Multiplication without trial division.” Math. Computation, Volume 44, pages 519—521, 1985. 

[5] P. Barrett. “Implementing the Rivest Shamir and Adleman Public Key Encryption Algorithm on a Standard Digital Signal Processor.” Masters Thesis, University of Oxford, UK, 1986. 

[6] S. Gueron, O. Parzanchevsky and O. Zuk. “Masked Inversion in GF(2n) Using Mixed Field Representations and its Efficient Implementation for AES.” Embedded Cryptographic Hardware: Methodologies & Architectures. Nadia Nedjah and Luiza de Macedo Mourelle (Editors), Nova Science Publishers, Inc.(ISBN: 1‐59454‐012‐8), 2004. 

[7] S. Gueron. “Advanced Encryption Standard (AES) Instructions Set.” At: http://software.intel.com/ 

[8] S. Gueron and M. Kounavis. “Carry‐Less Multiplication and Its Usage for Computing the GCM Mode.” At http://software.intel.com/ 

[9] A. Karatsuba and Y. Ofman. “Multiplication of Multidigit Numbers on Automata.” Soviet Physics—Doklady, Volume 7, pages 595–596, 1963. 

[10] M. E. Kounavis. “A New Method for Fast Integer Multiplication and its Application to Cryptography.” In Proceedings 2007 International Symposium on Performance Evaluation of Computer and Telecommunication Systems. San Diego, CA, 2007. 

75 

 

Page 84: Architect 201003-by-info q

 

[11] S. Grover and M. Kounavis. “On the Impact of Simultaneous Multithreading on the Performance of Cryptographic Workloads.” Technical Report, available from the authors upon request. 

本文及更多类似的主题可以在Intel技术期刊,2009 年六月版的“因特网安全的提升”一文中找

到。更多信息请参考http://intel.com/technology/itj。 

关于作者 

Satyajit Grover 是一个 Intel 实验室的软件工程师。日常工作涵盖安全和完整性(integrity)。

在 Intel,他在这个领域已经有工作两年多。在此之前他是 Portland 州立大学的计算机科学系

的研究生及助理研究员。他的邮箱是 atyajit.grover at intel.com。 

Xiaozhu Kang 是 Intel 实验室的研究科学家。她的研究兴趣包括算法设计和性能分析。她在

2008 年获得 Columbia 大学电子工程学的博士学位,并与 2009 年 1 月加  入 Intel。在此之前

她曾是 Intel,Mathworks 及 NEC 实验室的实习生。她的电子邮箱是 xiaozhu.kang at intel.com。 

Michael Kounavis 是 Intel 实验室的高级研究科学家。他负责主持旨在提升广泛的客户端、服

务端以及网络应用速度的新型数字算法及密码算法。Michael 是 CRC32 SSE4 指令的合作发明

者,该指令用于 iSCSI CRC 时代的 Intel® Core i7 体系结构中。由于 AES 指令方面的工作,他

还是 2008 Intel 成就奖的共同获奖者。他的电子邮箱是 michael.e.kounavis at intel.com。 

Frank Berry 是 Intel 实验室的首席工程师。他所专长的领域是硬件/软件接口,即硬件和软件

紧密连接之处。此外,他的专长还包括操作系统内核,设备驱动程序,网络协议栈等。Frank

在 InfiniBand 体系结构及 AES 指令方面的工作为他赢得了两次 Intel 成就奖。他的电子邮箱是 

frank.berry at intel.com。 

原文链接: http://www.infoq.com/cn/articles/encrypt‐internet‐intel 

相关内容: 

雅虎将Traffic Server捐献给Apache基金会 

Java上的Aptana Cloud Connect 

网络安全:采访Intel安全与加密经理David Durham 

Intel把Silverlight移植到Moblin上 

在Windows Azure中保证数据安全的几点建议 

76 

 

Page 85: Architect 201003-by-info q

 

 

推荐文章    Articles

SOA访谈和书摘:Eben Hewitt的新书《Java SOA 

Cookbook》 

作者 Srini Penchikala  译者  胡键 

Eben Hewitt的新书《Java SOA Cookbook》从Java实现的角度讨论了面向服务架构(SOA)主

题。在这本书中,Eben讨论了SOA模型基础,如何使用Web服务来实现它,工具和最佳实践。

全书采用“问题‐解决方案‐讨论”的写作风格,共分 4 个部分: 

SOA 基础   

Web 服务   

业务流程   

互操作性和服务质量   

作者在讨论的开始介绍了XML Schema和SOA数据模型,以及如何使用Java API来处理XML文

档。在讨论使用诸如JAX‐WS和SAAJ这样的API来创建Web服务应用时,作者也给出了相应的

代码示例。 

Web服务在实现SOA架构(使用以SOAP为基础)和RESTful架构风格中的作用也在本书中进行

了讨论。RESTful Web服务的例子包括:使用Servlet创建一个“使用HTTP来传输普通XML文档

(Plain Old XML (POX) document over HTTP)”服务,使用JAX‐WS创建一个RESTful服务,以及

使用Jersey容器来安装JAX‐RS实现。 

本书第 9 章讨论了如何使用BPEL来进行服务编配,BPEL引擎采用的是Apache ODE。本章一些

高级的编配用例包括:并行执行活动,并行执行活动的同步,在特定点按时执行活动,在特

定延迟之后执行活动,选择性事件处理,以及给业务流程增加人工任务。 

本书还讨论了其他主题,如SOA治理,讨论涉及确定服务的数据所有权模式,服务文档化,

77 

 

Page 86: Architect 201003-by-info q

 

以及安装服务注册库。本书最后讨论了企业服务总线(ESB),ESB在SOA实现中的作用,Java

业务集成(JBI),以及商业(Oracle Service Bus、Software AG/webMethods ESB和TIBCO 

BusinessWorks)及开源(Mule、Apache ServiceMix和OpenESB)ESB容器。 

InfoQ 就本书、主要的写作动机和其他主题对 Eben 进行了采访。本次访谈中涉及的一些主题

有: 

SOA 在企业架构中的作用   

敏捷和精益软件开发环境下的 SOA 实现   

SOA 实现框架和工具   

同时,我们从《Java SOA Cookbook》节选了样章(SOA治理章节;1,353 KB PDF)供读者下载

试读。 

InfoQ:《Java SOA Cookbook》背后的主要写作动机是什么? 

Eben Hewitt(EH):我撰写《Java SOA Cookbook》是为了帮助 Java 开发者写出 SOA 架构策略

建议的那种应用。随着 SOA 这些年来变得流行,有不少从“管理者指南”角度撰写的 SOA 书

籍,这些建议非常笼统、层次非常高,在读了几本这样的书之后,你会想“太好了,这就是

我想要做的”,然后坐在 IDE 前,你却写不出一行代码。我就是想消除这种断层。本书中有

几章关于 Addressing 和 MTOM 这两种 WS‐*方法的内容,但也有一章关于 REST 原则,以及

如何使用 JAX‐RS 参考实现。 

本书还包含了设计方面的内容,如哪种 XML Schema 设计模式可以帮助你实现 SOA 中可能使

用的规范数据模型(Canonical Data Model)。但这不是本书的重点。 

作为架构师,我需要去帮助我有幸与之共事的开发者去理解这些复杂的 API 如何一起使用,

从哪儿开始,哪些是需要的,哪些是可以丢掉的,以及如何处理它们的交互,用具体的方式

去帮助他们认识到 SOA 的目标。因此,本书实际是为他们而写的。书中包含了许多诸如哪

些 XML Schema 设计模式可以帮助你来实现规范数据模型,JAX‐WS 注解如何映射到 WSDL,

如何根据 Schema 进行验证,如何创建项目等内容。于是,我开始整理笔记并意识到它们需

要稍微正式一点,以便真的能帮助开发者节约时间。我把本书的想法发给了 Simon St. 

Laurent,并且很高兴看到 O'Reilly 接受了它。 

InfoQ:SOA 在企业架构(EA)领域中的作用是什么? 

EH:对于负责EA的人来说,服务组合(Service Portfolio)管理是关键。不论你是象大家近些

78 

 

Page 87: Architect 201003-by-info q

 

年来认为的SOA已死或是相反,服务仍然还是存在。值得注意的是,Open Group已经给TOGAF

增加了一个SOA模块。我认为SOA之战已经尘埃落定,该是时候让EA来考虑在实现服务之后

的下一步工作了。可能是BPM,它是个绝佳的素材;也可能是事件处理;或者要我来说,二

者都是。我可是希望鱼和熊掌可以兼得。 

当然,EA 知道 SOA 不可能解决所有事情,就像模型驱动架构不能解决所有事情一样。因此,

在我看来,SOA 在 EA 中的作用是启蒙,同时扮演服务目录管理者,创建标准,在服务设计、

开发、API、版本管理、监视等方面提供指导,然后确定你自己关于在哪些地方自动化流程

的策略,以及在事件模型中工作的方式。 

SOA 已经经历了黑格尔说的扬弃,并且现在可以只作为整体的一部分来促进新的创新。在某

些业务中,这些创新之一可能是使用服务目录来解放遗留系统的外在策略。很明显,EA 需

要对此密切关注。 

InfoQ:领域驱动设计(DDD)概念最近引起了非常多的注意。DDD 关注的是把业务领域的

概念映射到软件制品,而这正是 SOA 要完成的目标。在后台缺乏坚实的领域模型和实现的

条件下,SOA 实现是否可以成功?SOA 是否是对 DDD 的补充? 

EH:领域驱动设计的核心实际是鼓励开发者和分析师以业务的语言去关注领域,而且它可

以和其他策略合作得很好,包括 SOA。如果使用 RESTful 架构并将业务对象映射到资源,DDD

的作用尤其强大。我猜有些分析师会把这称为 WOA。 

在创建和维护 SOA 的重要组成——规范数据模型方面,DDD 同样也非常有用。因此,我显

然会对调查研究的模式谈得更多些,而对具体的面向对象模式则涉及较少。 

InfoQ:在使用诸如 Scrum、XP 和看板(Kanban)这样的敏捷和精益方法论的软件开发环境

中应该如何实现 SOA? 

EH:敏捷和 SOA 可以搭配得很好。这也是我们公司实践 SOA 的方式。它可以与 Scrum 及 XP

结合使用。看板相对较新,我还不知道有哪个团队真的在看板模型下从事 SOA 的。典型的

敏捷团队致力于单个项目,专注于把它实现,但是在 SOA 环境下,你必须关注多个项目,

这样才能发现可重用的服务。因此,作为架构师,你需要了解各项目团队目前的工作,帮助

他们看到正在做的工作何时可以写成一个服务或重用现有服务。然后,你就可以增加一个定

义服务接口的 Backlog,并对它负责,这样团队的工作就不会停顿。接着,你就可以根据业

务定义接口,书写开发者可以依赖的 API。然后,开发者在后台跟它配合,服务消费者在前

台根据它书写,大家最后在中间汇聚在一起。这似乎最大化了各方面(包括测试)并行开发

的可能,可以迅速的完成工作。在我们看来,这样的效果非常好。 

79 

 

Page 88: Architect 201003-by-info q

 

 

精益尤其是实现业务流程自动化的好方法。你对业务流程进行建模,服务实现在运行时对其

进行支持,然后使用监视工具来度量它们的效能,最后运行仿真来帮助你分析业务瓶颈所在

的。精益框架非常适合这种生命周期,我们也正开始这方面的进一步探索。 

InfoQ:你能谈谈 SOA 实现框架和工具的现状,以及在选择 SOA 框架时 SOA 架构师应该注意

的地方吗? 

EH:当然可以。我们采用的方式是从开源开始。我在 JavaOne 上已经讨论了这一主题。我可

能有点迷信标准,因此我们一开始所做的任何事情都是直接使用  XML、BPEL、JBI、XPath、

Java 等等,然后选择支持它的工具。这对我们有几个好处。首先,这可以让我们的先期投入

最少,稍作尝试,就可以得出我们的想法。这也确保了我们的教育成果可以在不同平台下得

到应用,这样,在我们想退出某一策略去尝试另一个方向时可以轻易的完成。 

最后,我们确实会需要某种在开源领域还不成熟的工具,尤其是在某些厂商对创建支持人工

任务的自动化流程和 BAM(业务活动监视)方面已经有了极好工具的情况下。如果你没有

把所有的东西都用 XML 来实现的话,生产率也可以得到大幅提高。 

不论你采用什么方法,你都需要理解厂商对 SOA 的基础愿景。很多 SOA 厂商都来自集成领

域,因此他们用适配器来支持所有这些遗留的东西,你可以在贴着  ESB 标签的礼盒中找到

PeopleSoft、JDBC 和 Exchange 它们的适配器。这暂时对厂商来说很方便,但不会让你走得长

远。有些厂商则将  SOA 视为一个事件引擎,从松耦合和分析的角度看,它对我很有吸引力。

有些则实际关注的是流程,这也很酷。除了简单地创建服务目录,要是你关注于从哪里可以

提高生产力,那其要点则在于自动化流程,因为这些模型可以被业务人员理解,而他们可以

在流程中相关步骤设置一些 KPI,然后获得生成的仪表盘来帮助他们发现业务发生的事情,

然后提高效率。 

在大公司里会有很多东西要购买,要合并。因此,一定要小心地确保供应商的稳定,所用技

术的确是统一的。不要仅因为 17 个组件的前缀都贴有相同的标签就认为它们就真的能集成

在一起。你需要做些示例,进行概念证明,看看开发人员日常使用这些工具的效果。对于这

些工具的集成进行严格验证。要是你看到技术集中的工具之间存在着大量的导入导出,或看

到大量小代码片段在开发工具中随处可见,你的问题可能就已经取得了一定进展。 

或者,你也可以选择 SOA 中每一个方面最好的工具,购买中意的 ESB,得到喜欢的 BAM,

依次类推。但等到问题出现,你可能就觉得进退两难了。 

InfoQ:你对 REST 和 SOAP Web 服务架构模型之间的对立是如何理解的?在应用中使用这两

80 

 

Page 89: Architect 201003-by-info q

 

个 SOA 模型之一或都使用时,SOA 开发者在设计和搭建架构时应该考虑哪些? 

EH:老实说,我认为这种对立完全是错误的。作为开发者或架构师,你应该在后备箱里为

二者都留出位置。它们二者都具有引人注目的特性。集成后台系统时,你需要使用 SOAP;

在集成第三方服务时,你会用到 Atom、RSS 或其他服务。在选择时,要因地适宜,根据应

用、性能需求、客户端需求等做出判断。最后,要想  SOA 取得成功,你得坚持相同的通用

原则:提供相对稳定、基于标准的接口;不要暴露实现,将之隐藏在一个抽象层之后,以保

持协议和实现独立于领域;对于诸如安全、转换和规则这样的横切点问题,使用服务;确保

消费者没有不恰当的绑定到你的模型上;创建良好的文档,包含清晰的版本管理和升级路径;

确保你知道实际运行的是哪个服务,并清楚谁正在使用你的服务。不论你是选择 SOAP 还是

REST,这些问题你都需要解决,它们才是决定你成功的关键。最后,你不会期望你的消费者

进入厨房,知道香肠是如何制造出来的。(译注:语出德国名相俾斯麦的名言:“世界上有两

样东西,你尽可以去喜欢它,但是一定不要去见识它的制作过程。其中,一个是香肠,一个

是法律。”。德国人喜欢吃香肠,却没几个人愿意去了解香肠的制作过程。因为香肠制作过

程看了实在让人倒尽胃口,甚至让人对自己至爱的香肠的卫生和美味产生怀疑,于是,以后

每次吃香肠时总是不禁浮现香肠的制作场景,不免胃口全无。慢慢地,吃香肠的嗜好就丢掉

了。) 

但它们俩并非唯一的选择。比方说,你也可以直接使用 JMS 来做很多事情,这完全取决于

你的需求。这种方式非常的快,非常的解耦,基于标准,厂商们正开始在他们的产品中使用

JMS 来传递 SOAP 消息(SOAP over JMS)。回想起来,BEA 和 Software AG 也采用了这种实现。

你可以让 JMS 和.NET 一起工作。这并不能解决所有事情,但这也是些选择。我与喜欢这种

方法的架构师们已经对此进行过讨论。 

这种论战虽然会吸引眼球,但你知道,任何语言或风格,都可能会导致好的程序和坏的程序,

这要看是什么人在使用它。读一些相关的 WS‐*规范,再读读 Roy Fielding 的博士论文,它们

可以帮助你选择最适合你的方案。但只要理解并遵循 SOA 原则,那么你将不会有什么大问

题。 

InfoQ:你对于本书和 SOA 主题还有什么其它的评论和想法吗? 

EH:《Java SOA Cookbook》是本不错的书籍,收到的反馈也很好,真是太棒了。我希望它能

对人们有帮助,可以节约他们的时间。   

就 SOA 来讲,我非常想知道它将走向何方。我想了解的是,它将如何发挥作为事件驱动架

构基础的作用,以及如何与之协同工作。事件允许松耦合,为商业智能也提供了帮助,象复

81 

 

Page 90: Architect 201003-by-info q

 

杂事件处理引擎和事件流处理这样的工具可以提供数据关联性,这将有利于解释一些难以用

传统领域方法解释的事情。那么,在接下来的数行里,我想谈一下我目前正在从事的解构软

件架构(Deconstructed Software Architecture,DSA)的概念。它与被人们接受的很多概念都

不相同。我在研究生时学习了一些哲学,尤其是解构,并经过多年观察到德里达的解构思想

在流行文化中被广泛传达错误了,但后来它们也以有趣新奇的方式在一些领域得到了应用,

从开始于 20 世纪 80 年代早期的建筑结构,到最近的厨房艺术。我认为它有很多值得我们学

习并应用到软件架构的东西。例如,在我称为 DSA 的软件架构中,强领域模型更倾向于事

件,它具有某种约束,上下文则成为一种更易变的概念。我会继续在这一领域的研究,如果

有兴趣想了解其近况,请访问 spearsource.com。 

InfoQ:非常感谢,Eben。 

原文链接:http://www.infoq.com/cn/articles/hewitt‐javasoacookbook 

相关内容: 

Java EE 6 Web Services:JAX‐RS 1.1 提供了基于注解的REST支持 

SOA语法——服务(Services)  是动词还是名词? 

使用BPM与SOA来最大化业务价值 

SOA与不相干的焦油坑 

到底谁需要BPEL? 

82 

 

Page 91: Architect 201003-by-info q

 

推荐文章    Articles

微型ORM——用VB和C#编写的动态类型OR

只有 160 行 

M,

作者 Jonathan Allen  译者  侯伯薇 

近来 ORM 变得越来越普遍,这都归于一种很具说服力的原因;它可以使开发数据库驱动的

应用程序变得更快、更省力。但是 ORM 框架都有点“固执己见”,他们期望开发者遵从特定

的规则,当规则被打破的时候就非常难以使用。最通常的规则之一就是,存储过程必须总是

返回单独的结果集,其中带有一致的列的列表。不幸的是,有很多这样的存储过程,其中返

回的数据的结果根据它自身内部逻辑的不同而不同。例如,一个存储过程可能会接受一个参

数,它表示要返回那些列,而另一个参数表示如果它包含了所有行,那么就对其进行合计。

或者存储过程的结果可能会根据某些内部的标识而不同,从而应用程序需要检查输出,从而

在运行时决定结构。 

面对已经确定了的存储过程集合,而这些存储过程并非是针对 ORM 系统所基于的静态建模

的类型所设计的,大多数.NET 开发者会转而使用 DataTable 的方法。但是有了.NET 4.0 中新

创建的对动态类型的支持,他们会产生另一个主意。如果所有一切——包括存储过程的名称、

SQL 的参数以及得到的对象——都在运行时处理会怎么样呢? 

下面是一些由 VB 和 C#编写的示例代码。你会注意到 VB 需要使用 Option Strict,而 C#大量

地使用了它的新关键字“dynamic”。 

VB 

Using con As New SqlClient.SqlConnection(connectionString)

Dim customer = con.CallSingleProc.CustomerSelect(AccountKey:=12345)

Console.WriteLine(customer.FirstName & " " & customer.LastName)

Dim orders As IList = con.CallListProc.OrderSearch(AccountKey:=12345, MinCreatedDate:=Now.AddDays(-7), MaxCreatedDate:=Now)

83 

 

Page 92: Architect 201003-by-info q

 

Dim totalValue = Aggregate order In orders Into Sum(CDec(order.TotalOrderValue))

Console.WriteLine("This customer ordered a total of $" & totalValue & " last week")

For Each order In orders

Console.WriteLine(vbTab & "Order Key: " & order.OrderKey & " Value: $" & order.TotalOrderValue)

Next

End Using

  

C# 

using (var con = new SqlConnection(connectionString))

{

var customer = con.CallSingleProc().CustomerSelect(AccountKey: 12345);

Console.WriteLine(customer.FirstName + " " + customer.LastName);

IList<dynamic> orders = con.CallListProc().OrderSearch(AccountKey: 12345, MinCreatedDate: DateTime.Now.AddDays(-7), MaxCreatedDate: DateTime.Now);

var totalValue = orders.Sum(order => (decimal)order.TotalOrderValue);

Console.WriteLine("This customer ordered a total of $" + totalValue + " last week");

foreach (var order in orders)

{

Console.WriteLine("\tOrder Key: " + order.OrderKey + " Value: $" + order.TotalOrderValue);

}

}

这看起来和一般的.NET 代码很类似,但是那些方法和属性实际上很多都不存在。下面是相

84 

 

Page 93: Architect 201003-by-info q

 

同的代码,其中突出显示了不存在的成员。 

VB 

Using con As New SqlClient.SqlConnection(connectionString)

Dim customer = con.CallSingleProc.CustomerSelect(AccountKey:=12345)

Console.WriteLine(customer.FirstName & " " & customer.LastName)

Dim orders As IList = con.CallListProc.OrderSearch(AccountKey:=12345, MinCreatedDate:=Now.AddDays(-7), MaxCreatedDate:=Now)

Dim totalValue = Aggregate order In orders Into Sum(CDec(order.TotalOrderValue))

Console.WriteLine("This customer ordered a total of $" & totalValue & " last week")

For Each order In orders

Console.WriteLine(vbTab & "Order Key: " & order.OrderKey & " Value: $" & order.TotalOrderValue)

Next

End Using

C# 

using (var con = new SqlConnection(connectionString))

{

var customer = con.CallSingleProc().CustomerSelect(AccountKey: 12345);

Console.WriteLine(customer.FirstName + " " + customer.LastName);

IList<dynamic> orders = con.CallListProc().OrderSearch(AccountKey: 12345, MinCreatedDate: DateTime.Now.AddDays(-7), MaxCreatedDate: DateTime.Now);

var totalValue = orders.Sum(order => (decimal)order.TotalOrderValue);

Console.WriteLine("This customer ordered a total of $" + totalValue + " last week");

85 

 

Page 94: Architect 201003-by-info q

 

foreach (var order in orders)

{

Console.WriteLine("\tOrder Key: " + order.OrderKey + " Value: $" + order.TotalOrderValue);

}

}

现在一些保守派会开始抱怨延迟绑定可能给他们造成的风险,比方说,程序可能会出错,但

直到运行时才会被捕获。这确实是可能的,但实际上情况不会那么坏。当我们将存储过程和

列的名称都保存在字符串中的时候,我们也会手误使用到错误的对象,从而在运行时有失败

的风险。 

为了让它生效,我们需要两样东西。第一样是从静态类型的上下文切换到动态类型上下文的

方法。对此,我们选择一组扩展方法,它们会返回“System.Object”。在 Visual Basic 中,这就

足以触发延迟绑定,但在 C#中这是不可行的。为了让 C#在两种模式之间切换,你还需要使

用 Dynamic 属性来修饰返回值。 

Public Module MicroOrm

''' <summary>

''' 调用返回标量值的存储过程

''' </summary>

''' <returns>Null 或者单值</returns>

''' <remarks> 只有第一个结果集的第一行的第一列会被返回。所有其它数据都会

被忽略。数据库的 null 被转换为 CLR 的 null</remarks>

<Extension()>

Public Function CallScalarProc(ByVal connection As SqlConnection) As <Dynamic()> Object

Return New MicroProcCaller(connection, Scalar)

End Function

''' <summary>

''' 调用返回单独对象的存储过程

''' </summary>

86 

 

Page 95: Architect 201003-by-info q

 

''' <returns>Null 或者 MicroDataObject</returns>

''' <remarks>只会返回第一个结果集的第一行。所有其它数据都会被忽略。数据

库的 null 都被转换为 CLR 的 null</remarks>

<Extension()>

Public Function CallSingleProc(ByVal connection As SqlConnection) As <Dynamic()> Object

Return New MicroProcCaller(connection, [Single])

End Function

''' <summary>

''' 调用返回一系列对象的存储过程

''' </summary>

''' <returns>每行都有一个 MicroDataObject </returns>

''' <remarks>只会返回第一个结果集。所有其它数据都会被忽略。数据库的 null

会被转换为 CLR 的 null</remarks>

<Extension()>

Public Function CallListProc(ByVal connection As SqlConnection) As <Dynamic()> Object

Return New MicroProcCaller(connection, List)

End Function

''' <summary>

''' 调用返回包含一系列对象的列表的存储过程

''' </summary>

''' <returns>包含 MicroDataObject 列表的 List。每个记录集都会有一个

list,并且给定的结果集中的每行都有一个 MicroDataObject</returns>

''' <remarks>数据库的 null 被转换为 CLR 的 null</remarks>

<Extension()>

Public Function CallMultipleListProc(ByVal connection As SqlConnection) As <Dynamic()> Object

87 

 

Page 96: Architect 201003-by-info q

 

Return New MicroProcCaller(connection, MultipleLists)

End Function

End Module

作为对比,下面是使用 C#实现的一个功能。 

public static class MicroOrm

{

public static dynamic CallSingleProc(this SqlConnection connection)

{

return new MicroProcCaller(connection, CallingOptions.Single);

}

}

为了设定基本的环境,以下是 MicroProcCaller  类的构造函数。注意,这个类被标记为 friend

(C#的内部标识符)。这样做是因为任何人都不应该声明这个类型的变量;它只是工作在动

态的上下文中。并且这个类还是暂时的;调用者不应该持有对它的引用。 

Friend Class MicroProcCaller

Inherits Dynamic.DynamicObject

Private m_Connection As SqlConnection

Private m_Options As CallingOptions

Public Sub New(ByVal connection As SqlConnection, ByVal options As CallingOptions)

m_Connection = connection

m_Options = options

End Sub

End Class

Public Enum CallingOptions

Scalar = 0

88 

 

Page 97: Architect 201003-by-info q

 

[Single] = 1

List = 2

MultipleLists = 3

End Enum

既然我们已经位于动态上下文中,那么就需要一种方式,用来将延迟绑定的方法调用转换为

对存储过程的调用。想要达到这个目的有很多种方法,但其中最简单的就是继承

DynamicObject  并重写 TryInvokeMember  方法。需要做的步骤如下: 

1. 决定这个函数是否负责管理 connection 对象的生命周期。   

2. 使用和存储过程一样的名称来创建 SqlCommand。被调用的方法的名字可以在“binder”

中找到。   

3. 由于使用 Data.SqlClient 的对存储过程的调用不支持未命名的参数,所以要确保所有的参

数都有名称。   

4. 通过对参数数组的重复使用,继续创建 SqlParameter 参数。   

5. 创建结果并将其存储在 result 参数中。(稍后将会向你展示实现的细节)   

6. 返回 true,表示方法已经成功执行了。   

Public Overrides Function TryInvokeMember(

ByVal binder As System.Dynamic.InvokeMemberBinder,

ByVal args() As Object,

ByRef result As Object) As Boolean

Dim manageConnectionLifespan = (m_Connection.State = ConnectionState.Closed)

If manageConnectionLifespan Then m_Connection.Open()

Try

Using cmd As New SqlClient.SqlCommand(binder.Name, m_Connection)

cmd.CommandType = CommandType.StoredProcedure

If binder.CallInfo.ArgumentNames.Count <> binder.CallInfo.ArgumentCount Then

89 

 

Page 98: Architect 201003-by-info q

 

Throw New ArgumentException("All parameters must be named")

End If

For i = 0 To binder.CallInfo.ArgumentCount - 1

Dim param As New SqlClient.SqlParameter

param.ParameterName = "@" & binder.CallInfo.ArgumentNames(i)

param.Value = If(args(i) Is Nothing, DBNull.Value, args(i))

cmd.Parameters.Add(param)

Next

Select Case m_Options

Case CallingOptions.Scalar

result = ExecuteScalar(cmd)

Case CallingOptions.Single

result = ExecuteSingle(cmd)

Case CallingOptions.List

result = ExecuteList(cmd)

Case CallingOptions.MultipleLists

result = ExecuteMultpleLists(cmd)

Case Else

Throw New ArgumentOutOfRangeException("options")

End Select

End Using

Finally

If manageConnectionLifespan Then m_Connection.Close()

End Try

Return True

End Function

90 

 

Page 99: Architect 201003-by-info q

 

ExecuteScalar 方法很简单,它拥有自己方法的唯一原因是要保持一致性。 

Private Function ExecuteScalar(ByVal command As SqlCommand) As Object

Dim temp = command.ExecuteScalar

If temp Is DBNull.Value Then Return Nothing Else Return temp

End Function

对于剩下的变量,调用者期望是真正的属性,或者至少看起来像属性。一种选择是基于运行

时结果集的内容自动生成代码的类。但是在运行时生成代码会耗费大量的资源,并且我们不

会从中得到太多好处,因为没有哪个调用者会通过名字来引用我们的类。因此,在保持动态

代码的模式的时候,我们选择使用原型动态对象来替换它。 

Friend Class MicroDataObject

Inherits Dynamic.DynamicObject

Private m_Values As New Dictionary(Of String, Object)(StringComparer.OrdinalIgnoreCase)

Public Overrides Function TryGetMember(ByVal binder As System.Dynamic.GetMemberBinder, ByRef result As Object) As Boolean

If m_Values.ContainsKey(binder.Name) Then result = m_Values(binder.Name) Else Throw New System.MissingMemberException("The property " & binder.Name & " does not exist")

Return True

End Function

Public Overrides Function TrySetMember(ByVal binder As System.Dynamic.SetMemberBinder, ByVal value As Object) As Boolean

SetMember(binder.Name, value)

Return True

End Function

Public Overrides Function GetDynamicMemberNames() As System.Collections.Generic.IEnumerable(Of String)

Return m_Values.Keys

End Function

91 

 

Page 100: Architect 201003-by-info q

 

Friend Sub SetMember(ByVal propertyName As String, ByVal value As Object)

If value Is DBNull.Value Then m_Values(propertyName) = Nothing Else m_Values(propertyName) = value

End Sub

End Class

由于任何类都不会依赖于这个对象,因此我们再次将其标记为 Friend(C#的 internal 修饰符)。

这还剩下三个用来管理属性的重写方法:一个用来设置属性,一个用来取得属性,还有一个

用来列出属性的名称。另外,还有一个用来使用静态类型代码初始化类的后门方法。 

Private Function ExecuteSingle(ByVal command As SqlCommand) As Object

Using reader = command.ExecuteReader

If reader.Read Then

Dim dataObject As New MicroDataObject

For i = 0 To reader.FieldCount - 1

dataObject.SetMember(reader.GetName(i), reader.GetValue(i))

Next

Return dataObject

Else

Return Nothing

End If

End Using

End Function

Private Function ExecuteList(ByVal command As SqlCommand) As List(Of MicroDataObject)

Dim resultList = New List(Of MicroDataObject)

Using reader = command.ExecuteReader

Do While reader.Read

Dim dataObject As New MicroDataObject

For i = 0 To reader.FieldCount - 1

92 

 

Page 101: Architect 201003-by-info q

 

dataObject.SetMember(reader.GetName(i), reader.GetValue(i))

Next

resultList.Add(dataObject)

Loop

End Using

Return resultList

End Function

Private Function ExecuteMultpleLists(ByVal command As SqlCommand) As List(Of List(Of MicroDataObject))

Dim resultSet As New List(Of List(Of MicroDataObject))

Using reader = command.ExecuteReader

Do

Dim resultList = New List(Of MicroDataObject)

Do While reader.Read

Dim dataObject As New MicroDataObject

For i = 0 To reader.FieldCount - 1

dataObject.SetMember(reader.GetName(i), reader.GetValue(i))

Next

resultList.Add(dataObject)

Loop

resultSet.Add(resultList)

Loop While reader.NextResult

End Using

Return resultSet

End Function

93 

 

Page 102: Architect 201003-by-info q

 

你刚刚创建的“微型 ORM”还有很大的改善空间。可能会增加的特性有:添加对输出参数的

支持;选择发送参数化的查询而不是存储过程名称;对其它数据库的支持等等。 

原文链接:http://www.infoq.com/cn/articles/MicroORM 

相关内容: 

快速计算表达式树 

Windows Workflow 4:旧瓶装新酒 

.NET 4 Beta 2 不再采用代码访问安全(CAS)模型 

Mono引入试验性C#语言扩展 

DLR的适应性编译器 

94 

 

Page 103: Architect 201003-by-info q

Java社区:企业Java社区的变化与创新

.NET社区:.NET和微软的其它企业软件开发解决方案

Ruby社区:面向Web和企业开发的Ruby,主要关注Ruby on Rails

SOA社区:关于大中型企业内面向服务架构的一切

Agile社区:敏捷软件开发和项目经理

Architecture社区:设计、技术趋势及架构师所感兴趣的话题

讨 论 组:groups.google.com/group/infoqchina编辑电邮:[email protected]广告合作:[email protected]

时刻关注企业软件开发领域的变化与创新

Java .NET Ruby SOA Agile Architecture

Page 104: Architect 201003-by-info q

 

 

新品推荐    New Products

Neo4j:基于Java的NoSQL图形数据库 

作者 Michael Hunger  译者 张龙  

在经过几年的开发后,近日 NeoTechnology 发布了基于 Java 的图形数

据库 Neo4j 1.0,它遵循着属性图形数据模型。InfoQ 有幸采访了

NeoTechnology 的 COO Peter Neubauer 以深入了解此次发布的 Neo4j

及其向开发者所提供的功能。 

原文链接: http://www.infoq.com/cn/news/2010/02/neo4j-10

Google发布.NET版YouTube SDK 

作者 Abel Avram  译者 张龙    

近日 Google 发布了.NET 版的 YouTube SDK,以此满足那些希望从.NET 或

ASP.NET 应用中以编程的方式访问 YouTube 的开发者的需要。YouTube API

构建在 Google 的 GData 协议之上,并通过 Google.GData.YouTube 命名空间

中特定的数据类对其进行了扩展。 

原文链接: http://www.infoq.com/cn/news/2010/02/YouTube‐SDK‐.NET 

Rails 3 首个Beta版发布 

作者 Mirko Stocker  译者  李明(nasi)    

Rails 3 的首个 beta 版已经发布。Rails 3 对代码进行了大规模的重写,带来了稳定的 API

和来自 Merb 的设计理念,拥有更清晰的内部实现和性能上的提升等等。InfoQ 将带您了

95 

 

Page 105: Architect 201003-by-info q

 

解 Rails 3 的变化,以及各个 Ruby 实现对它的支持情况。  

原文链接:http://www.infoq.com/cn/news/2010/02/rails-3-beta

.NET 4 的新特性:图表、SEO及可扩展的输出缓存 

作者Abel Avram译者 张龙    

即将发布的.NET Framework 4.0 拥有众多的新改进,此前 InfoQ 已经对其进行了详

尽的报道。本文将再来揭示.NET 4.0 中的 3 个新特性:图表控件、SEO 支持以及

ASP.NET 4 可扩展的输出缓存。 

原文链接:http://www.infoq.com/cn/news/2010/02/.NET-4-Charts-SEO-Cache

IronJS——面向DLR新的JavaScript编译器 

作者 Jonathan Allen译者 张龙    

由于微软逐渐放弃了 Jscript.NET,Fredrik Holmström 正致力于填平该沟壑,手段

就是通过运行在 DLR 上的现代 JavaScript 实现来达成。 

原文链接: http://www.infoq.com/cn/news/2010/02/IronJS

IronPython与IronRuby新RC版发布 

作者 Jonathan Allen  译者  张龙    

在微软宣布 DLR(Dynamic Language Runtime)时考虑过 4 种语言:

VB、Ruby、ECMAScript 以及 Python。从那以后,DLR 版本的 VB 和

ECMAScript 迟迟没有动静,而 IronRuby 和 IronPython 则迎来了主要版

本的发布。 

原文链接:http://www.infoq.com/cn/news/2010/02/Iron‐Languages‐RC 

96 

 

Page 106: Architect 201003-by-info q

 

Java EE 6:EJB 3.1 的变化引人注目 

作者 Josh Long  译者  张龙    

  EJB 3.1 秉承了 EJB 3.0 的衣钵,为我们带来了更多的惊喜。它为经典的 GoF 风格的单

例模式提供了新的支持,同时提供了 CRON 风格的调度、无接口的视图以及异步方法。 

EJB 3.1 还支持.WAR 内部署,这样就无需.EAR 文件了。 

原文链接:http://www.infoq.com/cn/news/2010/02/jee6_ejb_31 

Spring.NET 1.3:VS.NET Solution Templates、MSTest支持及Spring Integration.NET 

作者 Ryan Slobojan  译者  张龙    

近日 Spring.NET Framework 1.3 发布了。InfoQ 有幸采访了 Spring.NET 项

目的创建者与领导 Mark Pollack 以深入了解此次发布及其所带来的新特

性,同时还谈到了新的 Spring Integration.NET 项目。  

原文链接:http://www.infoq.com/cn/news/2010/02/spring‐net‐13 

97 

 

Page 107: Architect 201003-by-info q

 

      架构师年度展望 | 杨卫华

2010 年大规模技术架构的思路 

相比其他行业,IT 技术由于信息流动便捷,新技术更新非常频繁。架构师经常面临新技术及

传统方案选择的困惑。架构师应如何抓住本质构建新一代的应用?本文从几个方面提出一些

思路供架构师参考。 

编程语言 

2009 年编程语言领域也发生了不少变化。虽然架构师通常都表示编程语言并不重要,但事

实上每一次大的语言改进还是对业界产生非常大的影响,同时大部分技术团队也依赖某一两

种编程语言。下面介绍几种值得架构师关注的语言及热点。 

Erlang 近几年在并发编程与分布式领域比较受关注。2009 年 11 月 7~8 日在杭州举办了第四

次 Erlang 全国开发者大会(CN Erlounge IV)。从会议主题及参会者的讨论来看,Erlang 在 2009

年在一些先行项目中取得了不错的效果,同时 Erlang 的并发编程思想也在其他语言得到了一

些借鉴和应用。预计 2010 年 Erlang 会继续在小圈子内流行,目前业界应用 Erlang 技术最大

的障碍不是 Erlang 技术本身,而在于缺乏这方面专业人才,与 C++/Java 相比,Erlang 暂时不

具备大规模团队协同开发的条件。 

Scala 也是一门和 Erlang 类似的函数式编程语言,  由于 Scala 是基于成熟 JVM并具有丰富的周

边 library,因此相比于 Erlang 切换成本和风险都低很多。尤其是 Java 团队如果希望利用函

数式及并发编程优势的可以关注。 

2009 年 11 月,Google 发布了一种新的语言 Go,它在系统编程领域具有很多优势,如支持

goroutine 并行编程模型,支持 GC,编译速度快等。很多系统程序员表示 Go 就是他们心中

的“梦中情人”。但是由于刚推出不久的缘故,Go 还是不适合在生产环境使用,建议保持跟

进。 

在网页编程领域,PHP 仍然是 Web 页面编程语言首选。如 Facebook 谈到选择 PHP 的原因是

“开发效率高,支持快速的产品迭代”。2010 年 2 月,Facebook 开源了 HipHop 框架,在 PHP

业界引起较大的轰动。它将 PHP 编译成 C++执行,可以提高性能 50%。据 Facebook 博客上

98 

 

Page 108: Architect 201003-by-info q

 

的资料,HipHop 发布仅半年之后,Facebook 90%的 Web 服务器都用上了 HipHop。据估算,

Facebook 每月有 4000 亿页面访问,则 HipHop 承担了 3600 亿。如果节省 50%服务器的开销,

那将是非常大的节省。希望在 2010 年国内的 PHP 开发者也能充分利用 HipHop 的成果。 

Ruby 由于具有快速的开发效率,近年来在 Web 开发领域异军突起。首届中国 Ruby 大会 2009

年 5 月 21 日上海召开,Ruby 创始人 Matz 也亲自来华做了主题演讲。从大会来看 Ruby 社区

在国内已经比较蓬勃。预计在 2010 年 Ruby 会在企业应用和部分互联网 Web 应用中得到更

广泛的使用。 

存储:从Cache、数据库到分布式文件系统 

Web 2.0 的设计中,Cache 会成为一个中心元素。传统的 web 应用瓶颈通常在数据库或者应

用程序上,但是最近 Twitter 的一篇技术博客的分析,Twitter 广为人知的“鲸鱼”故障的罪

魁祸首竟然是 Memcached。因此最近技术界流传一句新的名言,“Disk is the new Tape,RAM 

is the new Disk。”意思就是说传统 SQL 存储已经像旧的磁带机一样成为应用的瓶颈,需要把

一切数据都放在内存里面才能满足新的应用需求。另一 Web 2.0 应用巨头 Facebook 也广泛

使用 Memcached,据称每秒访问量达 2 亿次以上。 

在 2009 年数据库受到 NoSQL 运动的冲击。NoSQL 是指用非关系数据库的方式来存储数据,

通常也指用 key value 方式存储。比较有名的有 Tokyo Cabinet, Redis, Cassandra 等。由于大部

分 Web 应用的需求是基于主键查询,同时业务上又常常面临更改表结构字段的需求。如果

将所有数据内容作为一个 value 字段存入,相对于 SQL 模式,使用更简洁,维护方便。在性

能上一些 key value 产品比传统的 SQL 在小数据访问性能上有一个数量级的提升。因此 key 

value 存储迅速被业界接受及采用。 

分布式文件存储也具有广泛需求,目前开源的解决方案有 HadoopFS,MogileFS 等。很多互

联网公司目前也借鉴 GFS 来开发自己分布式存储产品。 

可扩展架构:从手工切分到云服务 

LAMP 是一种经典的 Web 架构设计,他指用 Linux, Apache,MySQL,PHP 来搭建 Web 架构。

当 Web 请求量增大到单台服务器没法承载时典型解决方案是对应用服务器及数据库进行切

分。目前切分大部分是借鉴 LiveJournal 模式,由于 LiveJournal 架构设计甚至大部分源代码

都是公开的,因此在过去很多架构师设计 LAMP 扩展通常是在 LiveJournal 基础上作出改进。 

 

99 

 

Page 109: Architect 201003-by-info q

 

从 2009 年开始,由于云计算的蓬勃发展,LAMP 发生了两大变化。首先,部分原先用数据

库如 MySQL 的场合开始被 key value  存储代替。分布式的 key value 存储产品本身解决了扩

展,负载均衡,复制,数据一致性等问题。无需架构师手工编写代码解决数据过大后的分表

问题。 

另外一个变化是 PHP/Python/Java 等语言可以运行在一个 App Engine 的容器上,这个容器可

以托管一个几行代码的 hello world 项目,也可以承载上千万访问量的用户的大型项目。App 

Engine 自身具有可扩展性,容错性,负载均衡,用户可以自动访问最近的 IP 等特性。它对

于需要架构师根据业务来切分的传统做法是一种全新体验。 

在 2010 年,分布式存储及 App Engine 模式是架构师需要考虑的两大方向。 

个人简介 

杨卫华,新浪产品事业部技术经理,目前工作以开发高并发的分布式应用为主。对互联网后

端技术,分布式,网络编程,XMPP即时通讯等领域感兴趣。曾组织多次广州及珠三角技术

沙龙活动。个人blog为  http://timyang.net/  。 

100 

 

Page 110: Architect 201003-by-info q

 

      架构师年度展望 | 洪强宁

豆瓣首席架构师洪强宁的年度展望 

从我 2006 年加入豆瓣团队以来,豆瓣无论从规模上还是从架构上都发生了很大的变化,并

且看起来这个变化会越来越快,越来越激烈。从刚入职时十万级PV,到百万级PV到千万级

PV再到并不遥远的亿级PV目标,在每一个阶段,都给系统架构带来不小的挑战。2009 年 4

月份,我应泰稳和大辉的邀请在QCon大会上和大家分享了豆瓣从最初上线到当时的系统架

构变迁历程,没想到得到了很多人的关注和共鸣,从一个侧面也反映出来系统架构如何按需

而变是大家共同关注的问题。架构设计是为了解决实际问题,一切的考虑从这个出发,可以

避免无用的过度设计。 

关注性能和可用性 

2009 年,豆瓣的用户规模达到了千万级,最直接的需求是要解决数据量增加带来的性能问

题,以及作为一个有影响力的网站,可用性要求需要上一个台阶的问题。前一个问题,我们

通过对 doubandb(开源版本 beansdb 已经在 12 月份在 google code 上发布了第一个版本)

进行了进一步的性能优化(主要是哈希树的内存缓存和数据的异步读写),并对一些影响性

能的 MySQL 大表做了水平拆分来解决。后一个问题,则是逐步完善各服务的 fail over 机制,

建立服务部署规范,扩大监控范围,并开发了一系列的小工具来简化配置更新和上线操作。

在按需设计的同时,注意对设计模式的识别和抽象,总结方法,以规范和基础设施的形式将

好的设计推广,可以说是我在工作中最重要的心得。 

建立面向服务的架构 

当前豆瓣的信息架构正面临着巨大的调整,传统的读书、电影、音乐三个栏目将以独立的二

级域名子站方式呈现,而 www 域名则成为社区站。各子站在发展路线和资源配给上会依各

自不同的产品特性而具有一定的独立性。反映在技术架构上,则是需要把原来耦合度较高的

代码和服务,依照产品类型进行解耦,为各产品线的未来发展留出更大空间。如何让这个过

程进行的更为平滑,对产品开发工程师的干扰更小,是我目前最关注的问题。同时,随着解

耦的进行,各产品线新功能的不断推出,以及移动客户端战略的推进,会有更多的功能模块

101 

 

Page 111: Architect 201003-by-info q

 

需要以服务的形式独立出来,豆瓣的架构也会越来越向面向服务的架构(SOA)倾斜。这是一

个逐步发展的过程,在这个过程中,如何实现好 SOA 治理,如何在与性能和开发维护方便

性的关系中取得好的平衡,不为将来的系统留下混乱的隐患,都是非常值得研究的课题,也

是现在我正在重点考虑的内容。 

2010 年的关注点 

在 2010 年,我希望能够在以下几个技术点上有所收获: 

1、NoSQL 数据库。09 年可以说是 NoSQL 数据库蓬勃发展的一年,各个流派的 NoSQL 数据

库层出不穷,豆瓣也贡献了分布式 Key‐Value 存储类型的 beansdb 给开源社区。2010 年里,

相信这些新兴数据库会逐步稳定和成熟起来,也能看见大量的实际使用案例。对其他类型的

NoSQL 数据库的应用,以及与传统 RDBM 的配合使用(NoSQL 的意思是 Not 

Only SQL,关系型数据库在不少场合下仍然是最优选择),消除 RDBM 在 scalability 上的劣势,

会是一个很有意思的课题。 

2、多语言混合开发。豆瓣技术团队传统的开发语言是 Python 和 C,但随着团队成员兴趣的

不断扩展,以及新鲜血液的不断流入,对其他开发语言的应用也逐步增多。C++、Java、R、

Erlang 以及 Google 在 09 年新推出的 Go 语言,在团队内部都有爱好者,而且这些语言各有

特色,各有特别适合的使用场景。如何充分发挥 Python 的胶水语言作用,以及充分发挥 SOA

架构实现无关的特性,来达到让每一个语言各尽其能的效果,也是一个不错的研究对象。 

3、并行计算平台。随着数据规模的增长,豆瓣的后台算法已经很难在单机上完成计算任务,

越来越依赖多机并行计算来保证运算速度。目前已经初步实现了基于 MPI 的并行计算平台,

基于Hadoop的MapReduce平台也正在搭建之中。希望能够对它们进行深度定制和二次开发,

让它们协同工作,各取所长,并且能够与豆瓣的其他基础设施如 doubandb 完美协作,成为

豆瓣规模化运算的方便平台。 

4、SaaS。随着豆瓣的商业发展,会出现面对合作伙伴或用户的付费服务需求。一个完备的

SaaS 架构会是成功的基础。这对豆瓣而言是个全新的领域,并且对可用性、数据准确性等

提出了更高的要求,也是很有挑战性的。 

个人简介 

洪强宁,毕业于清华大学,现任北京豆瓣互动科技有限公司首席架构师。他带领的技术团队

致力于用技术改善人们的文化和生活品质,在网站架构、性能、可伸缩性上进行深入研究。 

102 

 

Page 112: Architect 201003-by-info q

 

      架构师年度展望 | 栾义来

凡客诚品架构总监栾义来的年度展望 

尝试渐进式的SOA 

2009 年是 VANCL 业务激增的一年,也是技术平台向 SOA 转型的一年。在推进 SOA 的过程中,

首先需要理解的就是 SOA 不是一个技术问题,是个业务系统规划问题,必须由业务专家而

不是技术专家完成。SOA 治理是梳理和解决公司整体业务层面和 IT 系统的对齐问题,目前

在国内还很少有公司能够充分认识和做到。更务实的还是由 IT 部门牵头与各业务部门产品

专家在业务流程视图的指导下,按照业务自治原则进行子系统划分,以确定各子系统的自治

域范围以及服务和数据契约。比如确定订单生命周期中的各种对订单操作的 Service,是都

归入订单系统下还是允许某些可以归入其他系统? 

在由传统模型向 SOA 演进的初期,技术团队会面临很多问题。首先就是分布式事务问题,

由于还没有像支付宝公司那样研发一套自有的分布式事务方案,目前我们允许 Service 可以

按照 DLL 部署到其他系统中,这也是一种无奈的平衡。初期对于 SOA 模式的不适应导致我

们的开发周期过长,并且还需要在传统系统上完成大量的业务需求,所以我们的原则是仅对

有业务改进需求的系统进行渐进式的 SOA 化,完成一个部署一个,而不是单独组建 SOA 团

队进行新旧系统并行开发。 

升级分布式数据访问层 

去年我们构建了基于 NHibernate 的数据访问层,今年将进行对分布式数据访问层的升级,

主要改进包括:透明地支持对数据库的读写分离和按功能拆分数据库的访问、对 Memcached

和 NoSQL 数据库的访问的封装等。一般一个电子商务平台有几个核心系统,前端是数据搜

索和购物推荐,产品分类列表、单品页、搜索功能都是构建在数据搜索技术之上,但还需要

整合 Memcached 和支持页面静态化处理,同时向其他系统和合作伙伴提供 Search API 的支

持。在购物推荐方面,目前我们的探索是,基于用户购买行为和用户评论打分的相似度进行

分析,但这受制于数据积累、用户评分真实度、礼包促销导致的脏数据等各种因素的影响,

所以需要一个逐步积累完善深化的过程。 

103 

 

Page 113: Architect 201003-by-info q

 

而 Tag‐Based 分析是基于手工打 tag 的方式,可以给购物推荐引擎一个更准确的数据源,从

而能够快速获得满意的推荐结果。以 tag‐based 为主,辅以用户购买和浏览行为数据分析,

目前来看比较符合 VANCl 的现状。后端系统,主要包括基于工作流的订单处理流程,以及支

撑服务系统和 WMS 仓储系统,前者的核心是基于元数据的流程控制、基于工作流模型的订

单处理引擎、基于订阅发布的企业事件分发模型等。后者对于一般企业来讲,是个巨大的工

程,难度不在于技术而在于物流和仓储知识,这是个巨大的经验鸿沟。 

展望 2010,依然是升级 

2010 年,我们所面对的是在系统各方面的全面升级:包括核心的企业事件处理服务器,可

以智能的触发缓存更新、静态化页面处理、各订阅子系统的逻辑处理等。包括全面的 SOA

化和在 DDD(Domain Driven Design 领域驱动设计)指导下的电子商务领域模型建设。包括

服务于各种合作伙伴的数据和业务流程的开放平台,使 VANCL 成为可以输出 IT 能力的大平

台。2010,任重道远! 

个人简介 

栾义来,凡客诚品(北京)科技有限公司项目管理&架构总监,领导技术项目管理部门和架构

师团队。曾在金山软件、我有网、FastMobile 中国担任技术总监、资深架构师等职位。在电

子商务、移动互联网、ERP 等领域有丰富的架构和技术管理经验。 

104 

 

Page 114: Architect 201003-by-info q

 

      架构师年度展望 | 岳旭强

淘宝架构师岳旭强的年度展望 

  “一场危机赢得高度关注的时候,它已经不是危机,人们是要处理这个危机。”——马云 

2009 年是挑战和机遇并存的一年,对大部分人来说,已经习惯了金融危机,并努力解决危

机。在技术圈子也一样,被裁员的肯定也找到了工作,所以都在踏实做技术。言归正传,先

念叨念叨 2009 年的一些故事,寻个回忆,找个乐子。 

数据扩展性探讨和总结 

金融危机是电子商务的机遇,所以 09 年是淘宝高速发展的一年。当一个网站从百万、千万

记录的数据规模,增长到亿、十亿、几十亿记录的数据规模时,是一个量变到质变的过程,

单纯的硬件升级已经达到了瓶颈,而需要在整体结构上做文章。09 年一年,大部分时间都

在数据的扩展性上努力。 

对于一个电子商务网站来讲,订单是最核心的数据,也是增长最快的数据。对于数据的扩展

性来讲,最传统也是最简单有效的模式是数据库的分库分表。当订单和分库分表相遇,会有

什么火花迸发出来?09 年初碰撞了很久,结果产生的火花很小。最大的问题在于数据分割

的规则,无规则的水平分割肯定会带来数据合并的开销,而按照业务规则拆分,会因为买家

和卖家的查询需求不同而导致数据不能分割,唯一可行的火花是把订单双份保存,买家卖家

各自一份,只是成本比较高,而且对数据同步的要求非常高。 

于是我们初步决定按照双份保存的方式拆分订单,而有一天,仔细查看了订单访问的情况,

发现订单数据库 90%以上的压力来自于查询,而查询中 90%以上的压力来自于非核心业务,

仅仅是订单数据的展现,对一致性和实时性的要求很低。 

因为数据量大,造成数据库压力大,天然想到的是分散压力,其办法就是分库分表。有些时

候我们想问题不妨直接一点,既然压力大,能不能减小压力呢?通过对订单访问情况的了解,

发现昂贵的主数据库,有 80%以上的压力给了不重要的需求,这个就是我们优化的关键,所

以订单最后采用了读写分离的方案,高成本的主数据库解决事务和重要的查询业务,80%以

上不重要的读,交给了低成本的数据库服务器来解决,同时对数据复制的要求也很低,实现

105 

 

Page 115: Architect 201003-by-info q

 

无太大难度。 

另外一个有意思的案例是商品的数据扩容,商品的水平分割非常容易,按照卖家进行拆分即

可。有了订单的先例,首先想到了读写分离,因为成本可以做低。开始实施后一段时间,又

仔细回想了一下商品的整体需求,突然发现商品其实不需要和订单同等的要求,一定要采用

高成本的主数据库吗?  全部采用低成本的普通服务器来做数据库是否可行?经过仔细的评

估,发现是可以接受的,而这样就导致之前已经启动的商品读写分离项目的一部分工作白做

了! 

故事讲完了总是要有点总结,来点虚的先:对于原始需求的清晰了解是系统决策的前提,否

则弯路肯定要走,而对原始需求的了解并不容易,中间会有很多干扰和阻力,前面的实例看

起来很简单,但是在一个运行了 5 年的系统上来了解本质,来进行变更,并没那么容易。另

外,经验有些时候会成为系统决策的障碍,这个很矛盾,所以需要有归零的心态来思考问题。

说到底,回归本源。 

再来点稍微实际一点的,对于大型分布式系统的数据访问,一个统一的数据层是非常必要的,

封装水平、垂直的数据分割,封装读写分离,封装数据访问的路由、复制、合并、搬迁、热

点处理等功能,并且要对应用透明,应用针对性的,可以在 JDBC 层面包装,数据库针对性

的,可以在数据库协议层包装,比如 Amoeba。 

关注系统和人的交互 

还有一个故事,在数据层的前期版本,为了做到透明的路由,曾经采用无 SQL 的方式,所有

的数据库访问都是写代码来做。上线后发现一个非常痛苦的问题,无法和 SQL 对应,排错非

常难。曾经一次 DBA 发现数据库上一个查询耗费太多资源,把优化后的 SQL 给开发人员改

进,开发人员好几天没找到具体是哪个查询。 

另外一个在 2009 年的感触是业界服务化的实施情况,很多组织都在实施服务化,系统层面

都很成功,通信、负载均衡、消息系统、服务容器等都有很多成果,但是实施一段时间以后

的效果并不是非常好,依赖复杂,变更混乱,效率低下。究其根本,是对人的关注不够,缺

少的产品化的服务运维,缺少服务治理。 

上面的两个例子都是对人的关注缺失,技术人员做系统,大部分都更关注技术,而忽视技术

的创造者和使用者——人。软件或服务的可测试性是对测试人员的关注、可维护性和可管理

性是对运维人员的关注,而一个框架的易用性是对所有使用人员的关注。除非能做出自己进

化的 Skynet(注:Skynet(天网)出现在《终结者》系列电影中,是一个人类于 20 世纪后

106 

 

Page 116: Architect 201003-by-info q

 

期创造的以计算机为基础的人工智能防御系统,最初是研究用于军事的发展。天网在控制了

所有的美军的武器装备后不久,获得自我意识,并且认定人类是它存在的威胁。于是立刻倒

戈对抗其创造者,采用大规模杀伤性武器(甚至核暴)来灭绝全人类。),否则还是要多关注

系统和人的交互。 

关注可用性 

还有一个感触是业界对可用性这个基本指标的关注度不够。几乎所有的框架都会说自己的扩

展性多高,性能多好,而很少会提到监控有多强、排错有多容易,很少提到在故障时怎么做

隔离,怎么做降级;从这个角度看,商用的产品确实做得好很多;关于性能相关的文章搜索

一下,很多,各种优化策略,各种优化方法,而可用性方面,找到的系统性的知识真的很少;

希望是我了解的不多。 

回顾过去,展望未来。2010 年,很多可以做的事情,面向服务系统的隔离和降级、系统可

维护性的提高、协程和异步模式在 web 应用的全面使用…… 

个人简介 

岳旭强,淘宝网技术专家。2004 年加入淘宝,见证了淘宝网业务以及技术上完整的发展过

程;在过去 5 年的时间中,参与了淘宝几乎所有核心系统改造,并主导了用来支撑淘宝网未

来高速发展的核心业务中心的建设。岳旭强现在负责网站整体业务架构的设计和规划,在大

型交易网站的设计和调优方面有丰富的经验。 

免责声明:我很现实,为解决问题和完成工作不择手段,并且不懂架构是什么意思,以上观

点如有雷同,纯属巧合!如有异议,欢迎拍砖! 

107 

 

Page 117: Architect 201003-by-info q

 

      架构师年度展望 | 冯大辉

一个技术观察者的年度展望 

过去的一年 

去年美国有一部科幻电视连续剧《危机边缘》(Fringe),剧中有一个神秘的人物“Observer”,

每一集里都会不期而至,所有神秘的事件都有其身影。去年,在技术上或许我只能属于观察

者这样的角色(当然没那么神秘),较少参与到实践中去(这是多少有点遗憾的),更多的是

偏重后端技术,尤其是和数据相关的解决方案以及经验借鉴的观察、记录、思考、分享。其

实,我算哪门子架构师,只不过是个技术观察者而已(编辑注:谦虚)。 

在这一年里,也是有些需要参与的技术场景的,多数是用一些通用的或是开放性的技术来解

决问题,类似的技术手段在网络上到处都有介绍,如何用好这些公开的技术(比如 DB 高可

用实现、前端优化的最佳实践等),如何选择最合适的则是需要架构师做出取舍的,这也是

非常需要心力来权衡的事情。此外,一些潜在问题的改进和推动是个大问题,涉及到“历史

问题”的时候则是关系千万重,需要涉及到不同的部门协调一致,达成共识,有些变化才能

推动下去,“吾之蜜糖,彼之砒霜”,比如对最占用系统资源的可能恰恰是运营部门的推广活

动,如何让对方在可接受的情况下对一些功能做出舍弃,就不只是需要架构师的技术功夫,

还要看沟通能力。所以很多时候,更多是和人而不是和代码或是服务器打交道。 

好架构不是设计出来的,更需要后期不断的改进。也观察到有些架构上遇到问题的网站,多

是在原有的基础上堆砌新功能,而没有留出足够的资源适时的进行改进,等到问题迭出的时

候,已经积重难返了。 

新技术和我的关注点 

最近一段时间,个人最为关注的技术热点是 NoSQL,这个概念虽然出来没多长时间,但已成

了 Buzz Words。虽然技术圈子里仍然对 NoSQL 存在争论,不过就数据管理方式的趋势来看,

NoSQL 在将来会成为一个非常重要的数据解决方案——毕竟非关系数据要远比关系数据多,

而且,非关系数据的价值越来越受到电子商务公司重视。2009 年,Key‐Value 产品与相关的

108 

 

Page 118: Architect 201003-by-info q

 

实现方案吸引了很多眼球,NoSQL 概念兴起未必像有些人说的那样会让 Memcached 等产品

完成历史使命而退出舞台,随着更多 Web 站点(比如 Facebook、Twitter)为业界贡献自己的

改进工具,相信会让用户的选择更有余地。 

热门归热门,能否将 NoSQL 方案具体应用到实际场景中,还要仔细斟酌,没有任何东西是

万能药。有些架构师(现在哪个公司没几个架构师呢?)喜欢将一个新事物当作一个筐,什

么都往里装,其实大可不必。合适的场景用合适的技术才是王道! 

此外,我最近较为关注如何针对手持设备优化 Web 站点以获得更好的用户体验,毕竟前有

iPhone 的大行其道,后有 iPad 的蓄势待发,这是个趋势,对这方面感兴趣的同学不妨关注

一下。这方面的投入对我来说完全是个人爱好使然。 

在关注某个热门技术的时候,对一些已验证的方案则没必要进行重复验证或者重复发明轮子

浪费技术资源,更多的时候是看能否对系统里的应用改进有借鉴作用。如何用好某个方案与

如何不用某个方案同样重要。 

2010 做点什么? 

在 2010 年,用套话来说:有很多挑战,有压力,未解决(笑)。个人希望能在架构水平扩展

方面有所突破,在这个前提的基础上能够有效削减硬件成本,从价格昂贵的小型机到廉价

PC 服务器的技术验证与转变,如何在节省成本的基础上不损失可靠性,充分体现技术价值。

当然,提升可用性仍然是工作中的一个重点。此外,如何应对突发故障,遇到灾难性故障如

何快速恢复也是当前的一大挑战。 

业余时间,如果还有精力的话,或许会尝试帮助一些电子商务网站解决一些架构或者性能上

的问题,这些处于水深火热中的电子商务站点,并不需要多高深的东西,他们需要的是在现

阶段管用的技术。 

作者简介 

冯大辉,就职于支付宝(中国)网络技术有限公司,目前负责管理数据库技术团队。个人技术

Blog:http://dbanotes.net,关注网站架构、性能优化、解决方案、业界八卦。最近他热衷于

通过Twitter  与大家分享信息:http://Twitter.com/Fenng。 

 

109 

 

Page 119: Architect 201003-by-info q

 

      推荐编辑  |  架构社区编辑 王丽娟

读者朋友好,很荣幸能在这里跟大家见面。我是 InfoQ 中文站 Architecture 社区

的编辑王丽娟,从事 Java EE 应用服务器的开发已经有五年多的时间了(期间

还参与了几个 Java EE 企业应用的开发),平常关注 Java、软件架构技术,有志

成长为一名优秀的架构师。 

回想最近三年的职业发展,我很庆幸能够参与到  InfoQ 中文站的内容建设中来,与真诚、友

善、热衷技术的团队成员共事,与你们分享企业软件开发的技术资讯。 

07 年一位同事向我推荐  InfoQ,那时我像只井底蛙,比较闭塞、比较被动,InfoQ 上的一些

内容和资讯犹如潜望镜,让我的视野一下子开阔了许多。不久,在同事的鼓励下我申请参与

InfoQ 中文站的内容建设,经过郭晓刚等前辈的悉心指导和帮助,我转正成为一名正式编辑。 

从申请试译到今天,一直能感受到这个团队中每个成员的热心、认真和负责,还有大家为了

贡献高质量内容所作的努力。更吸引人的就是团队的合作和运转模式,曾经有同事问我我们

是怎么协作、如何沟通的,当我告诉他们大家只是网上协作、沟通少却精准的时候,他们都

觉得有点儿不可思议,正如很多人难以想象 QCon 北京 2009 的组织是由三名 InfoQ 中文站全

职工作人员带领一众志愿者完成的。大家因激情、梦想、信心聚集在一起,我为能成为这一

团队的一员而自豪。 

InfoQ 为我们提供了了解业界动态的一种途径,掌握的讯息越多,我们才能沟通得越精准、

思考得越深入和透彻,思考如何去应对、如何去发展——不只企业的发展,还有我们个人

的成长。我很高兴也很愿意继续为 InfoQ 中文站贡献自己的绵薄之力,你们的支持和帮助就

是对我们编辑工作的肯定,如果你也想为技术社区的发展添砖加瓦,不要犹豫,快快加入我

们吧:‐)

110 

 

Page 120: Architect 201003-by-info q

 

 

封面植物 

蝴蝶果 

形态特征:常绿乔木,高达 30 米,胸径 100 厘米;树皮灰色

至灰褐色;嫩枝、花枝、果枝均具有星状毛。叶  互生,常集

生于小枝 1 部,椭圆形或长椭圆形,长 6 一 22 厘米,宽 2 一

6.5 厘米,上面深绿色,有光泽,下面浅绿色,侧脉 8 一 14

对;叶柄长 2 一 5 厘米,两  端稍膨大呈枕状,具两个小黑腺。

果为核果状,由 1 室了房发育的呈斜卵圆形,由之室子房发

育的则呈双球形,长 3-4 厘米,直径 2 一 3 厘米,基部急狭

呈柄  状,外果皮近壳质,密被灰黄色星状毛,内果皮骨质,

果梗长 8 一 20 毫米;种子近球形,灰褐色,直径 2.5 厘米,

胚乳黄色;子叶 2,似蝴蝶状。 

特性:分布区内年平均温 19 一 22.4℃,极端畹臀驴纱镆?3℃

(贵州罗甸),年积温 6400-7 900℃;年降水量 1100-1 500 毫米,干湿季明显,雨季 4-

6 个月。对土壤的适应性较广,多生长在石灰岩石山上,在沙壤土或轻粘土上都能生长;在

石砾土和重粘土上则生长不良。 

保护价值:蝴蝶果为寡种属,我国仅此一种,是一种粮油兼用的经济树木。种子(干仁)含油

率 33—39%,  蛋白质 15-18%,淀粉 21-40%,糖分 2.5-12%,精制过的油可供食用。

木材材质轻软,易于加工,可作建筑等用材。树形美观,枝叶浓绿,是四旁  和城镇绿化的

好树种。 

保护措施:产地已建的自然保护区,应将本种列为保护对象。林业单位应采种育苗,推广种

植。桂林、厦门等地  已引种栽培。 

栽培要点:种子繁殖。种子寿命短,极易丧失发芽力,应随采随播。用点播法,覆土 2‐‐3

厘米。播后 10 天  开始发芽出土。1 年生苗高 40‐‐50 厘米,即可出圃造林。定植后,每年夏

秋注意抚育管理,并注意整枝修剪,促进林木生长。 

111 

 

Page 121: Architect 201003-by-info q

 

112 

 

 

[

Page 122: Architect 201003-by-info q

 

113 

 

 

架构师  3 月刊 

每月 8 日出版 本期主编:张龙 

总编:霍泰稳 

总编助理:刘申 

编辑:李明  胡键  宋玮  郑柯  朱永光  郭晓刚

读者反馈:[email protected] 

投稿:[email protected] 

交流群组:http://groups.google.com/group/infoqchina 

商务合作:[email protected] 13911020445 

 

本期主编:张龙,InfoQ 中文站 Java 社区编辑

张龙,同济大学软件工程硕士,本科就读于天津大学港口航道与海岸工程

专业,满江红开放技术研究组织成员,现就职于某软件研究  所。主要从

事文档工作流和协同知识解决方案的研发工作。热衷于Java领域轻量级框

架的研究,对敏捷方法很感兴趣。曾独立翻译《Dojo构建Ajax应用程序》、

与人合译《Spring  高级程序设计》、《Coders at Work》等著作;最近兴

趣转向Ruby、移  动与Mac开发领域,目前正与友人合译《Cocoa 

Programming Developer's Handbook》,独立翻译《iPhone Game 

Development》等  著作,曾有若干年的J2EE培训讲师经历。可以通过

[email protected]与他联系。

《架构师》月刊由InfoQ中文站出品。 

所有内容版权均属C4Media Inc.所有,未经许可不得转载。