<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>JavaEye论坛精彩帖子</title>
    <description>JavaEye论坛精彩帖子 - Java编程，Ruby编程，微软.net，AJAX，敏捷软件开发，综合软件技术</description>
    <link>http://www.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>发现JBoss Seam很棒呀！有用Seam做过项目的吗？</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://robbin.javaeye.com">robbin</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/212105" style="color:red;">http://www.javaeye.com/topic/212105</a>&nbsp;
          发表时间: 2008年07月06日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          上周去见了一个朋友Mark，他应邀在Red Hat的研讨会上面介绍他曾经用JBoss Seam做过的一个大的项目。因为听了他的演讲，对JBoss Seam多了一点认识，有点出乎意料的方便。所以周末在家下载了JBoss Seam摆弄了一下，把Seam自带的examples都浏览了一遍，也大致看了一下Seam的Reference，感觉挺惊艳的。于是又在JavaEye上面搜索了一下Seam，这才发现自从去年下半年开始，JavaEye已经有大量关于Seam的讨论了，这都一年多过去了，看来自己对Java社区已经有点孤陋寡闻了。<br /><br />写这个文章的目的是和大家一起交流一下JBoss Seam，虽然我通过文档和代码，已经对Seam有了不少了解，但是毕竟没有用Seam写过项目，希望有这方面经验的朋友多谈谈自己的体会。那么作为抛砖引玉，结合与Spring的对比，我先谈谈自己的感觉吧：<br /><br /><br /><span style="font-size: large">一、Seam适应快速开发、简化框架的趋势</span><br /><br />在RoR流行之前，Java社区的主流还是非常讲究分层、架构、复用和模式，而比较忽视快速开发和简化架构的，其结果就是代码量大、开发周期长、架构相当烦琐。以比较常见的Struts/Spring/Hibernate为例，从大的分层来说就有Web层、业务层和持久层，从细的分层就从前到后有：View(JSP) -> Struts Action -> Spring Business Object Bean -> Spring DAO Bean -> Hibernate Persistent Object。如果有Remoting调用，那么还需要相应的Service Facade层。每层都是用不同的技术框架或者模式、各层之间整合的方式也是五花八门。把整个项目的架构搭建起来，已经是非常麻烦的事情了。<br /><br />Seam给我的感觉像是一个异常简单的MVC框架，他实际上只有两层：JSF View和 Seam Component。而Seam Component有两类：一类是Entity Bean，另一类就是Session Bean。Entity Bean映射数据库表，Session Bean完成所有的业务逻辑，包括可能的持久化，事务，响应页面请求、商业逻辑，页面流控制等等。配置文件也不多，除了一堆基础的配置文件，唯一一个需要不断修改的就是pages.xml了，即配置JSF的view映射。<br /><br />所以Seam开发项目看起来很简单、很直接，无分层之苦恼。相应的也会让程序员把精力主要放在业务逻辑组件的实现上，而不是把精力浪费在架构、分层、模式和基础设施搭建的工作上面。<br /><br /><br /><span style="font-size: large">二、Seam的数据绑定做的很出色</span><br /><br />由于是一个简单的两层结构，View和Component之间的数据绑定做的很出色，看起来比我欣赏的Webwork的数据绑定方式更胜一筹。官方的说法叫做双向依赖注入，在component里面可以直接取到页面提交的数据，在页面也可以直接访问component数据。<br /><br />另外持久化数据的校验也直接集成好了，在EntityBean里面声明数据的约束，在页面就可以直接校验了，和RoR的数据校验方式是一样的，当然这也得益于Gavin King是Seam和Hibernate两个项目的作者的缘故。<br /><br /><br /><span style="font-size: large">三、Seam的组件机制看起来相当好用</span><br /><br />既然Seam简化了分层，实际上把主要的工作都推到组件层去完成了。但是Seam的组件层看起来很简单，这得益于Seam的组件机制设计了很多的组件状态，根据不同的组件状态，天然的划分了不同组件的功能和逻辑。<br /><br />Seam的组件有点类似于把传统MVC的Action和Spring的Bean合二为一了，但还是不同于传统的MVC框架下面的Action：传统的MVC Action是基于页面请求的，无法复用，而Seam的组件是事件驱动方式，它只需要捕获和实现事件代码就可以了，至于怎么触发它并不需要知道，他和Web层可以不绑定，因此理论上面来说是可以实现组件复用的。我个人认为Seam的这个组件机制非常巧妙，既可以用来实现响应页面事件，绑定页面数据的所谓Web Bean，也可以用来实现和Web没有任何关系的纯业务逻辑组件，一个很漂亮的实现。<br /><br />另外Seam的组件注入机制看起来也很简单，不像Spring那样麻烦，而且内置了很多现成的组件进来，直接用Annotation声明一下就可以用了，感觉写组件真的很方便、很灵活、很强大。<br /><br /><br /><span style="font-size: large">四、Seam把数据库资源的管理和事务的封装完全隐藏起来了</span><br /><br />Spring的数据库资源管理和事务封装是通过提供了一系列的代理类以及配置文件来实现的，程序员还是要通过配置文件的方式来手工管理事务，访问数据库也必须通过Template编写匿名内部类来实现，而且在Spring/Hibernate框架下面，OpenSessionInView是一个很讨厌的问题。<br /><br />但是Seam已经把数据库资源的管理和事务的封装全部都隐藏起来了，程序员完全不需要知道，也不需要操心这些事情，这真是个大大的解放。当然Seam可以做到这一点，也无非是因为Seam提供了一套上至View层，下至持久层完整的框架，因此可以把实现细节隐藏在框架内部，不暴露给程序员。Spring之所以做不到这一点，也因为他只充当了一个黏合剂，不能够直接修改View层和持久层带来的限制。<br /><br /><br /><span style="font-size: large">五、Seam对第三方框架的整合看起来比Spring更深入</span><br /><br />原来印象当中只有Spring才提供了一站式的解决方案，这次一看Seam文档，呵！发现Seam也都齐全了，什么邮件啦、工作流啦、页面流啦、规则引擎啦、异步任务调度啦、消息系统啦、Web服务啦、远程调用啦、甚至全文检索啦全部都集成了。而且集成的比Spring更深入一些，例如Java EE本身的JMS，MDB自然是Seam的强项，而JBoss自家的JBPM，JPDL，Rules集成的更加没得说。<br /><br />从整合角度来说，感觉Spring和Seam的出发点不同：Spring更像一个平台，我提供整合的可能性，然后程序员你自家去整合，我提供一些写好的整合bean，对于这些你通过XML配置一下就整合进来了，如果我没有提供bean的，那么你也可以自己写bean来整合。而Seam更像一个完整的框架而不是平台，我这个框架想提供的功能，框架自身就已经整合好了，你直接用就是了，你也可以自己写扩展来整合，但是这个不是Seam希望程序员做的事情。<br /><br />因此对于程序员的感觉来说，Spring给你提供了一切的零件和半成品，但你要自己动手来组装，而Seam已经给你装好了一个成品，你就别自己改装了，直接拿去用吧。<br /><br /><br /><span style="font-size: large">六、Seam提供了方便的代码生成器</span><br /><br />和appfuse类似，可以直接用ant task来生成一个完整项目的骨架，以及相应的组件代码生成器，利用seam-gen可以快速生成一个完整的、带有AJAX功能的CRUD项目，而且还是一个eclipse或者netbeans工程，你可以直接用IDE打开编辑了。这功能虽然不太难做，但是对于程序员来说，帮助是很大的。Seam做的相当不错。<br /><br /><br />以上是我对Seam的一点小小的赞许，当然我也有一点疑问：<br /><br /><span style="font-size: large">一、Seam的View实现是JSF，看页面代码还是密密麻麻的Tag</span><br /><br />我是非常反感JSP Tag的，看看页面密密麻麻的Tag就头皮发麻，能不能弄一个Template呀，例如freemarker啥的？这些Tag既不直观，也不方便扩展。需要扩展页面组件，总不能让我自定义Tag去干活吧？不清楚这个问题怎么办？像freeamarker还可以方便的自定义页面宏呢。<br /><br /><span style="font-size: large">二、每次修改都要重新打包发布，太麻烦了吧</span><br /><br />就算修改一个页面，也要整个打包deploy成为一个ear去拷贝到jboss的应用目录下面，这个要是改页面，不是得烦死？ 我以前都是在项目里面直接内嵌Jetty，作为一个application启动，修改页面根本无需重起呀，更不要说deploy了。<br /><br /><br />总体来说，我觉得Seam框架非常出色，尤其是他的组件机制设计的很有匠心，真不愧是Gavin King精心打造的框架了，虽然看起来还是有些缺陷，但是做企业应用项目的话，Seam是一个很棒的选择，作为程序员来说，要比用Spring/Hibernate/Struts省心的多，更能够把精力放在业务逻辑的编写上面，开发效率也很不错，可能是Java开源框架里面最优秀的快速开发框架之一了。
          <br/>
          <span style="color:red;">
            <a href="http://robbin.javaeye.com/topic/212105#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 06 Jul 2008 20:56:35 +0800</pubDate>
        <link>http://www.javaeye.com/topic/212105</link>
        <guid>http://www.javaeye.com/topic/212105</guid>
      </item>
      <item>
        <title>Java程序员应该学习Ruby</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://quake.javaeye.com">Quake Wang</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/208478" style="color:red;">http://www.javaeye.com/topic/208478</a>&nbsp;
          发表时间: 2008年06月27日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Java v.s Ruby，prototype js v.s jquery， Hibernate v.s iBatis v.s EJB ...<br />这种语言之争，框架之争，每隔<a href="http://www.javaeye.com/topic/180517" target="_blank">一段时间</a>总会在论坛<a href="http://www.javaeye.com/topic/206906" target="_blank">出现</a><br /><br />最近我读到一篇博客：<a href="http://jbossdna.blogspot.com/2008/06/java-developers-should-learn-ruby.html" target="_blank">Java程序员应该学习Ruby</a>，非常赞同作者的观点，粗略翻译其中的小部分，希望大家可以减少这种无意义的争论<br /><br />--------翻译开始分割线--------<br />Java程序员应该学习Ruby<br /><br />当然，它不一定是Ruby，你可以挑选其他语言，比如ErLang，甚至JavaScript，只要它和Java有足够的差异就可以了。<br />因为它能够让你成为一个更好的Java程序员：<br /><br /><span style="font-size: medium">1. 学习另外一种语言，它能够让你深入不同的开发者社区</span><br /><br />针对相同的问题，你可以找到不同的思想和不同的做法，或许它们不一定是更好，只是不同而已。其他社区往往有新鲜的视角来看待相同的问题，有时候甚至会让你更感激Java社区（比如Java有大量优秀的library）<br /><br /><span style="font-size: medium">2. 学习另一种语言，可以教你新的idioms</span>（idioms - 我想用行话来翻译idiom更准确一些）<br /><br />你可以在Java使用其中的一些行话，或者由于语言限制，你还不能使用它。<br />以Ruby的blocks为例子，它是Ruby闭包的一种表现，比方说你可以很方便地遍历数组，然后做一些操作(打印)：<br /><pre name="code" class="ruby">
animals = ['lion','tiger', 'bear']
animals.each {|animal| puts animal }
</pre><br /><br />很遗憾，目前Java还没有闭包，在Java 6里面如果要做类似的事情就是通过匿名内部类来解决，需要2个接口：<br /><pre name="code" class="java">
public interface OnEach&lt;T> {
  void run(T obj);
}
public interface List&lt;T> ... {
  void each( OnEach&lt;T> action );
}
</pre><br /><br />然后上面ruby例子就可以这样用：<br /><pre name="code" class="java">
List&lt;String> animals = Arrays.asList( new String[]{"lion", "tiger", "bear"} );
animals.each( new OnEach&lt;String>() {
 public void run( String animal ) {
  System.out.println(animal);
 }
});
</pre><br /><br />不过还是有点麻烦，Java 7将会引进闭包，目前已经有<a href="http://www.javaworld.com/javaworld/jw-06-2008/jw-06-closures.html" target="_blank">多个设计</a><br /><br /><span style="font-size: medium">3. 学习另一种语言，也迫使您使用不同的工具和过程</span><br /><br />以Ruby的<a href="http://rspec.info/" target="_blank">RSpec</a>为例，它是一个<a href="http://behaviour-driven.org/" target="_blank">Behavior Driven Development</a>框架，通过使用它你会发现和Java社区的Test Driven Development区别，并且可以从中学到很多。<br /><br /><br />Java是伟大的，并且还会继续，但是它需要进化。它已经有13年的历史了，我们一些人几乎把所有的时间都花在Java领域。去探索一下其他语言，我打赌你会成为一个更好的Java程序员。<br />--------翻译结束分割线--------<br /><br /><br />我之前一直是一个Java程序员，去年开始接触Ruby，在不到一年的时间里（更准确的说是在学习了Ruby 2个星期后），我觉得已经变成了一个更好的Java程序员，你还在等什么，开始学习Ruby吧。
          <br/>
          <span style="color:red;">
            <a href="http://robbin.javaeye.com/topic/208478#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 27 Jun 2008 09:35:07 +0800</pubDate>
        <link>http://www.javaeye.com/topic/208478</link>
        <guid>http://www.javaeye.com/topic/208478</guid>
      </item>
      <item>
        <title>推荐一款使用Extjs做GUI的数据库浏览工具--DBExplorer</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cnetwei.javaeye.com">cnetwei</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/207901" style="color:red;">http://www.javaeye.com/topic/207901</a>&nbsp;
          发表时间: 2008年06月25日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><span style="font-size: small;">学习Ext的过程中 完成一个数据库浏览工具&mdash;&mdash;DBExplorer。基于JDBC连接各种数据库：支持sql语句执行，支持数据浏览和修改，支持LOB数据的查看、下载和修改，支持数据导出等功能。</span></p>
<p><span style="font-size: small;">更多细节内容可以在 </span><a href="http://jdbexplorer.googlecode.com"><span style="font-size: small;">http://jdbexplorer.googlecode.com</span></a><span style="font-size: small;">&nbsp;进一步了解。</span></p>
<p>&nbsp;</p>
<p><span style="font-size: small;">其它的就不多说啦，贴几张图看看：</span></p>
          <br/>
          <span style="color:red;">
            <a href="http://robbin.javaeye.com/topic/207901#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 25 Jun 2008 15:59:43 +0800</pubDate>
        <link>http://www.javaeye.com/topic/207901</link>
        <guid>http://www.javaeye.com/topic/207901</guid>
      </item>
      <item>
        <title>XP的反省-Pair Programming</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://emarket.javaeye.com">emarket</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/207558" style="color:red;">http://www.javaeye.com/topic/207558</a>&nbsp;
          发表时间: 2008年06月24日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>常常看到论坛上有人讨论PP（Pair Programming）,但是大多是纸上谈兵，书上云的过多。真正谈感受的少。 我在一家做XP的公司做了4年了，从做service到做product, 总的来说pair programming给我带来的的忧大于喜，缺点大于有点。 </p>
<p>&nbsp;</p>
<p>总的来说PP有它的优点，很多researcher也发表了论文，记得比较清楚的一片就是一个大学里面对一个班的学生分组实验，结果用PP的那组效率比较高。 但这毕竟是research, 给我们的启示是PP在某种特定的情况下的结果:</p>
<p>&nbsp;</p>
<p style="padding-left: 30px;"><strong>1. Pair的人必须对等 （同班同学）</strong>
</p>
<p style="padding-left: 30px;"><strong>2. Pair的人必须全力以赴 (同学们，老师在做实验哦，不要走神！)</strong>
</p>
<p style="padding-left: 30px;"><strong>3. Pair的人必须对要解决的问题有相同（或相近）的认知 </strong>
</p>
<p>&nbsp;</p>
<p>而上面的3点在现实公司里却大部分情况下不能成立。1就不用说了，2，举个例子，如果有一个人生病，或是惦记的其他的事则会screw up整天的进度。3，和1相关，人的水平不同，不可能像大学那样对一个东西的认知近似。 </p>
<p>&nbsp;</p>
<p>我个人的经验是<span style="font-size: medium;"><strong>10%的pair时间是高效的pair，其余的则是浪费时间</strong>
</span>
。</p>
<p>&nbsp;</p>
<p>另外从人性的角度来讲，<strong>pair on everything则是对人性的强奸</strong>
，强调沟通没有错误，但是工作毕竟是工作，如果天到晚说比写花的时间更多，则有点本末倒置了。我们公司是100% pair, 任何的task，不管有没有必要，都要pair （条件允许的话）, 老板的原则是绝不让任何一个知识点停留在一个人的脑瓜里：）,一个人躺下了，另一个就能补上。 但是从现实的角度来讲，我们的产品的确出现过超过一个developer走了，结果他们经常working的那个module就会没有人能够维护了，结果需要重写。 所以从knowlege spread的角度来说，公司的benifit和情感留人+document, 比pair来的更实惠。</p>
<p>&nbsp;</p>
<p>另外<strong>pair的确剥夺了developer的个人空间</strong>
。 以前的公司， 上网灌水，给朋友 MSN, 的小动作全都不行了：（， 也许有人会说这些的东西在公司应该禁止！ 但是现实一点，我来java eye灌水 ， 跟几个圈内的朋友msn讨论心得，是对工作有正面影响的。 而且msn的圈内朋友对于疑难问题的帮助会很大的。 </p>
<p>&nbsp;</p>
<p>而且还有一点最大的就是<strong>pair剥夺了自学的时间</strong>
， 没有pair的时候当有东西不会的时候， 对一个问题的研究会刨根结底，但是pair的时候，如果你的partner会，他大概只会给你概括一下，如果你的partner不会，那就会是一个非常有趣的pairing session, 什么google, yahoo, 大部分情况，结果是 this is a fking task that we should never touch as we dont have corrosponding knowlege... 但是如果一个人能够静下心来把问题的来龙去脉搞清楚，把相应的prerequiste的knowlege搞清楚， 问题在得到解决的同时，自己也会得到提高。说白了当两个新手在pair的时候的确很低效，而且不利于&ldquo;成长&rdquo;</p>
<p>&nbsp;</p>
<p>说了这么多， 一句话<span style="font-size: medium;"> <strong></strong>
</span>
</p>
<p style="text-align: center;"><span style="font-size: medium;"><strong>少Pair可以怡神，多pair的确伤身， 不pair也能过日子</strong>
</span>
。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://robbin.javaeye.com/topic/207558#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 24 Jun 2008 16:10:04 +0800</pubDate>
        <link>http://www.javaeye.com/topic/207558</link>
        <guid>http://www.javaeye.com/topic/207558</guid>
      </item>
      <item>
        <title>开源Visual Swing Designer for Eclipse，邀请有志者帮忙改进</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://rehte.javaeye.com">rehte</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/208787" style="color:red;">http://www.javaeye.com/topic/208787</a>&nbsp;
          发表时间: 2008年06月27日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          一直以来非常喜欢Swing，对Swing的研究也有很长一段时间了，一直希望Swing在Java桌面开发中扮演重要的角色。但是很久以来Java桌面开发始终是个弱项，其中很大一部分原因是缺乏比较好用的界面设计工具。<br /><br />NetBeans的界面设计工具(以前叫Matisse Project)的出现给Java的Gui开发尤其是Swing开发带来了希望，但遗憾的是当前Java集成开发环境仍然是Eclipse的天下，据统计，目前市场上至少2/3的份额是被eclipse占有。虽然netbeans已经获得长足的进步，并进一步吸引了更多的developer，但是由于历史习惯和遗留系统等等问题，这个市场份额在最近几年肯定还是eclipse的天下。<br /><br />当然eclipse也有很多很优秀的界面工具插件，可惜的是免费的插件其质量难以与netbeans的匹敌，好用的插件又都是收费的。因此<strong>一直想为eclipse开发一款免费的、开源的、功能上与Mattise Project相近的界面设计工具，</strong>算是为Swing的发展做一点贡献。<br /><br />从今年1月份开始，我来到一家新公司，主要做基于eclipse插件平台的开发，得以学习了eclipse的插件开发知识。以前曾经使用swing做过一个swing的界面设计工具，但由于是一款独立的工具，没有集成到任何IDE中，因此几乎没有实用价值。因此决定在闲暇时间将这个工具重新用eclipse插件技术进行开发。<br /><br /><strong>经过了五个月左右周末的努力，这款界面设计工具终于快要完成了，目前定的版本是0.9.0。但由于还有许多细节需要细化，需要大量的精力投入其中，因此想提前把代码开源出来，希望有志者能帮我一起完成。</strong><br /><br /><strong>开发这款工具的目标是希望达到以下特点：</strong><br /><br /><strong>1. 界面布局模仿Netbeans界面设计工具，操作和netbeans设计工具基本一模一样，容易直观的实现布局。</strong>这是第一目标。目前已经实现。<br /><br /><strong>2. 代码的生成和解析不需要辅助form文件，直接从源代码文件进行解析生成。生成代码可读性要强，要可以编辑并且同步。</strong>目前已经基本实现，有些折中处理，采用约定代替配置的办法提高代码解析速度。<br /><br /><strong>3. 直接支持树和表的界面设计，不需要写代码，直观的采用界面操作，便可以直接生成表和树的数据模型代码。</strong>此功能已经实现。而且目前的框架可以很容易扩展，实现类似其他复杂组件的界面设计。<br /><br /><strong>4. 工具的性能良好，界面设计功能流畅，代码解析/生成速度快。</strong>目前来看，速度和性能还不错，初步的打算是将速度放在最后处理优化。<br /><br /><strong>5.支持在设计时切换LookAndFeel,并能生成所设定LookAndFeel的代码。</strong>这样就能做到设计时和运行时完全一致。而NetBeans的设计工具只能以NetBeans自身相同的LookAndFeel设计，然后使用另外的LookAndFeel预览。<br /><br />说了这些，忘了说明一下代码位置：<br />http://code.google.com/p/visualswing4eclipse/<br />使用的是LGPL授权方式。照顾商业利用和开源改进而采用此授权。<br />目前支持的Eclipse平台是3.4，JDK请使用1.6<br /><br />忘了一条，我的msn是rehte @ hotmail . com<br /><br /><strong><br />看到还有人关心我很欣慰，毕竟在提到做Java开发就是指Web应用开发的时代，还有人关注Java桌面开发。我这个帖子的目的是邀请熟悉最好是精通Swing/SWT和Eclipse RCP技术的朋友参加这个项目，帮助我完成这个工具。这个工具离实用阶段还有一定的距离，但是目前在实现来说只是细节打磨、bug修改阶段了，但这需要大量的精力，我一个人吃不消，希望有人能帮助我。当然你在功能和实用性上提的意见也是欢迎的，我会把它们作为参考意见加入到今后的开发中。由于这个工具目前一直是我一个人来做，能力和精力都有限，所以最好不要上来直接和netbeans和其他商用的工具比较。我的目标是他们，但需要大家的帮助。</strong>
          <br/>
          <span style="color:red;">
            <a href="http://robbin.javaeye.com/topic/208787#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 27 Jun 2008 18:59:16 +0800</pubDate>
        <link>http://www.javaeye.com/topic/208787</link>
        <guid>http://www.javaeye.com/topic/208787</guid>
      </item>
      <item>
        <title>分布式缓存系统Memcached学习心得</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://liubin65030-gmail-com.javaeye.com">悠游键客</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/208981" style="color:red;">http://www.javaeye.com/topic/208981</a>&nbsp;
          发表时间: 2008年06月28日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          缘起: 在数据驱动的web开发中，经常要重复从数据库中取出相同的数据，这种重复极大的增加了数据库负载。缓存是解决这个问题的好办法。<br />Memcached是什么?<br />Memcached是由Danga Interactive开发的，高性能的，分布式的内存对象缓存系统，用于在动态应用中减少数据库负载，提升访问速度。<br /><br /><strong>Memcached能缓存什么？</strong><br />       通过在内存里维护一个统一的巨大的hash表，Memcached能够用来存储各种格式的数据，包括图像、视频、文件以及数据库检索的结果等。<br /><br /><strong>Memcached快么？</strong><br />       非常快。Memcached使用了libevent（如果可以的话，在linux下使用epoll）来均衡任何数量的打开链接，使用非阻塞的网络I/O，对内部对象实现引用计数(因此，针对多样的客户端，对象可以处在多样的状态)， 使用自己的页块分配器和哈希表， 因此虚拟内存不会产生碎片并且虚拟内存分配的时间复杂度可以保证为O(1).。<br />       Danga Interactive为提升Danga Interactive的速度研发了Memcached。目前，LiveJournal.com每天已经在向一百万用户提供多达两千万次的页面访问。而这些，是由一个由web服务器和数据库服务器组成的集群完成的。Memcached几乎完全放弃了任何数据都从数据库读取的方式，同时，它还缩短了用户查看页面的速度、更好的资源分配方式，以及Memcache失效时对数据库的访问速度。<br /><br /><strong>Memcached的特点</strong><br />       Memcached的缓存是一种分布式的，可以让不同主机上的多个用户同时访问， 因此解决了共享内存只能单机应用的局限，更不会出现使用数据库做类似事情的时候，磁盘开销和阻塞的发生。<br /><br /><strong>Memcached的使用 </strong><br />一 、Memcached服务器端的安装 （此处将其作为系统服务安装）<br />     下载文件：memcached 1.2.1 for Win32 binaries (Dec 23, 2006)<br />   1 解压缩文件到c:\memcached<br />   2 命令行输入 'c:\memcached\memcached.exe -d install' <br />   3 命令行输入 'c:\memcached\memcached.exe -d start' ，该命令启动 Memcached ，默认监听端口为 11211<br />  通过 memcached.exe -h 可以查看其帮助<br /><br />二、客户端使用<br />      下载memcached java client：http://www.whalin.com/memcached/#download<br />   1 解压后将java_memcached-release_2.0.1.jar jar包添加到工程的classpath中<br />       2 利用memcached java client 一个简单的应用<br /><pre name="code" class="java">
package com.danga.MemCached.test;    
   
import java.util.Date;    
   
import com.danga.MemCached.MemCachedClient;    
import com.danga.MemCached.SockIOPool;    
   
   
public class Test {        
    protected static MemCachedClient mcc = new MemCachedClient();       
       
    static {       
        String[] servers ={"192.168.40.4:12000"};       
       
        Integer[] weights = { 3 };       
       
        //创建一个实例对象SockIOPool     
        SockIOPool pool = SockIOPool.getInstance();       
       
        // set the servers and the weights    
        //设置Memcached Server    
        pool.setServers( servers );       
        pool.setWeights( weights );       
       
        // set some basic pool settings       
        // 5 initial, 5 min, and 250 max conns       
        // and set the max idle time for a conn       
        // to 6 hours       
        pool.setInitConn( 5 );       
        pool.setMinConn( 5 );       
        pool.setMaxConn( 250 );       
        pool.setMaxIdle( 1000 * 60 * 60 * 6 );       
       
        // set the sleep for the maint thread       
        // it will wake up every x seconds and       
        // maintain the pool size       
        pool.setMaintSleep( 30 );       
       
        // Tcp的规则就是在发送一个包之前，本地机器会等待远程主机    
                  // 对上一次发送的包的确认信息到来；这个方法就可以关闭套接字的缓存，    
                  // 以至这个包准备好了就发；    
                  pool.setNagle( false );       
        //连接建立后对超时的控制    
                  pool.setSocketTO( 3000 );    
        //连接建立时对超时的控制    
                  pool.setSocketConnectTO( 0 );       
       
        // initialize the connection pool       
        //初始化一些值并与MemcachedServer段建立连接    
                  pool.initialize();    
               
       
        // lets set some compression on for the client       
        // compress anything larger than 64k       
        mcc.setCompressEnable( true );       
        mcc.setCompressThreshold( 64 * 1024 );       
    }       
           
    public static void bulidCache(){       
        //set(key,value,Date) ,Date是一个过期时间，如果想让这个过期时间生效的话，这里传递的new Date(long date) 中参数date，需要是个大于或等于1000的值。    
        //因为java client的实现源码里是这样实现的 expiry.getTime() / 1000 ，也就是说，如果 小于1000的值，除以1000以后都是0，即永不过期    
        mcc.set( "test", "This is a test String" ,new Date(11211));   
    //十秒后过期    
              
    }       
      
    public static void output() {       
        //从cache里取值    
        String value = (String) mcc.get( "test" );       
        System.out.println(value);        
    }       
           
    public static void main(String[] args){       
        bulidCache();      
        output();           
    }     
       
}       

</pre>
          <br/>
          <span style="color:red;">
            <a href="http://robbin.javaeye.com/topic/208981#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 28 Jun 2008 17:58:52 +0800</pubDate>
        <link>http://www.javaeye.com/topic/208981</link>
        <guid>http://www.javaeye.com/topic/208981</guid>
      </item>
      <item>
        <title>解决海量数据的新思路——分布式数据库</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://chester60.javaeye.com">chester60</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/212046" style="color:red;">http://www.javaeye.com/topic/212046</a>&nbsp;
          发表时间: 2008年07月06日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          目前，分布式的概念越来越流行，但是在数据库领域里，分布式的应用相对较少。在参阅了Google的Map/Reduce概念后，我构思了一种分布式数据库的架构，并实现了其雏形，现在将其基本思路写出来，希望能起到抛砖引玉的作用。我工作时间不长，其中错误，不完善之处还请大家多多指出，谢谢。<br /><br />    设计这个分布式数据库的目的在于快速的处理海量数据。基本思路其实很简单，将数据分布到多个数据节点中，在执行SQL语句时，分析SQL语句的语义，对一个或多个数据库进行操作。这样就可以使查询的压力分散到每一个节点上面，面对海量数据时的处理时间大大缩短。<br /><br />    先拿几个简单的SQL语句做分析，看看在分布式的环境下和平常有何不同。假设我们现在有两个数据节点A和B，表名为Table，其中ID为1~100的数据保存在节点A，ID为101~200的数据保存在节点B。以下的SQL语句都是同时对2个数据库执行。<br /><br />    Select * from Table where ID=1<br />    这样A数据库将返回ID为1的数据，数据库B返回为空。这时简单的合并A和B的数据，就可以得到正确的结果。<br /><br />    Select top 10 * from Table<br />    这时A数据库将返回10条数据，B数据库返回10条数据，这时如果合并A和B，将返回20条结果。这时必须移除多余的10条数据才是正确的结果。<br /><br />    Select * from Table order by ID<br />    这时A，B数据库将返回所有的数据，但是要使得数据符合order by的条件，很显然应该进行一次排序操作。<br /><br />    Select top 10 * from Table order by ID<br />    这时A，B数据库都返回10条数据，经过合并后，还要经过排序，移除的操作，才能确保结果正确。<br /><br />    SQL语句中需要处理的关键字还有max，min，count，sum，avg等，这里就不写出来了。经过这几个例子我们可以看到，其实只要经过一些处理，分别对不同数据节点上的查询，可以转化成对单一数据库查询等效的结果。而这些处理归纳起来，只有合并，排序，移除这三种情况，其实这和Map/Reduce思想非常的类似，无论什么复杂的动作，最终归结都可以通过几个简单操作来完成。这些处理当然需要一定的时间，但是在面对海量数据时，很多情况下，处理所需要的时间可以小到忽略不计。<br /><br />    上面只是一些简单的SQL语句，面对一些复杂的SQL语句，要在SQL语句处理的过程中，进行数据节点之间的数据交换才能完成的（例子在文末会给出）。因此要实现一个完全能够处理SQL语句的分布式数据库，需要在数据库的内核部分进行改动。在实现这个组件时，时间是有限的，进行内核部分的改造不现实，所以我采取了中间件的方式，来实现了这个分布式数据库的雏形，采用的数据库是MSSQL2000，下图是我设计的分布式数据库的概念图（参见附件1）：<br /><br /><br />    如图所示，数据根据一定规则分布（一般可以直接Hash主键）到每一个数据节点中，由分布式数据库服务器对每个数据节点进行访问，进行归并/排序/移除操作，然后通过数据接口，返回给程序。<br /><br />    其中几个数据接口所适用的场景为：<br /><br />    Reader：提供对数据库的查询结果，逐条进行读取的接口。在海量数据下，有时候需要读取大量数据进行处理，如果一次读取到内存中显然不现实。此时可以使用Reader模式逐条读取，进行分批处理。<br /><br />    DataFiller：提供对数据的XML包装，适用于小数据量的读取，主要是给Web应用提供一个方便的接口。<br /><br />    Command：执行delete，update，insert等不返回数据的SQL语句。<br /><br />    BulkCopy：批量插入接口。主要是为大数据量的导入提供高速接口。<br /><br />    实现这个中间件，难点应该是在SQL语句的语义分析上。这块应该使用编译原理来实现，但是在我的实现中，并没有用到，原因一个是时间问题，另外一个是因为基于中间件的方式，对一些复杂的SQL语句无法得到正确的结果。所以使用了正则表达式和一些方法来对SQL语句进行分析，分析出应该如何对执行结果进行处理，以及SQL语句应该发送到单个节点还是多个节点。以下是处理的流程示意图（参见附件2）：<br /><br />    在实现时需要注意的地方是，一定要让SQL语句从发送到执行，到返回结果之间没有任何延迟，否则每秒能够执行的SQL语句最多只有几十条。一开始我使用的模型是很常见的查询线程模型（参见附件3）：<br /><br />    每个语句执行完毕之后，在HashMap中将执行状态设置为执行完毕。使用一个查询线程，不断的遍历HashMap，发现有执行完毕的语句，便将其发往结果处理模块。为了避免CPU占用率100%，查询线程必须要有Sleep语句，但是windows下线程轮切的最小时间段为15ms，并且在Sleep的过程中，CPU将优先处理其他线程，这样Sleep一次至少需要20ms。这样，无论SQL查询再快，分布式数据库的处理速度也会被限制在1000/20=50条/秒以下。在我做的第一个模型中，每秒最多只能处理20多条SQL语句，在面对Web应用时，显然是不够的。<br /><br />    后来我采用的是信号量机制，即在生成Query线程时，给其分配一个信号量，执行每个SQL语句都会将一个监视线程加入线程池，监视线程堵塞住，等待所有信号量置为发信状态，然后立刻将结果送入结果处理模块。Windows处理信号量是非常快的，可以以CPU指令周期来计量。经过这个改进，分布式数据库处理一个查询的语句，基本等同于执行查询所需的时间。当然，这样的设计造成了使用的线程比较多，调试起来非常困难，需要非常小心的设计，而且在数据节点多的时候，必须维护一个成百上千线程的线程池，个人觉得是非常不好的。我注意到无论处理多少数据，MSSQL中的线程只有20多个，可以判断出他们的设计是非常精巧的，肯定和我的这种设计不同。如果有更好的方法解决这个问题，请不吝赐教，谢谢。<br /><br />    以上便是一个分布式数据库中间件的基本概念和一个基本实现。当然，实现一个商用的中间件，还有很多工作需要做，例如权限，数据安全，节点故障处理，日志等模块，都有很多改进的地方。目前我实现的这个中间件非常简陋，由于MSSQL本身的限制，有很多模块实现得不够优雅，不过唯一值得欣慰的是，性能上来说是非常不错的，达到了分布式系统的初衷。目前有3台机器作为数据节点运行，进行随机数据访问时，负载基本平均分到了每一个节点上。大数据量读取，大数据量写入一般都有单数据库2倍以上的速度。当然，分布式不是万能的，目前有些问题是无法解决的。例如：<br /><br />    1、多表问题：简单的举个例子，例如有一张用户表，一张产品ID表，还有一张交易记录表，以用户表，产品ID表为外键，如果执行诸如<br /><br />    Select * from 交易记录表 where 交易记录表.产品ID=产品ID表.ID and 交易记录表.用户ID=用户表.用户ID<br /><br />    这样的语句时，如果只对执行完的结果进行处理，无论如何架构这几张表，都会出错。为什么？原因有点难说清楚，有兴趣的话仔细思考一下就知道了。<br />    对于这样的语句，中间件根本无法处理，只有修改内核，在执行语句的过程中，对每个数据节点进行数据交换，才可以解决。目前的解决方法是把其中一张表放到单个数据库上。不过这样程序看起来就很怪异，一个查询动作要用到两个不同的数据库访问类，没有弄明白整个框架的程序员都不知道为什么要这样做。<br /><br />    2、语意分析：在分布式的环境下，SQL语意转换为操作原语的难度更加高了，确保其逻辑完全正确很困难，我离散数学学得很差，目前还不能达到100%的正确率，所以不得不在数据接口中保留了手动模式，即手工决定该如何处理数据，非常的丑陋。以目前的识别率，一些复杂的SQL语句要么分开几次写，要么使用手动模式自定义其处理流程才能确保其正确，目前也没时间去完善分析模块，只能随它去了。<br /><br />    提出这些问题希望能得到大家的指点，毕竟独自一人开发思路会有很多局限性，个人感觉其中还有很多地方可以挖掘，完全可能成为另外一种处理海量数据的方式。最后，谢谢你的观赏。
          <br/>
          <span style="color:red;">
            <a href="http://robbin.javaeye.com/topic/212046#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 06 Jul 2008 15:17:48 +0800</pubDate>
        <link>http://www.javaeye.com/topic/212046</link>
        <guid>http://www.javaeye.com/topic/212046</guid>
      </item>
      <item>
        <title>一次Java垃圾收集调优实战</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://calvin.javaeye.com">江南白衣</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/212967" style="color:red;">http://www.javaeye.com/topic/212967</a>&nbsp;
          发表时间: 2008年07月09日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h3>1 资料</h3>
<ul>
<li><span class="nobr"><a href="http://calvin.javaeye.com/blog/91905" title="Visit page outside Confluence" rel="nofollow">JDK5.0垃圾收集优化之--Don't Pause(花钱的年华)<sup><img class="rendericon" src="../../../../images/icons/linkext7.gif" border="0" height="7" align="absmiddle" alt="" width="7" />
</sup>
</a>
</span>
&thinsp;</li>
<li><span class="nobr"><a href="http://calvin.javaeye.com/blog/91903" title="Visit page outside Confluence" rel="nofollow">编写对GC友好，又不泄漏的代码(花钱的年华)<sup><img class="rendericon" src="../../../../images/icons/linkext7.gif" border="0" height="7" align="absmiddle" alt="" width="7" />
</sup>
</a>
</span>
&thinsp;</li>
<li><span class="nobr"><a href="http://pengjiaheng.spaces.live.com/blog/cns!2DAA368B386E6AEA!770.entry" title="Visit page outside Confluence" rel="nofollow">JVM调优总结<sup><img class="rendericon" src="../../../../images/icons/linkext7.gif" border="0" height="7" align="absmiddle" alt="" width="7" />
</sup>
</a>
</span>
&thinsp;</li>
<li><span class="nobr"><a href="http://www.md.pp.ru/~eu/jdk6options.html" title="Visit page outside Confluence" rel="nofollow">JDK 6所有选项及默认值<sup><img class="rendericon" src="../../../../images/icons/linkext7.gif" border="0" height="7" align="absmiddle" alt="" width="7" />
</sup>
</a>
</span>
&thinsp;</li>
</ul>
<h3>2 GC日志打印</h3>
<p>&nbsp; GC调优是个很实验很伽利略的活儿，GC日志是先决的数据参考和最终验证：</p>
<div class="macro">
<div class="code">
<div class="codeContent">
<pre class="code-java">-XX:+PrintGCDetails -XX:+PrintGCTimeStamps(GC发生的时间) -XX:+PrintGCApplicationStoppedTime(GC消耗了多少时间) -XX:+PrintGCApplicationConcurrentTime(GC之间运行了多少时间)</pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<h3>3 收集器选择</h3>
<h4><a name="JavaPerformance-CMS收集器：暂停时间优先" style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(../../../CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;amp;file=anchor.gif);"></a>
CMS收集器：暂停时间优先</h4>
<p>&nbsp;&nbsp; 配置参数：-XX:+UseConcMarkSweepGC<br />
&nbsp;&nbsp; 已默认无需配置的参数：-XX:+UseParNewGC(Parallel收集新生代)
-XX:+CMSPermGenSweepingEnabled(CMS收集持久代)
-XX:UseCMSCompactAtFullCollection(full gc时压缩年老代)</p>
<p>&nbsp;&nbsp; 初始效果：1g堆内存的新生代约60m，minor gc约5-20毫秒，full gc约130毫秒。</p>
<h4><a name="JavaPerformance-Parallel收集器：吞吐量优先" style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(../../../CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;amp;file=anchor.gif);"></a>
Parallel收集器：吞吐量优先</h4>
<p>&nbsp;&nbsp;&nbsp; 配置参数： -XX:+UseParallelGC -XX:+UseParallelOldGC(Parallel收集年老代，从JDK6.0开始支持)</p>
<p>&nbsp;&nbsp;&nbsp; 已默认无需配置的参数： -XX:+UseAdaptiveSizePolicy(动态调整新生代大小)</p>
<p>&nbsp;&nbsp;&nbsp; 初始效果：1g堆内存的新生代约90-110m(动态调整)，minor gc约5-20毫秒，full gc有无UseParallelOldGC 参数分别为1.3/1.1秒，差别不大。</p>
<p>&nbsp;&nbsp;&nbsp; 另外-XX:MaxGCPauseMillis=100 设置minor gc的期望最大时间，JVM会以此来调整新生代的大小，但在此测试环境中对象死的太快，此参数作用不大。</p>
<h3><a name="JavaPerformance-1.4调优实战" style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(../../../CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;amp;file=anchor.gif);"></a>
4 调优实战</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Parallel收集高达1秒的暂停时间基本不可忍受，所以选择CMS收集器。
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在被压测的Mule 2.0应用里，每秒都有大约400M的海量短命对象产生：</p>
<ol>
<li>因为默认60M的新生代太小了，频繁发生minor gc，大约0.2秒就进行一次。</li>
<li>因为CMS收集器中MaxTenuringThreshold(生代对象撑过过多少次minor gc才进入年老代的设置)默认0，存活的临时对象不经过Survivor区直接进入年老代，不久就占满年老代发生full gc。</li>
</ol>
<p>&nbsp; &nbsp;&nbsp; 对这两个参数的调优，既要改善上面两种情况，又要避免新生代过大，复制次数过多造成minor gc的暂停时间过长。</p>
<ol>
<li>使用-Xmn调到1/3 总内存。观察后设置-Xmn500M，新生代实际约460m。(用-XX:NewRatio设置无效，只能用 -Xmn)。</li>
<li>添加-XX:+PrintTenuringDistribution 参数观察各个Age的对象总大小，观察后设置-XX:MaxTenuringThreshold=5。</li>
</ol>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 优化后，大约1.1秒才发生一次minor gc，且速度依然保持在15-20ms之间。同时年老代的增长速度大大减缓，很久才发生一次full gc，</p>
<p>&nbsp; &nbsp; &nbsp; 参数定稿：</p>
<div class="macro">
<div class="code">
<div class="codeContent">
<pre class="code-java"> -server -Xms1024m -Xmx1024m -Xmn500m -XX:+UseConcMarkSweepGC   -XX:MaxTenuringThreshold=5  -XX:+ExplicitGCInvokesConcurrent</pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最后服务处理速度从1180 tps 上升到1380 tps，调整两个参数提升17%的性能还是笔很划算的买卖。</p>
<p>&nbsp;</p>
<p>&nbsp; &nbsp;&nbsp; 另外，JDK6 Update 7自带了一个VisualVM工具，内里就是之前也有用过的Netbean Profiler，类似JConsole一样使用，可以看到线程状态，内存中对象以及方法的CPU时间等调优重要参考依据。免费捆绑啊，Sun 这样搞法，其他做Profiler的公司要关门了。</p>
          <br/>
          <span style="color:red;">
            <a href="http://robbin.javaeye.com/topic/212967#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 09 Jul 2008 10:39:01 +0800</pubDate>
        <link>http://www.javaeye.com/topic/212967</link>
        <guid>http://www.javaeye.com/topic/212967</guid>
      </item>
      <item>
        <title>分享一款word风格的rails在线编辑器</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://liuqiang.javaeye.com">liuqiang</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/213151" style="color:red;">http://www.javaeye.com/topic/213151</a>&nbsp;
          发表时间: 2008年07月09日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="Section0" style="LAYOUT-GRID:  15.6pt none">
<p class="0"><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"><span style="font-family: 宋体;">&nbsp;&nbsp;&nbsp;&nbsp;在线编辑器是web应用中最常见的东西了，关于它的作用和意义我不想多说什么了。对于编辑器的使用，之前就是随便找个简单的HTML编辑器甚至是textarea来应付，也没花多少时间来整这个东西，但事情开始逐渐变得麻烦起来，因为我们的客户（可能就是你的老板）的要求越来越高：能不能加上点丰富的表情？能不能使编辑器再多支持几种格式排版？或许有一天客户看到了搜狐的编辑器，回来说能不能让我们的编辑器也增加本地图片上传？最好再要加个附件功能，并且也要从本地上传&nbsp;&hellip;&hellip;&hellip;&hellip;，这一切让我以前做的小编辑器显得无地自容，也忒简陋了吧。于是我很自然地想到了rails里面最常用的FCK编辑器，的确，它基本可以满足我的所有需要，可是仍有3点让我感到不大舒服的地方：</span></span><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"></span></p>
<p class="0"><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">&nbsp; 1&nbsp;<span style="font-family: 宋体;">尽管FCk的配置使用已经很方便了，但仍然有不少需要汉化和定制的地方。</span></span><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"></span></p>
<p class="0"><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">&nbsp; 2&nbsp;<span style="font-family: 宋体;">这个东西显的有稍稍有点大，为了性能，我还期望让它再小一点。</span></span><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"></span></p>
<p class="0"><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">&nbsp;&nbsp;3&nbsp;<span style="font-family: 宋体;">这是个不是理由的理由：用户感到单调了，为什么我们的系统里面的编辑器都是一个模样，我们需要点新口味。</span></span><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"></span></p>
<p class="0"><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"></span>&nbsp;</p>
<p class="0"><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"><span style="font-family: 宋体;">&nbsp;&nbsp;&nbsp; 我首先的想法就是改改FCk，旧米做新饭，可是我发现修改FCK不是件容易的事，并且把FCK修改成另外一种风格和结构更难，后来转念一想，反正里外都是改，我何不找另外一款编辑器做做文章，之前在51js混的时候听说新浪的编辑器做的不错，于是load下来看看，豁豁豁&hellip;&hellip;，这不就是word吗？太酷了，我有了马上就使用它的冲动，但是打开源码一看是个asp版本的，并且转为utf8后，注释也成了乱码，好在它的js代码可读性还算比较好，于是我开始着手做两件事，1是裁掉一些功能&nbsp;2是把它转为rails版本的。经过一段时间的修改和维护这个东东算是稳定下来了，使用和效果如下：</span></span></p>
<p class="0"><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">&nbsp;&nbsp;&nbsp; 将editor文件夹放在public下，在需要用编辑器的的form中写：</span></p>
<p class="0"><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"></span>&nbsp;</p>
<pre name="code" class="ruby"><span style="color: #ff0000;"> 注意这里的id不要写成content，貌似是由于命名冲突的原因</span> 
&lt;input type="hidden" id="content1" name="content" value=""&gt;&lt;/input&gt; 
<span style="color: #ff0000;">注意这里要把上面的隐藏域的id穿给编辑器的iframe</span>
 &lt;iframe id="myEditor" src="/editor/editor.htm?id=content1" frameborder="0" scrolling="no" width="550" height="220"&gt;&lt;/iframe&gt;

再附上一段js校验编辑器内容不为空的代码
var content = myEditor.getHTML().replace(/&lt;.*?&gt;/g,"").split(" ").join("").split(" ").join("");
if(content.length==0){
        alert('公告内容不能为空！');
        return false;
    }</pre>
<p class="0">&nbsp;<span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">
<p class="0">&nbsp;</p>
</span></p>
<p class="0"><img src="../../upload/picture/pic/17662/0cff6c23-c499-31a1-9f16-be27f2dbb9e2.jpg " height="464" alt="" width="631" /></p>
<p class="0"><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">&nbsp;&nbsp;&nbsp; 效果还不错吧，下面还有2件重要的事情要做：上传图片和上传附件，之所以说这个是rails版的，也就是这两个功能和rails有点干系。先简分析下上传本地图片吧，原理是这样的，点击上传图片后弹出一个新窗口，叫你输入你的本地图片，这个窗口对应的页面是editor\editor目录下的img.htm文件，打开看看可以看到有个向服务器提交图片的form，并且action指向服务器保存编辑器图片的那个action，用户提交本地图片后，服务器将图片保存，并把该图片的保存地址返还回去，编辑器接收到该图片地址后，插进编辑器的主窗口，这样图片基本就在编辑中显现了，当然你可以在img.htm写上校验逻辑，我已经加上了图片类型判别的js校验。整个流程就是这样，上传本地附件和图片的流程基本一样，上传附件窗口对应的文件是attach.htm文件，只不过服务器保存用户提交的附件后，返还的是下载该附件的地址，我也已经在attach.htm加上zip和rar的校验。注意我已经将上述的东西做好了，无需修改任何东西！当然你可以再去修改成你自己喜好的风格。</span></p>
<p class="0"><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">&nbsp;&nbsp;&nbsp; 接下来就开始写服务器处理上传图片的附件的逻辑了，注意由于我在上传图片和上传附件的form中把action的地址分别指向的是:/front/editors/upload_editor_image和/front/editors/upload_editor_attach，所以如果你不想修改任何东西的话，那么请保证后台的控制器一定要是front/editors,action分别是upload_editor_image和upload_editor_attach。代码附上：</span></p>
<span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">
<pre name="code" class="ruby">class Front::EditorsController &lt; ApplicationController
  skip_before_filter :verify_authenticity_token
  # 上传图片
  def upload_editor_image
    file = params[:imgfile]
    filename = params[:imgfile].original_filename.split('.').reverse  
    filename = Time.now.strftime("%Y%m%d%H%M%S")  + rand(10000).to_s + "." + filename[0]  
    File.open("#{File.expand_path(RAILS_ROOT)}/public/upload/editor_image/#{filename}", "wb") do |f|   
      f.write(file.read)        
    end      
    render :text =&gt; "&lt;script&gt;window.parent.LoadIMG('/upload/editor_image/#{filename}')&lt;/script&gt;"
  rescue
    render :text =&gt; "&lt;script&gt;window.parent.alert('您上传的图片无效或者损坏！');window.parent.divProcessing.style.display='none'; &lt;/script&gt;"
  end
  
  # 上传附件
  def upload_editor_attach
    file = params[:attach]
    filename = params[:attach].original_filename.split('.').reverse  
    filename = Time.now.strftime("%Y%m%d%H%M%S") + rand(10000).to_s + "." + filename[0]  
    File.open("#{File.expand_path(RAILS_ROOT)}/public/upload/editor_attach/#{filename}", "wb") do |f|   
      f.write(file.read)        
    end      
    render :text =&gt; "&lt;script&gt;window.parent.LoadAttach('/upload/editor_attach/#{filename}')&lt;/script&gt;"
  rescue
    render :text =&gt; "&lt;script&gt;window.parent.alert('您上传的附件无效或者损坏！');window.parent.divProcessing.style.display='none'; &lt;/script&gt;"
  end
  
  def download_attach
    send_file params[:path]
  rescue
    render :text =&gt; "对不起，改附件已经损坏，无法下载！"
  end
end
</pre>
<p class="0">&nbsp;</p>
</span>
<p class="0">&nbsp;</p>
<p class="0"><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"></span>&nbsp;效果如下：</p>
<p class="0"><img src="../../upload/picture/pic/17664/73cd0cd5-1038-3a79-a77e-ff62417b1a70.jpg " height="208" alt="" width="412" /></p>
<p class="0">&nbsp;</p>
<p class="0"><img src="../../upload/picture/pic/17660/ae845d1e-c7ce-3dcd-b737-7448aadc4e43.jpg " height="337" alt="" width="649" /></p>
<p class="0">下面是改编辑器的压缩包，直接解压即可。</p>
<p class="0"><span style="font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"></span>&nbsp;</p>
</div>
<!--EndFragment-->
          <br/>
          <span style="color:red;">
            <a href="http://robbin.javaeye.com/topic/213151#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 09 Jul 2008 16:51:10 +0800</pubDate>
        <link>http://www.javaeye.com/topic/213151</link>
        <guid>http://www.javaeye.com/topic/213151</guid>
      </item>
      <item>
        <title>利用rails轻松建立个性化主页门户</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://liuqiang.javaeye.com">liuqiang</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/211468" style="color:red;">http://www.javaeye.com/topic/211468</a>&nbsp;
          发表时间: 2008年07月04日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 简单来说，个性化主页就是结合了各种小模块和网络信息的个人主页。与传统网站的区别是：用户可以非常自由地控制其内容（通过RSS，email等等），内容会更适合用户口味并且使用查看也非常方便，由于有了ajax技术，所以更像是一个桌面软件。例如<a href="http://www.netvibes.com/">http://www.netvibes.com/</a>就提供了比较酷的个性化主页服务。<br />总的来说主要有以下几个特点：</p>
<p>1 页面中的内容是一个个小模块，其内容来自于其他站点或者服务&nbsp;</p>
<p>2 用户可以根据自己的喜好通过拖拽随意摆放这些小模块 </p>
<p>3 用户可以添加自己感兴趣的小模块 </p>
<p>4&nbsp; 用户可以删除任意已添加的小模块 </p>
<p>5 用户可以改变自己的页面风格以及布局。</p>
<p>用rails解决这些问题显得极为简洁，为了简化说明，这里不考虑用户权限，如下：</p>
<p>&nbsp;</p>
<p>1 在主应用（也就是提供主页服务的系统）建立模块加载机制和代理转发功能（依据dlee翻译的《ajax模式与最佳实践》最后一章的MVC模式），在这里简化下就是一个user有N个page,一个page有N列，一列有N个模块。建立模型如下：</p>
<pre name="code" class="ruby">class User &lt; ActiveRecord::Base
   has_many :pages
 end

class Page &lt; ActiveRecord::Base
   has_many :columns
   belongs_to :user
 end

class Column &lt; ActiveRecord::Base
   has_many :cells
   belongs_to :page
end

class Cell &lt; ActiveRecord::Base
      belongs_to :column
end</pre>
<pre name="code" class="ruby">#在后台发起向其他系统调用服务，当然可以带有一些查询参数比如username已取得和该用户相关的模块内容。
def show
    @cell = Cell.find params[:id]
     Net::HTTP.start(@cell.url,@cell.port) do |http|
        response = http.get(<a href="mailto:'#{@cell.path}'">'#{@cell.path}'</a>, 'Accept' =&gt; 'text/xml')
     end
     render :text =&gt; @response.body
 end

#其他系统处理请求并返回，返回结果可以是html/xml/rss/flash/js等等，这里暂用字符串文本代替。
def show
     render :text =&gt; "ok"
 end
</pre>
<p>其中需要说明的是：cells表中应存有name、来源URl、port、path，name表示改模块的名字，URl的作用是记录该cell的内容来自于哪个外部站点的rest服务，port指定外部站点的端口，path指定服务的路径。</p>
<p>&nbsp;</p>
<p>2 利用rails内置的ajax功能处理拖拽，代码如下：</p>
<pre name="code" class="ruby">#为简明起见，取id为1的 page,当然也可以根据user来取page
def index 
    @page = Page.find 1
    @columns = @page.columns
end</pre>
<p>&nbsp;</p>
<pre name="code" class="ruby">  &lt;%= javascript_include_tag :defaults %&gt;</pre>
<pre name="code" class="ruby">&lt;table id="table_&lt;%= @page.id %&gt;" align="center"&gt;
      &lt;tr id="tr_&lt;%= @page.id %&gt;"&gt;
        &lt;% for column in @page.columns %&gt;           
          &lt;td id="td_&lt;%= column.id %&gt;" style="height:auto;word-break:break-all;vertical-align:top;"&gt;       
            &lt;% for cell in column.cells %&gt;            
                &lt;div id="cell_&lt;%= cell.id %&gt;" class="cell"&gt;
                    正在载入……
            &lt;/div&gt;       
            &lt;% end %&gt;
          &lt;/td&gt;
        &lt;% end %&gt;
      &lt;/tr&gt;
    &lt;/table&gt;

     &lt;% for column in @page.columns %&gt;
        &lt;%= sortable_element "td_#{column.id}",  
          :url =&gt; { :action =&gt; "sort" , :column_id =&gt; column.id } , 
          :dropOnEmpty =&gt; true ,   
          :tag =&gt; "div" ,
          :containment =&gt; [
           #一个页面最多可以支持4列，总之把page的所有column设置为拖拽容器即可。
       "td_#{@page.columns[0].id}" ,
          "td_#{@page.columns[1].id}" , 
          "td_#{@page.columns[2].id}" ,
          "td_#{@page.columns[3].id}"
        ] , :constraint =&gt; false %&gt;    
      &lt;% end %&gt;
    &lt;% end %&gt;</pre>
<p>&nbsp;异步地为每个小模块加载内容</p>
<p>&nbsp;</p>
<pre name="code" class="ruby">&lt;script&gt;
window.onload = function(){
&lt;% for column in @page.columns %&gt;                 
      &lt;% for cell in column.cells %&gt;   
                new Ajax.Updater('cell_&lt;%= cell.id %&gt;',
                '/Cell/show/&lt;%= cell.id %&gt;',
                {asynchronous:true,evalScripts:true,method:'get'});
      &lt;% end %&gt;
&lt;% end %&gt;
}
&lt;script&gt;</pre>
<p>&nbsp;</p>
<p>后台处理排序</p>
<pre name="code" class="java">def sort
    @column = Column.find params[:column_id]
    td_index = "td_" + @column.id.to_s 
    list = params[td_index] 
    list.each_with_index { |id,idx| 
      cell = Cell.find id
      cell.column = @column
      cell.row_index = idx.to_i
      cell.save
    } 
end</pre>
<p>&nbsp;</p>
<p>3 向页面添加模块，这里默认向页面的第一列添加，添加模块的div可以做成弹出的浮动div形式。</p>
<pre name="code" class="ruby">   &lt;div&gt;
        &lt;% for cell in @cells %&gt;
              &lt;%= link_to_remote cell.name , :update =&gt; "td_#{@page.columns[0].id}" , :mothod =&gt; :get ,
:url =&gt; {:action =&gt; "add_cell" , :page_id =&gt; @page.id , :id =&gt; cell.id} ,:position =&gt; "top"  %&gt;
         &lt;% end %&gt; 
  &lt;/div&gt;
</pre>
<p>&nbsp;后台代码如下：</p>
<pre name="code" class="ruby">def add_Cell
    @page = Page.find params[:page_id]
     #获取该页面的第一列，column_index表示改列的列标
    @column = Column.find :first , :conditions =&gt; ["page_id=? and column_index=?" , @page.id , 1]
      @cell = Cell.find params[:id]
      @cell.column = @column
      @cell.row_index =  0#row_index 表示该模块在一列中的位置
    @cell.save
end</pre>
<p>&nbsp;</p>
<p>&nbsp;4 删除模块</p>
<pre name="code" class="java">#在这里简单的删除该cell记录，前台直接隐藏该cell的div再向后台发送ajax请求。
def delete_cell
    Cell.delete params[:id]
end</pre>
<p>&nbsp;</p>
<p>5 关于设置主题和列数，这个用ajax实现比较容易也比较常见，在此不做解释了。</p>
<p>&nbsp;</p>
<p>6 这里仅提供了一个思路，很多地方可以完善和扩展，比如在现实中column和cell应为多对多的关系，这里简化为一对多，这个方案已经过简单的扩展和测试，效果还不错。</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://robbin.javaeye.com/topic/211468#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 04 Jul 2008 12:10:02 +0800</pubDate>
        <link>http://www.javaeye.com/topic/211468</link>
        <guid>http://www.javaeye.com/topic/211468</guid>
      </item>
      <item>
        <title>RubyCAS-----来自ruby世界的一款灵巧的CAS服务器</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://liuqiang.javaeye.com">liuqiang</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/212170" style="color:red;">http://www.javaeye.com/topic/212170</a>&nbsp;
          发表时间: 2008年07月07日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><span style="font-family: 仿宋;"><span style="font-weight: bold; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">
<p class="0">&nbsp;</p>
<p><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"><span style="font-family: 宋体;"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"><span style="font-family: 宋体;"><font face="'宋体'" style="font-weight: normal; font-size: 10.5pt; mso-spacerun: 'yes';"><font face="宋体"><font face="'宋体'" style="font-weight: normal; font-size: 10.5pt; mso-spacerun: 'yes';"><font face="宋体">
<p class="0">&nbsp;&nbsp;&nbsp;&nbsp;说到cas服务器，首先想到的是耶鲁大学的那款基于java的开源cas服务器，研究一段时间后发现，不是很让人满意，首先是配置过程有点麻烦，新版本的java&nbsp;cas&nbsp;server&nbsp;基于spring&nbsp;framework，用maven部署打包，如果没有一定java功底的话，很难驾驭它。再有就是定制过程麻烦，要对源码做一些修改，这就要求对源码结构有一定的了解。另外还有一些数字证书导入导出的繁琐过程。</p>
</font></font></font></font></span><font face="'宋体'" style="font-weight: normal; font-size: 10.5pt; mso-spacerun: 'yes';"><font face="宋体"><font face="'宋体'" style="font-weight: normal; font-size: 10.5pt; mso-spacerun: 'yes';">
<p class="0">&nbsp;</p>
</font></font></font></span><font face="'宋体'" style="font-weight: normal; font-size: 10.5pt; mso-spacerun: 'yes';"><font face="宋体">
<p class="0">&nbsp;</p>
</font></font></span><font face="'宋体'" style="font-weight: normal; font-size: 10.5pt; mso-spacerun: 'yes';">
<p class="0">&nbsp;</p>
</font></span>
<p class="0">&nbsp;</p>
</p>
<p>&nbsp;</p>
<p class="0"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"><span style="font-family: 宋体;">&nbsp;&nbsp;&nbsp; 那么现在就让Ruby将生活变得简单点，让</span></span><span style="font-weight: normal; font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes';">Rub</span><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">yCAS<span style="font-family: 宋体;">将sso问题变得的容易些吧。之所以说</span></span><span style="font-weight: normal; font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes';">Rub</span><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">yCAS<span style="font-family: 宋体;">灵巧主要有以下几个原因：</span></span></p>
<p class="0"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">&nbsp;&nbsp;&nbsp; 1&nbsp;<span style="font-family: 宋体;">安装部署简单，你甚至可以不了解ruby编程。</span></span></p>
<p class="0"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">&nbsp;&nbsp;&nbsp; 2&nbsp;<span style="font-family: 宋体;">可以不用SSL，因为很多应用，比如论坛博客社区等系统没有那么高的安全性要求，我们也不想在页面跳转时出现警告框。</span></span></p>
<p class="0"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">&nbsp;&nbsp;&nbsp; 3 可以用SSL,但它的过程是非常简单的，只需安装个gem即可。</span></p>
<p class="0"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;<span style="font-family: 宋体;">定制简单，基本所有的定制在一个yml文件就搞定了。</span></span></p>
<p class="0">&nbsp;&nbsp;&nbsp; &hellip;&hellip;&hellip;&hellip;</p>
<p class="0"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"><span style="font-family: 宋体;">&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://code.google.com/p/rubycas-server/wiki/QuickStart">http://code.google.com/p/rubycas-server/wiki/QuickStart</a>，这里有linux下配置安装的说明，那下面我就展示下windows/WEBrick平台下的安装部署测试过程。</span></span></p>
<p>&nbsp;</p>
<p class="0">&nbsp;</p>
<p class="0"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">1&nbsp;<span style="font-family: 宋体;">安装</span></span><span style="font-weight: normal; font-size: 10.5pt; font-family: 'Times New Roman'; mso-spacerun: 'yes';">Rub</span><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">yCAS，安装之前请保证你的你的机器已经装有ruby 1.8.4或更新的版本。在shell中输入：gem install rubycas-server </span></p>
<p class="0">&nbsp;</p>
<p class="0"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">2 <span style="font-family: 宋体;">必要的配置，主要是指定cas server的端口、用户数据库以及验证策略，打开C:\ruby\lib\ruby\gems\1.8\gems\rubycas-server-0.6.0目录，新建config.yml文件，并将config.example.yml文件的内容全部拷贝进去，由于yml文件的可读性非常好，所以基本都可以理解其中的配置项，把以下3个地方的注释去掉并做如下修改：</span></span></p>
<pre name="code" class="ruby">server: webrick 
port: 443 
#ssl_cert: /path/to/your/ssl.pem 

database: adapter: mysql 
database: cas 
username: root 
password: 123456 
host: localhost 

authenticator: class: CASServer::Authenticators::SQL      
    database:cas    
    adapter: mysql 
    database: cas 
    username: root 
    password: 123456 
    server: localhost 
  user_table: users 
  username_column: username password_column: password </pre>
<p class="0">&nbsp;&nbsp;</p>
<p>
<p class="0"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">3 <span style="font-family: 宋体;">为了能在windows下运转正常，修改一行代码，linux平台下就省去这一步。打开C:\ruby\lib\ruby\gems\1.8\gems\rubycas-server-0.6.0\lib目录中的casserver.rb文件，</span></span></p>
<p class="0"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"><span style="font-family: 宋体;">找到这行：
<p><span style="color: #ff0000;">$CONFIG_FILE ||= '/etc/rubycas-server/config.yml'</span></p>
<p class="0">&nbsp;改为：</p>
<span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"><span style="font-family: 宋体;"><font face="'宋体'" style="font-weight: normal; font-size: 10.5pt; mso-spacerun: 'yes';"><font face="宋体"><font face="'宋体'" style="font-weight: normal; font-size: 10.5pt; mso-spacerun: 'yes';"><font face="宋体">
<p class="0"><span style="color: #ff0000;">$CONFIG_FILE ||= 'C:\ruby\lib\ruby\gems\1.8\gems\rubycas-server-0.6.0\config.yml'</span></p>
</font></font></font></font></span><font face="'宋体'" style="font-weight: normal; font-size: 10.5pt; mso-spacerun: 'yes';"><font face="宋体"><font face="'宋体'" style="font-weight: normal; font-size: 10.5pt; mso-spacerun: 'yes';">
<p class="0">&nbsp;</p>
</font></font></font></span><font face="'宋体'" style="font-weight: normal; font-size: 10.5pt; mso-spacerun: 'yes';"><font face="宋体">
<p class="0">&nbsp;</p>
</font></font></span><font face="'宋体'" style="font-weight: normal; font-size: 10.5pt; mso-spacerun: 'yes';">
<p class="0">&nbsp;</p>
</font></span>
<p class="0">&nbsp;</p>
</p>
<p class="0">&nbsp;</p>
<p class="0"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">4&nbsp;<span style="font-family: 宋体;">以上3步基本搞定cas&nbsp;server所有该做的事情了，事情就那么简单，在cmd中输入rubycas-server启动cas server,访问<a href="http://localhost:443">http://localhost:443</a>即可看到登录界面。</span></span><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';"><span style="font-family: 宋体;">那么下面我们编写客户端测试吧，这里我采用的是ruby做客户端，<a href="../../../topic/210994">http://www.javaeye.com/topic/210994</a>这篇文章已经介绍了ruby客户端的配置使用，在这里只要在<span style="font-family: Courier New;">config/environment.rb</span> 文件中最后那段修改为：</span></span></p>
<p class="0">&nbsp;</p>
</p>
<pre>CASClient::Frameworks::Rails::Filter.configure( :cas_base_url =&gt; http://localhost:443 ) </pre>
<font face="仿宋"><font face="'宋体'" style="font-weight: bold; font-size: 10.5pt; mso-spacerun: 'yes';">
<p>
<p class="0">&nbsp;</p>
<p class="0">&nbsp;</p>
<span style="font-weight: bold; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">
<p class="0"><span style="font-weight: normal; font-size: 10.5pt; font-family: '宋体'; mso-spacerun: 'yes';">5&nbsp;按照上一步建立2个rails应用A和B,分别装上rubycas客户端，我的测试结果如下，访问A时跳到了cas服务器登录界面，只有输入正确密码才跳回A,这时访问B时无需验证直接进入，并通过session[:cas_user]得到了在访问A时登入的用户名，关闭浏览器，A B反过来再来一遍，一样是可以的。</span></p>
</span></p>
</font>
<p class="0">&nbsp;</p>
</font></span><font face="仿宋">
<p>
<p class="0">&nbsp;</p>
</p>
</font></span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><!--EndFragment--><a href="http://code.google.com/p/rubycas-server/">http://code.google.com/p/rubycas-server/</a></p>
          <br/>
          <span style="color:red;">
            <a href="http://robbin.javaeye.com/topic/212170#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 07 Jul 2008 08:52:07 +0800</pubDate>
        <link>http://www.javaeye.com/topic/212170</link>
        <guid>http://www.javaeye.com/topic/212170</guid>
      </item>
      <item>
        <title>Spring Framework 2.5 Reference中文版正式发布</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://digitalsonic.javaeye.com">DigitalSonic</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/209974" style="color:red;">http://www.javaeye.com/topic/209974</a>&nbsp;
          发表时间: 2008年07月01日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong><span style="font-size: small;">声明</span> </strong><br />Spring中文参考手册得到Spring Framework开发团队的直接授权和大力的支持，其目的是在中文世界推广优秀的开源技术。本次翻译活动由满江红开放技术研究组织(<a href="http://www.redsaga.com" target="_blank">http://www.redsaga.com</a> )和Spring中文论坛(<a href="http://spring.jactiongroup.net" target="_blank">http://spring.jactiongroup.net</a> ) 共同发起、组织。我们在此郑重宣布，本次翻译遵循原Spring Framework的授权协议，即Apache 2.0协议。在完整保留全部文本(包括本版权页)，并且不违反Apache 2.0协议的前提下，允许和鼓励任何人进行全文转载及推广，所有参与人员放弃除署名权外的一切权利。<br /><br /><strong><span style="font-size: small;">致谢</span> </strong><br />如此庞大的项目不是一两个组织可以独立完成的，就像Spring本身一样，涵盖了Java技术的方方面面。因为有了大家的关心和支持才使此次项目能够顺利完成。有理由相信，中文开源世界必将在不久的将来展现出更广阔的发展空间，希望大家都能为推动中国软件发展奉献出自己的一份力量。<br /><br />项目主页：<br /><a href="http://wiki.redsaga.com/confluence/display/Spring2/Spring2.5" target="_blank">http://wiki.redsaga.com/confluence/display/Spring2/Spring2.5</a> <br /><br />在线版本：<br /><a href="http://www.redsaga.com/spring_ref/2.5/html/" target="_blank">HTML</a> / <a href="http://www.redsaga.com/spring_ref/2.5/html_single/" target="_blank">HTML Single</a> <br /><br />下载地址：<br /><a href="http://www.redsaga.com/spring_ref/2.5/spring-reference.pdf" target="_blank">PDF(593页，4.41MB)</a> / <a href="http://www.redsaga.com/spring_ref/2.5/Spring-Reference_zh_CN.chm" target="_blank">CHM(2.08MB)</a> <br /><br />勘误表：<br /><a href="http://wiki.redsaga.com/confluence/pages/viewpage.action?pageId=3171" target="_blank">http://wiki.redsaga.com/confluence/pages/viewpage.action?pageId=3171</a> </p>
          <br/>
          <span style="color:red;">
            <a href="http://robbin.javaeye.com/topic/209974#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 01 Jul 2008 00:01:54 +0800</pubDate>
        <link>http://www.javaeye.com/topic/209974</link>
        <guid>http://www.javaeye.com/topic/209974</guid>
      </item>
      <item>
        <title>MySQL Storage Engine 小记</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://mozart.javaeye.com">Mozart</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/211951" style="color:red;">http://www.javaeye.com/topic/211951</a>&nbsp;
          发表时间: 2008年07月05日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>这段时间在看《High Performance MySQL》，看到存储引擎这个地方感到很多细节比较陌生，所以总结小记一些<br />
<br />
为了适应各种不同的运行环境，MYSQL提供了多种不同的存储引擎（Storage Engine ）,在应用程序开发这个层面上，开发者可以根据不同的需求选择适合的Storage Engine 方案，更为灵活的是，你可以根据每张表将要存储数据的特点，选择不同的Storage Engine,也就是说，在一个MYSQL数据库中，可以混合使用多种不同的Storage Engine<br />
<br />
首先小瞥一下MySQL的体系结构，在最高抽象层度下，可以用Garlan &amp; Shaw的分层结构体系来表示（左）<br />
<img src="../../upload/picture/pic/17429/e9ca34d9-432d-3ad2-b8d9-d13b45b74fc9.jpg" alt="" />
<br />
其中应用层为所有RDBMS用户提供用户接口，逻辑层包括了所有核心功能的实现，物理层则负责将数据存储在硬件设备上。<br />
<br />
图中右侧更为具体的描述了逻辑层的组成，查询处理子系统、事务管理子系统、恢复管理子系统和存储管理子系统共同组成了MySQL的逻辑层。相信Storage Engine的位置是在Storage Management处，既Storage Engine属于Storage Management子系统的一部分<br />
<br />
为了让思路更清晰一些，下面给出一幅比较全面的体系结构图（或更确切的说是流程图，只是忽略了反馈）<br />
<img src="../../upload/picture/pic/17425/e3795bbd-c9d8-3c04-bc0e-83db0bfb8322.jpg" height="770" alt="" width="616" />
<br />
上面三幅图来自于一篇非官方（不保证百分百的正确）的MySQL体系结构的报告，与《High Performance MySQL》一书中给出的MySQL大体结构（下图,基本对应于Logic Layer，从第一幅图右侧可以看出MySQL logic layer同样遵从分层体系结构）还是比较吻合的。<br />
<img src="../../upload/picture/pic/17423/a8a8105e-5ba7-3c4d-9bc3-6716c7bb9c3c.jpg" height="226" alt="" width="373" />
<br />
连接上图中第二层和第三层之间的接口是并不针对任何存储引擎的单一API,.大概由20个基本的类似&ldquo;启动事务，返回结果集&rdquo;等函数组成。存储引擎并不处理SQL，相互之间也不通信，它们的任务只是简单的响应高层传来的请求。<br />
<br />
<strong><span style="font-size: small;">存储引擎各自的一些特点</span>
</strong>
<br />
<br />
上面提到的四种存储引擎都有各自适用的环境，这取决于它们独有的一些特征。主要体现在性能、事务、并发控制、参照完整性、缓存、 故障恢复，备份及回存等几个方面<br />
<br />
<br />
目前比较普及的存储引擎是MyISAM和InnoDB.而MyISAM又是绝大部分Web应用的首选。MyISAM与InnoDB的主要的不同点在于性能和事务控制上。<br />
<br />
MyISAM是早期ISAM(Indexed Sequential Access Method,我现在用的MySQL5.0已经不支持ISAM了）的扩展实现，ISAM被设计为适合处理读频率远大于写频率这样一种情况，因此ISAM以及后来的MyISAM都没有考虑对事物的支持，排除了TPM，不需要事务记录，ISAM的查询效率相当可观，而且内存占用很少。MyISAM在继承了这类优点的同时，与时俱进的提供了大量实用的新特性和相关工具。例如考虑到并发控制，提供了表级锁，虽然MyISAM本身不支持容错，但可以通过myisamchk进行故障恢复。而且由于MyISAM是每张表使用各自独立的存储文件（MYD数据文件和MYI索引文件），使得备份及恢复十分方便（拷贝覆盖即可），而且还支持在线恢复。<br />
<br />
所以如果你的应用是不需要事务，处理的只是基本的CRUD操作，那么MyISAM是不二选择<br />
<br />
InnoDB被设计成适用于高并发读写的情况.使用MVCC(Multi-Version Concurrency Control)以及行级锁来提供遵从ACID的事务支持。InnoDB支持外键参照完整性，具备故障恢复能力。另外 InnoDB的性能其实还是不错的，特别是在处理大数据量的情况下,用官方的话说就是： InnoDB的CPU效率是其他基于磁盘的关系数据库存储引擎所不能比的。不过InnoDB的备份恢复要麻烦一点，除非你使用了4.1以后版本提供的Mulit-tablespace支持，因为InnoDB和MyISAM不同，他的数据文件并不是独立对应于每张表的。而是使用的共享表空间，简单的拷贝覆盖方法对他不适用，必须在停掉MYSQL后对进行数据恢复。使用Per-Table Tablespacesd，使其每张表对应一个独立的表空间文件，则情况要简单很多。<br />
<br />
一般来说，如果需要事务支持，并且有较高的并发读写频率，InnoDB是不错的选择。要是并发读写频率不高的话，其实可以考虑BDB,但由于在MySQL5.1及其以后版本中，将不再提供BDB支持。这个选项也就没有了<br />
<br />
至于Heap和BDB（Berkeley DB），相对来说，普及率不如前两种，但在有些情况下，还是挺适用的<br />
<br />
Heap存储引擎就是将数据存储在内存中，由于没有磁盘I./O的等待，速度极快。但由于是内存存储引擎，所做的任何修改在服务器重启后都将消失。<br />
&nbsp;<br />
Heap挺适合做测试的时候使用<br />
<br />
<br />
BDB是MySQL第一款事务安全的存储引擎。在Berkeley DB database library的基础上建立，同样是事务安全的，但BDB的普及率显然不及InnoDB，因为大多数在MySQL中寻找支持事务的存储引擎的同时也在找支持MVCC或是行级锁定存储引擎，而BDB只支持Page-level Lock。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>附上一张《High Performance MySQL》 中的各存储引擎的特性表</p>
<table rules="all" cellspacing="0" border="1" width="100%" cellpadding="4">
<thead>
<tr>
<th class="docTableHeader">
<p class="docText">Attribute</p>
</th>
<th class="docTableHeader">
<p class="docText">MyISAM</p>
</th>
<th class="docTableHeader">
<p class="docText">Heap</p>
</th>
<th class="docTableHeader">
<p class="docText">BDB</p>
</th>
<th class="docTableHeader">
<p class="docText">InnoDB</p>
</th>
</tr>
</thead>

<tbody>
<tr>
<td class="docTableCell">
<p class="docText">Transactions</p>
</td>
<td class="docTableCell">
<p class="docText">No</p>
</td>
<td class="docTableCell">
<p class="docText">No</p>
</td>
<td class="docTableCell">
<p class="docText">Yes</p>
</td>
<td class="docTableCell">
<p class="docText">Yes</p>
</td>
</tr>
<tr>
<td class="docTableCell">
<p class="docText">Lock granularity</p>
</td>
<td class="docTableCell">
<p class="docText">Table</p>
</td>
<td class="docTableCell">
<p class="docText">Table</p>
</td>
<td class="docTableCell">
<p class="docText">Page (8 KB)</p>
</td>
<td class="docTableCell">
<p class="docText">Row</p>
</td>
</tr>
<tr>
<td class="docTableCell">
<p class="docText">Storage</p>
</td>
<td class="docTableCell">
<p class="docText">Split files</p>
</td>
<td class="docTableCell">
<p class="docText">In-memory</p>
</td>
<td class="docTableCell">
<p class="docText">Single file per table</p>
</td>
<td class="docTableCell">
<p class="docText">Tablespace(s)</p>
</td>
</tr>
<tr>
<td class="docTableCell">
<p class="docText">Isolation levels</p>
</td>
<td class="docTableCell">
<p class="docText">None</p>
</td>
<td class="docTableCell">
<p class="docText">None</p>
</td>
<td class="docTableCell">
<p class="docText">Read committed</p>
</td>
<td class="docTableCell">
<p class="docText">All</p>
</td>
</tr>
<tr>
<td class="docTableCell">
<p class="docText">Portable format</p>
</td>
<td class="docTableCell">
<p class="docText">Yes</p>
</td>
<td class="docTableCell">
<p class="docText">N/A</p>
</td>
<td class="docTableCell">
<p class="docText">No</p>
</td>
<td class="docTableCell">
<p class="docText">Yes</p>
</td>
</tr>
<tr>
<td class="docTableCell">
<p class="docText">Referential integrity</p>
</td>
<td class="docTableCell">
<p class="docText">No</p>
</td>
<td class="docTableCell">
<p class="docText">No</p>
</td>
<td class="docTableCell">
<p class="docText">No</p>
</td>
<td class="docTableCell">
<p class="docText">Yes</p>
</td>
</tr>
<tr>
<td class="docTableCell">
<p class="docText">Primary key with data</p>
</td>
<td class="docTableCell">
<p class="docText">No</p>
</td>
<td class="docTableCell">
<p class="docText">No</p>
</td>
<td class="docTableCell">
<p class="docText">Yes</p>
</td>
<td class="docTableCell">
<p class="docText">Yes</p>
</td>
</tr>
<tr>
<td class="docTableCell">
<p class="docText">MySQL caches data records</p>
</td>
<td class="docTableCell">
<p class="docText">No</p>
</td>
<td class="docTableCell">
<p class="docText">Yes</p>
</td>
<td class="docTableCell">
<p class="docText">Yes</p>
</td>
<td class="docTableCell">
<p class="docText">Yes</p>
</td>
</tr>
<tr>
<td class="docTableCell">
<p class="docText">Availability</p>
</td>
<td class="docTableCell">
<p class="docText">All versions</p>
</td>
<td class="docTableCell">
<p class="docText">All versions</p>
</td>
<td class="docTableCell">
<p class="docText">MySQL-Max</p>
</td>
<td class="docTableCell">
<p class="docText">All Versions</p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://robbin.javaeye.com/topic/211951#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 05 Jul 2008 23:35:13 +0800</pubDate>
        <link>http://www.javaeye.com/topic/211951</link>
        <guid>http://www.javaeye.com/topic/211951</guid>
      </item>
      <item>
        <title>ruby+cas实现sso</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://liuqiang.javaeye.com">liuqiang</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/210994" style="color:red;">http://www.javaeye.com/topic/210994</a>&nbsp;
          发表时间: 2008年07月03日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>之前做了几个基于ruby,java的系统，现在想把它们整合到一起，首先遇到了单点登录问题，开始是用跨域iframe来实现，效果还行，但安全性不大高，所以还是打算上cas，方案如下:</p>
<p>1 安装cas3.0并配置<a href="210679">http://liuqiang.javaeye.com/admin/blogs/210679</a>，保证<a href="http://localhost:8080/cas">http://localhost:8080/cas</a>能正常运行。</p>
<p>&nbsp;</p>
<p>2 安装ruby的cas客户端：进入项目根目录，运行ruby script/plugin install <a href="http://rubycas-client.googlecode.com/svn/trunk/rubycas-client">http://rubycas-client.googlecode.com/svn/trunk/rubycas-client</a></p>
<p>&nbsp;</p>
<p>3 打开<span style="font-family: Courier New;">config/environment.rb</span> ，在该文件最后也就是等rails初始化完毕，加上 CASClient::Frameworks::Rails::Filter.configure(<br />&nbsp;&nbsp;&nbsp; :cas_base_url =&gt; "<a href="http://localhost:8080/cas">http://localhost:8080/cas</a>"<br />&nbsp; )</p>
<p>&nbsp;</p>
<p>4 在需要校验的控制器中加入 before_filter CASClient::Frameworks::Rails::Filter</p>
<p>&nbsp;</p>
<p>5 在视图中加入登录链接：&lt;a href="/front/sessions/login"&gt;登录&lt;/a&gt;</p>
<p>&nbsp;</p>
<p>6 在负责处理登录的控制器中加上 before_filter :set_current_url , CASClient::Frameworks::Rails::Filter</p>
<pre name="code" class="ruby"> <pre name="code" class="java"> before_filter :set_current_url ,CASClient::Frameworks::Rails::Filter

  def set_current_url
#记下来源url,因为在之后的验证过程中，来源url会丢失
    cookies[:current_url] = request.referer
  end

 def cas_login
#跳到来源url
    redirect_to cookies[:current_url]
  end</pre>
&nbsp;</pre>
<p>&nbsp;<br />7 登录完毕后可以用session[:cas_user]将登录的用户名取出</p>
          <br/>
          <span style="color:red;">
            <a href="http://robbin.javaeye.com/topic/210994#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 03 Jul 2008 12:02:34 +0800</pubDate>
        <link>http://www.javaeye.com/topic/210994</link>
        <guid>http://www.javaeye.com/topic/210994</guid>
      </item>
      <item>
        <title>改善 Dojo 应用程序的初始下载时间</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://dzt.javaeye.com">dzt</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/207354" style="color:red;">http://www.javaeye.com/topic/207354</a>&nbsp;
          发表时间: 2008年06月24日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;&nbsp;&nbsp; 加载 Ajax 应用程序之后，随后它将获取较小的数据和内容片段，以避免重新呈现整个页面的开销，从而提高性能。这样做的代价是，应用程序的初始下载时间通常会较长。本文将讨论如何减少 Dojo 应用程序的初始下载时间并同时获得很好的性能。</p>
<p>&nbsp;</p>
<p><strong><span style="font-size: medium;"><a name="N1008C"><span class="atitle">仅获取所需的数据</span>
</a>
</span>
</strong>
</p>
<p>&nbsp;&nbsp;&nbsp; Asynchronous
JavaScript and XML (Ajax) 应用程序能够提高某些 Web
应用程序的性能。加载应用程序之后，获取较小的数据和内容片段可以帮助避免重新呈现整个页面的开销。不过，这样做得的代价是，应用程序的初始下载时间通常
会比较长。</p>
<p>&nbsp;&nbsp;&nbsp; 我现在已有多年的 Dojo 应用程序使用经验。<a href="http://www-306.ibm.com/software/webservers/appserv/was/featurepacks/web20/">IBM&reg; WebSphere&reg; Application Server Feature Pack for Web 2.0</a>
 和 <a href="http://www.projectzero.org/">Project Zero</a>
 现在都包括 <a href="http://dojotoolkit.org/">Dojo Toolkit</a>
的 IBM 分发版本，提供了一些增值扩展。由于 Dojo Toolkit
的模块化特性，初始加载可能会花费相当长的时间，因为使用的每个模块可能都需要下载一些 JavaScript&trade;、HTML 和 CSS
文件。这会在网络上带来大量额外的 IO 操作，远远超过每个模块本身的大小。</p>
<p>&nbsp;&nbsp;&nbsp; 通常，这个模块化特征是程序员所必需的，因为通过其可以方便地进行调试和编码，但编写了应用程序之后，此模块化特征就不再重要了&mdash;&mdash;或不再需要了。您可以通过多种方法减少 Dojo 应用程序的初始下载时间。</p>
<p>&nbsp;</p>
<p><strong><span style="font-size: medium;"><a name="sec2"><span class="atitle">使用 Dojo 构建和打包系统</span>
</a>
</span>
</strong>
</p>
<p>&nbsp;&nbsp;&nbsp; Dojo Toolkit 提供了打包和压缩技术，用于将在应用程序中使用的 Dojo 代码打包为单个文件，然后使用名为 Dojo
ShrinkSafe 的压缩技术将其压缩到最小尺寸。大部分 Dojo
应用程序都应该将此技术作为其部署的一部分使用，因为此技术将极大地提高应用程序的性能（特别是初始下载时间）。您只需要为应用程序创建概要，并在其中指
定要使用哪个 Dojo 组件。清单 1 显示了一个示例。</p>
<p>&nbsp;&nbsp;&nbsp; <strong><a name="N100B7"><strong>清单 1. 示例概要</strong>
</a>
</strong>
</p>
<p>&nbsp;</p>
<pre name="code" class="js">dependencies ={

    layers:  [
        {
        name: &quot;example.js&quot;,
        dependencies: [
			
			&quot;dojo.*&quot;,
			&quot;dojo.parser&quot;,
			&quot;dijit.dijit&quot;,
			&quot;dijit.Declaration&quot;,
			&quot;dijit.layout.LayoutContainer&quot;,
			&quot;dojox.layout.ContentPane&quot;,
			&quot;dijit.Toolbar&quot;,
			&quot;dijit.layout.AccordionContainer&quot;,
			&quot;my.widget.Super&quot;         
       	]
        }
    ],
	
	
    prefixes: [
        
		[ &quot;dijit&quot;, &quot;../dijit&quot; ],
		[ &quot;my&quot;, &quot;/myWidgets&quot;],
		[ &quot;dojox&quot;, &quot;../dojox&quot; ]
    ]

};</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 然后您将运行命令行构建工具，使用各种选项传入概要。Dojo 构建然后将应用程序所需的所有代码（包括 JavaScript、HTML 和
CSS）放入单个文件中，并对其进行压缩。通过使用此方法，我发现在应用程序初始下载中，IO 调用的数量可能从 200 个以上减少到 2 个或 3
个。我还发现总体大小减少了约 60%。将很快推出关于使用 Dojo 构建和打包系统的 developerWorks 教程，不过在 <a href="http://dojotoolkit.org/book/dojo-book-0-9/part-4-meta-dojo/package-system-and-custom-builds">Dojo 网站</a>
上提供了关于打包系统和自定义构建的更多信息。</p>
<p>&nbsp;</p>
<p><strong><a name="sec3"><span class="atitle"><span style="font-size: medium;">延迟加载和缓存 Dojo 内容</span>
 </span>
</a>
</strong>
</p>
<p>可
以极大减少初始下载大小的另一个方法是，对页面的内容部分进行延迟加载，并在加载之后对其进行缓存。有时候，这样的做法会更好：不在首次访问应用程序时就
加载所需的所有东西，而仅在这个时候加载应用程序的部分内容。用户完全可能会在访问站点时从来不会访问 Web
应用程序的某些特定部分，因此下载这些不会接触的部分所消耗的时间都浪费掉了。所以，您并不需要下载应用程序中可能不会使用的部分。而且，第一印象极为重
要：如果不能快速显示初始主页，可能会让用户更快放弃使用您的程序。</p>
<p>通常，您会希望加载包含初始菜单的布局，然后在加载之后获取主页内容。常见 Dojo 应用程序通常由一些布局元素组成。请看清单 2：</p>
<p>
            <br />
<a name="N100D2"><strong>
清单 2. 布局</strong>
</a>
</p>
<p>&nbsp;</p>
<pre name="code" class="js">&lt;body class=&quot;tundra&quot;&gt;
	&lt;div dojoType=&quot;dijit.layout.LayoutContainer&quot; 
		layoutChildPriority=&quot;top-bottom&quot; 
		id=&quot;main&quot; 
		class=&quot;layout&quot; &gt;
		&lt;div dojoType=&quot;dijit.layout.ContentPane&quot; 
			layoutAlign=&quot;top&quot; class=&quot;banner&quot;&gt;
			&lt;h2&gt;Electronic and Movie Depot !!&lt;/h2&gt;
		&lt;/div&gt;
		&lt;div dojoType=&quot;dijit.layout.ContentPane&quot; 
			layoutAlign=&quot;top&quot; class=&quot;menu&quot;&gt;
			&lt;div dojoType=&quot;dijit.Toolbar&quot; id=&quot;mainMenuBar&quot;&gt;
				&lt;div dojoType=&quot;dijit.form.Button&quot; 
					id=&quot;productListMenu&quot; 
					onclick=&quot;showItem('productList',
						'product/product.html');&quot;&gt;
					Shopping
				&lt;/div&gt;
				&lt;div dojoType=&quot;dijit.form.Button&quot; 
					id=&quot;orderListMenu&quot; onclick=&quot;showItem('orderPage',
						'cart/cart.html');&quot;&gt;
					Shopping Cart
				&lt;/div&gt;
			&lt;/div&gt;
		&lt;/div&gt;
		&lt;div dojoType=&quot;dijit.layout.ContentPane&quot; 
			class=&quot;mainArea&quot; 
			id=&quot;center&quot; layoutAlign=&quot;client&quot;&gt;
			&lt;div dojoType=&quot;dojox.layout.ContentPane&quot; 
				executeScripts=&quot;true&quot; id=&quot;productList&quot; 
				style=&quot;display:none&quot;&gt;
			&lt;/div&gt;
			&lt;div dojoType=&quot;dojox.layout.ContentPane&quot; 
				executeScripts=&quot;true&quot; 
				id=&quot;orderPage&quot; 
				style=&quot;display:none&quot;&gt;
			&lt;/div&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/body&gt;</pre>
&nbsp;
<p>通过清单 2 可以了解一些事项。我创建了一个简单的方法来将 HTML 片段加载到特定的内容中。我还使用
dojox.layout.ContentPane 替代了缺省 dijit。扩展的内容窗格允许在加载区域时执行
JavaScript。通过这样，不仅可以延迟加载 HTML 内容，还可以采用延迟加载方式加载关联的逻辑。清单 3
显示了我所编写的实用方法的实现。</p>
<p>
            <br />
<a name="N100DE"><strong>清单 3. 延迟加载</strong>
</a>
</p>
<p>&nbsp;</p>
<pre name="code" class="js">var loaded = new dojox.collections.Dictionary();

function hideAll()
{
	console.debug(&quot;Hiding other content&quot;);
	var ids = loaded.getKeyList();
	console.debug(&quot;Getting ID -&gt; &quot; + ids);
	console.debug(&quot;List is Array&quot;);
	for (var id in ids) {
		console.debug(&quot;Getting section -&gt; &quot; + ids[id]);
		var section = dijit.byId(ids[id]);
		console.debug(&quot;Got Section -&gt; &quot; + section);
		if (section) {
			console.debug(&quot;setting DOM&quot;);
			section.domNode.style.display = &quot;none&quot;;
		}
	}
	console.debug(&quot;Content is hid&quot;);
}

function showItem(key,template)
{
	hideAll();
	console.debug(&quot;Show Item -&gt; &quot; + key);
	var item = dijit.byId(key);	
	console.debug(item);
	if (item) 
	{
		if(!loaded.contains(key))
		{
			item.setHref(template);
			item.refresh();
			loaded.add(key,template);
		}
		
		item.domNode.style.display =&quot;block&quot;;
	}
}

/**
 * Load Default page
 */
dojo.addOnLoad(function loadDefault()
{
	console.debug(&quot;Loading initial state&quot;);
	showItem('productList','product/product.html');
});</pre>
&nbsp;
<p>&nbsp;&nbsp;&nbsp; 在清单 3 中调用 showItem 时，我隐藏了在主体中可能可见的任何内容。我然后进行检查，确定是否加载了
HTML。如果未加载，将下载模板，然后将其缓存在 Dojo 词典中。下次请求此页面时，将会直接显示该区域。我还使用
dojo.addOnLoad 方法加载缺省页面。</p>
<p>&nbsp;&nbsp;&nbsp; 在清单 3 中调用 showItem
时，我隐藏了在主体中可能可见的任何内容。我然后进行检查，确定是否加载了 HTML。如果未加载，将下载模板，然后将其缓存在 Dojo
词典中。下次请求此页面时，将会直接显示该区域。我还使用 dojo.addOnLoad 方法加载缺省页面。</p>
<p>&nbsp;</p>
<p><strong><span style="font-size: medium;"><a name="sec4"><span class="atitle">不要全部使用 dijit</span>
</a>
</span>
</strong>
</p>
<p>我们很可能喜欢为主要应用程序组件创建 dijit（Dojo 小部件）。例如，在清单 4 中，可以看到将应用程序处理为 Dojo dijit 的示例。</p>
<p>
            <br />
<a name="N100F5"><strong>清单 4. 将应用程序处理为 dijit 可以减少下载时间</strong>
</a>
</p>
<p>&nbsp;</p>
<pre name="code" class="js">&lt;div dojoAttachPoint = &quot;registerId&quot;
	dojoType=&quot;registration:RegistrationWidget&quot; 
	style=&quot;display:none&quot;
&gt;
&lt;/div&gt;
&lt;div dojoAttachPoint = &quot;datacenterId&quot;
	dojoType=&quot;datacenters:DataCentersWidget&quot;  
	inputTopic=&quot;no.show.datacenter&quot; 
	style=&quot;display:none&quot;&gt;
&lt;/div&gt;</pre>
&nbsp;
<p>&nbsp;&nbsp;&nbsp; 在清单 4 中，我将每个应用程序组件都包装在 dijit 中。反过来，每个 dijit 都由子 dijit 组成。甚至可以将加载整个应用程序视为超 dijit：</p>
<p>
                <code>&lt;div id = &quot;layout&quot; dojoType=&quot;layout:EEFLayoutWidget&quot; class=&quot;layoutDef&quot;&gt;&lt;/div&gt;
</code>
            </p>
<p>问题是，您忽略了延迟加载内容（或太过复杂而不能考虑这个选项），特别在构建中包括所有小部件的情况下。我发现，最好为 UI 组件（Data Grid、专用组合框、特殊文本区）创建 dijit，然后加载使用 dijit 的普通 HTML 模板。</p>
<p>通过遵循一些指导原则和实践，可以很容易地减少下载应用程序的时间，而且仍然能够获得 Dojo 具有的一些性能优势。</p>
<p>&nbsp;</p>
<p><strong><a name="resources"><span class="atitle"><span style="font-size: medium;">参考资料</span>
 </span>
</a>
</strong>
</p>
<p><strong>学习</strong></p>
<ul>
<li>
               您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/websphere/techjournal/0802_col_barcia/0802_col_barcia.html" onmouseover="linkQueryAppend(this)" target="_blank">英文原文</a>
            <br />
<br />
</li>
<li>
                <a href="http://dojotoolkit.org/book/dojo-book-0-9/part-4-meta-dojo/package-system-and-custom-builds">The Book of Dojo: The Package System and Custom Builds</a>
            <br />
<br />
</li>
<li>
                <a href="http://dojotoolkit.org/book/dojo-book-0-9/part-5-dojox/dojox-layout">The Book of Dojo: DojoX Layout</a>
            <br />
<br />
</li>
<li>
                <a href="http://www.projectzero.org/">Project Zero</a>
            <br />
<br />
</li>
<li>
                <a href="http://www.ibm.com/developerworks/cn/web">IBM developerWorks Web development 专区</a>
            <br />
<br />
</li>
<li>
                <a href="http://www.ibm.com/developerworks/cn/websphere/zones/was/bigpicture.html">IBM developerWorks WebSphere Application Server 专区</a>
            <br />
<br />
</li>
</ul>
<p><br />
<strong>获得产品和技术</strong></p>
<ul>
<li>
                <a href="http://dojotoolkit.org/">Dojo Toolkit</a>
            <br />
<br />
</li>
<li>
                <a href="http://www-306.ibm.com/software/webservers/appserv/was/featurepacks/web20/">IBM WebSphere Application Server Feature Pack for Web 2.0</a>
            <br />
<br />
</li>
</ul>
<p><br />
<strong>讨论</strong></p>
<ul>
<li>
                <a href="http://www.ibm.com/developerworks/blogs/page/barcia" onmouseover="linkQueryAppend(this)">Blog：Web 2.0 和中间件</a>
            </li>
</ul>
          <br/>
          <span style="color:red;">
            <a href="http://robbin.javaeye.com/topic/207354#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/106' target='_blank'><span style="color:blue;font-weight:bold;">JavaEye问答大赛开始了！ 从6月23日 至 7月6日，奖品丰厚 ！</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/92' target='_blank'><span style="color:red;font-weight:bold;">快来参加7月17日在成都举行的SOA中国技术论坛</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 24 Jun 2008 10:38:38 +0800</pubDate>
        <link>http://www.javaeye.com/topic/207354</link>
        <guid>http://www.javaeye.com/topic/207354</guid>
      </item>
      <item>
        <title>慎用typo(theme_support)的换肤机制</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://woody-420420.javaeye.com">woody_420420</a>&nbsp;
          链接：<a href="http://www.javaeye.com/topic/215970" style="color:red;">http://www.javaeye.com/topic/215970</a>&nbsp;
          发表时间: 2008年07月17日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <ul>
<li>
<h1>前言</h1>
</li>
</ul>
<p>&nbsp; 本文提到的<a href="https://rubyforge.org/projects/typo/" target="_blank">typo</a>版本是目前最新的5.0.3.98.1，<a href="https://rubyforge.org/projects/theme-generator/" target="_blank">theme_support</a>版本是1.3.0。在typo中，我们看到了很好很花哨的换肤机制，而theme_support则是从typo中抽取出来的一个plugin，以供其他程序进行换肤操作。<br />&nbsp; 先简单介绍下typo换肤的使用。<a href="http://typogarden.org/" target="_blank">typogarden</a>提供了typo十分丰富的皮肤，我们只需要下载喜欢的皮肤，解压，放在typo程序根目录的theme目录下即可，大致的结构图如下所示：<br /><img src="http://woody-420420.javaeye.com/upload/picture/pic/18020/49c22e18-d99f-3853-a474-235e6f62169a.png" height="467" alt="" width="255" /><br />&nbsp; 然后，就可以在admin界面选择自己的皮肤。的确十分方便。但是，使用这种机制，会存在一个严重的性能问题，下面将详细分析问题的原理及其我目前所知的解决方案。</p>
<ul>
<li>
<h1>Typo的换肤原理</h1>
</li>
</ul>
<p>&nbsp; 通常，我们会将程序的图片，css等与皮肤相关的文件放在网站的public目录下，在view中直接引用即可。但是从上图我们可以看到，typo将新皮肤的所有相关文件都存放在theme目录下的各个子目录下。那么typo是如何引用这些文件的呢？下面，我们随便打开某一个皮肤下面的layout文件，例如theme/typographic/layouts下面的default.html.erb文件，可以看到如下代码：</p>
<pre name="code" class="html">&lt;%= stylesheet_link_tag '/stylesheets/theme/style.css', :media =&gt; 'all' %&gt;</pre>
<p>&nbsp; 你仔细搜查一下程序，绝对发现不了/stylesheets/theme目录，乱引用？当然不是，我们可以在routes.rb中发现如下的route信息：</p>
<pre name="code" class="ruby">    get.with_options(:controller =&gt; 'theme', :filename =&gt; /.*/, :conditions =&gt; {:method =&gt; :get}) do |theme|
      theme.connect 'stylesheets/theme/:filename', :action =&gt; 'stylesheets'
      theme.connect 'javascripts/theme/:filename', :action =&gt; 'javascript'
      theme.connect 'images/theme/:filename',      :action =&gt; 'images'
    end</pre>
&nbsp;
<p>&nbsp; 很经典的route配置，原来在typo中，所有对css，javascript，image的引用，不是通过直接引用public目录下的文件，而是通过一个传统的controller：ThemeController来完成的。至于ThemeContorller具体代码，这里不详细谈，因为不是本文的重点，无非就是根据当前选择的皮肤（在admin界面选择的），到相应的皮肤目录（比如：theme/typographic）下，将各个文件找到，然后通过send_file的方式发送到客户端浏览器。那执行完一次action后，controller到底应该执行怎么样的render操作呢？（通过上图，我们看到不同的view文件，在各自的theme子目录下）<br />&nbsp; 在ApplicationController中，有如下代码：</p>
<pre name="code" class="ruby">class ApplicationController &lt; ActionController::Base
......
  def setup_themer
    # Ick!
    self.view_paths = ::ActionController::Base.view_paths.dup.unshift("#{RAILS_ROOT}/themes/#{this_blog.theme}/views")
  end
end</pre>
<p>&nbsp;&nbsp; 大致讲下，setup_themer方法的作用是根据目前皮肤配置（this_blog.theme），将controller的view_paths设置为某一个皮肤的目录（比如：theme/typographic/views），这样，在执行render操作的时候，将使用皮肤目录下的view,layout等等（还记得前面提到的layout中引用css的方法么？重要！）。并且，将setup_themer方法设置为需要换肤的contorller的before_filter。于是，当我们执行程序的时候，就可以达到动态换肤的目的。<br />&nbsp; 大致原理如是。。。</p>
<ul>
<li>
<h1>性能问题的由来</h1>
</li>
</ul>
<p>&nbsp; 前面我讲了，这种机制会存在一个严重的性能问题，是怎么来的呢？在传统方式下，我们将css，images，js都放在public目录下，view进行引用的时候，在web服务器层面，就完成了文件的引用，发送操作。但是在typo这种机制下，每引用一个css，图片，js，web服务器会将请求route到rails，通过rails的ThemeController来处理请求，返回文件。这都还算小事，在一次request，response周期，这样一个额外操作往往占用不了多大的百分比。但是，我们知道ThemeController是rails中一个普通的Controller，它也继承自ApplicationController。通常，我们会将很多程序通用逻辑放在ApplicationController中来做，比如：验证用户合法性，处理本地化等等，而这些操作，大部分都是访问数据库。也就是说，我们通过ThemeController，仅仅想得到一个css或者图片文件，但是ApplicationController仍然会初始化，执行相应的操作（重复，无用的操作）。这就是性能问题的根源。口说无凭，下面的数据揭示了一切：<br /><img src="http://woody-420420.javaeye.com/upload/picture/pic/18016/72a6fba1-dd98-3036-8ace-4e6bb1b22866.png" height="362" alt="" width="281" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <img src="http://woody-420420.javaeye.com/upload/picture/pic/18014/72522c09-5551-3f59-bd0a-f82663c2be1a.png" height="369" alt="" width="279" /><br />&nbsp; 上面两个性能测试是我随机访问一次typo首页得到的，我们可以看到，对css，image，js的请求，耗费了数十毫秒的操作。为什么请求一个css会耗费如此多时间呢？从下面的图中，我们可以看到原因：<br /><img src="http://woody-420420.javaeye.com/upload/picture/pic/18012/df4d2e29-8e08-3940-9dba-15a1d43054f0.png" height="562" alt="" width="587" /><br />&nbsp; Oh~My god！我出来打个酱油而已，咋搞出个db访问占用了这么长的周期？原因就是我前面提到的，访问ThemeController的时候，ApplicationContorller偷偷摸摸的作祟着（执行了一些业务逻辑的操作，用户验证等）。具体执行的多余db操作如下图所示：<br /><img src="http://woody-420420.javaeye.com/upload/picture/pic/18010/c0ffc657-4b56-359e-8338-460d4541dfa3.png" height="120" alt="" width="800" /><br />&nbsp; 什么show tables，select blogs，select triggers之类操作啊~我请求一个css，何必呢？<br />&nbsp; 性能问题的原因分析完毕！不要忘了，我举例的这些简单的皮肤中，只是简单的十几个css，js，images等。如果你真的使用这种机制在自己的程序中，我想，一个稍微复杂点的皮肤不止十个图片文件。加入我们要在皮肤中引用数十个此类文件，那么性能问题将是十分严重的。</p>
<ul>
<li>
<h1>解决方案</h1>
</li>
</ul>
<p>&nbsp; 目前，我找到三个解决方案处理这个性能问题。</p>
<p>&nbsp; 1. 在ApplicationController中，执行某些业务逻辑的时候，判断一下controller，如果是ThemeController，则跳过。这样做的好处是不用变动typo中换肤方法的使用，仍然将皮肤放在theme目录下即可。但是，这样做似乎&ldquo;侵入性&rdquo;太强，仅仅为了一个皮肤，修改业务逻辑