﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-学习笔记</title><link>http://www.blogjava.net/echo/</link><description>Simple is beautiful.</description><language>zh-cn</language><lastBuildDate>Sat, 18 Apr 2026 11:12:34 GMT</lastBuildDate><pubDate>Sat, 18 Apr 2026 11:12:34 GMT</pubDate><ttl>60</ttl><item><title>软件架构师成长</title><link>http://www.blogjava.net/echo/archive/2008/03/03/183556.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Mon, 03 Mar 2008 12:20:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2008/03/03/183556.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/183556.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2008/03/03/183556.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/183556.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/183556.html</trackback:ping><description><![CDATA[&nbsp;<span style="font-size: medium"> 对于任何一个软件开发人员来说，架构师都是一个令人向往的角色。就连世界首富比尔盖茨在2000年卸任公司CEO的同时，也担任了微软公司的荣誉角色&#8220;首席软件架构师&#8221;，可见&#8220;架构师&#8221;这一称谓的吸引力。架构师是公司的&#8220;金领&#8221;，有着非常高的收入，很少需要考虑生存的问题，从而有更多的精力思考关键技术问题，形成&#8220;强者愈强&#8221;的良性循环。部分优秀的开发人员在工作了一定时间后，就要开始考虑自己的未来到底向哪个方向发展。如果开发人员的沟通能力强过技术能力，在补充一定的项目管理知识后，可以向技术管理的方向转型。如果其对技术一直很感兴趣，而沟通能力也不弱，则可以试着进一步加强技术修养，以期向架构师的方向发展，最终&#8220;修成正果&#8221;。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;那么，到底什么是架构师呢？所谓的架构师，应该是一个技术企业的最高技术决策者。他主要负责公司软件产品或软件项目的技术路线与技术框架的制订。好的架构师都是善良的独裁者，具有很强的技术、良好的写作能力、良好的口头表达能力，能够在各个层次进行沟通。从开发人员到架构师的成长应该是阶梯式的，一般来讲开发人员在刚刚开始工作时只能开发简单的独立软件模块，慢慢的随着经验的增长，他开始接触一些相互之间有信息传递的模块，而后来，他会发现自己接到的开发任务已经不是一个独立的单体，这些任务由一些专门的软件部分组成，可能包含数据库，工作流引擎，消息服务等等各种功能模块，可能分布在不同的服务器上，所有的部分协同起来，完成软件功能。而这时候，体系结构的好坏将直接决定了系统的性能和可扩展性，而就在这时候，这名优秀的开发人员也开始思考架构师应该思考的问题了，或者说，他向成长为架构师的道路迈出了一大步。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;什么是架构师最具价值的技能呢？就是要了解不同的知识，做一个&#8220;杂家&#8221;或者说&#8220;博学家&#8221;。当然，如果你的数据库技术非常棒，或者你在工作流引擎方面具有不可超越的专家知识，那也是很不错的。好的架构师有好多都是从专家成长过来的。但是，这不是架构师应该做的事情，架构师应该做的是了解所有的东西，既了解技术的宏观面，又了解技术的细节。真正的架构师不仅仅要了解软件，也要了解硬件，在关键的部位使用合适的硬件来取代软件，可以成倍甚至成百倍的提高整个系统的效率。下面我将会以互联网行业对的架构师的要求为例，向大家讲解作为架构师应该具备的知识。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;互联网行业是当前最激动人心的行业之一，很多的创新都来自于这个行业，而每一个大型的网站如Google，Yahoo，Myspace等都需要解决一个非常复杂的问题，就是网站的分布式向外扩展(Scale&nbsp;Out)的问题。解决这个问题，需要最优秀的架构师对业务进行剖析，利用软硬件将网站进行重构，甚至根据业务研发相应的分布式技术，解决网站复杂的分布式计算的问题。如果你想在这个行业中成为一名架构师的话，需要至少掌握网络知识，硬件，软件，网站优化等方方面面的知识：<br />
<br />
1．&nbsp;网络知识。<br />
当前的软件已经绝对不是那种仅仅跑在一台单机上的孤立应用了。不仅仅是在互联网行业，任何一个行业的软件，都要求其具有网络功能。因此，网络知识是架构师必备的知识。我们所说的网络知识，不仅仅包括TCP/IP，http等互联网行业常用的软件协议，也包括网络规划，甚至更具体的说，根据网站应用所处的地理环境进行网络规划。比如人们常说：&#8220;这世界上最远的距离不是生与死的距离，而是电信到网通的距离&#8221;（笑）如果应用是建立在中国的，就要考虑电信用户和网通用户访问网站的速度应该都比较快才可以。这时候的解决方案可能有多种，比如采用CDN（Content&nbsp;Delivery&nbsp;Network内容分发网络）使得网站的内容发布到离用户最近的服务器，又可以采用把服务器放在一些所谓的双线机房中，甚至将几种方案结合起来使用。这些都统统归到网络知识中。做为公司的架构师，要对这些知识都有所了解，才有助于在遇到问题时找到最佳答案。<br />
<br />
2．&nbsp;硬件知识。<br />
了解硬件的极限，是架构师的基本功。我见过一些人，他们的眼中软件硬件都是没有极限的，需要资源就申请，系统性能下降了就买更高级的设备。然而，硬件的性能有很大一部分取决于I/O设备。而这些I/O设备依靠的都是机械物理运动，这种运动是有极限的。因此当资源访问量增大到一定的程度时，这种物理运动将成为瓶颈。比如说，在开发网站的过程中，记录访客的状态是一件很重要的事情，一般来说可以使用HttpSession来记录。而HttpSession的存储问题将是一个很大的挑战，尤其是多机共享Session时，将HttpSession存成文件并通过多机共享或网络备份的方式来解决分布式的问题是常用的方案，然而，架构师必须考虑到这种方案是有I/O极限限制的，很难扩展到超过一定规模的大型网络。同时，架构师应该了解目前最近的硬件发展是否对软件系统会造成一定的影响，比如在多核的条件下是否对软件编程有新的要求，是否会对运行在虚拟机和非虚拟机上的程序有影响等等。<br />
<br />
3．&nbsp;软件知识。<br />
软件知识所包含的范围就更加广泛了。对于互联网行业来讲，架构师要了解操作系统，数据库，应用服务器等各方面的知识。比如说，如果网站使用的操作系统是Linux，就要了解这个Linux版本的性能与局限性，比如说最多可以存放的单个文件为多大。有的数据库的数据是以单个文件来存放的，虽然我们很少见到数据库中的数据多到不能再放入一条记录的情况，但是作为架构师，请时刻注意，这种可能性是有的。而且如果你有幸在一家高速成长的互联网企业中，而你所负责的应用又没有经过优化的话，可能你会很快见到这种现象。这种现象的发生可能是由于操作系统不支持大文件的原因，也可能是数据库不支持大文件。不论如何，架构师应该在这种现象发生之前就把一切都准备好。对数据库中表的拆分是架构师应该遇到的另外一个困难。一般来说增加应用服务器比较简单而增加数据库服务器则是比较复杂的问题，如果一个站点由多个数据库支持，架构师需要考虑如何在保证数据一致的情况下，让多个数据库分担压力。有些解决方案是将数据库的读写分开，使得大多数的查询sql不经过核心数据库，而只是访问数据库的副本，但事实上，这种方式也只能维护规模不大的网站。对于大型的网站来说，把业务分散到不同的数据库中，只共享必要的数据，才是合理的提高网站扩展性的解决方案。<br />
<br />
4．&nbsp;其他知识。<br />
作为系统架构师，可能还需要对分布式系统，负载均衡，网络安全，数据监控等等各方面都有所了解。不仅仅是了解理论知识，也要对相关的产品和业界进展有一定的认识。比如说做负载均衡最好的产品是那种。目前最常用的备份策略是什么，有什么缺点。如何使用缓存，如何做好日志分析等等。<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;刚刚谈到的是架构师需要掌握的知识，然而，冰冻三尺非一日之寒。这个过程需要我们慢慢的积累。如果你已经进入到公司进行软件开发，请时刻关注你所开发软件的性能与可扩展性，而不仅仅局限在功能上，时刻想着任何一个简单的问题：我开发的模块如果放在多人并发的环境下会怎样，慢慢的就会有所心得。如果你还是一个在校学生，不要想着自己离架构师这个职位还很遥远。要知道，成为架构师的修炼之路是很长的，甚至可以说是终身的，因此早点进入学习状态，不断修炼自己。在学校期间学好离散数学，数据结构，操作系统，编译原理，体系结构，数据库原理等关键课程，并积极寻找机会到外面实习，增长自己的工作经验。如果有机会去到一些技术主导的公司中工作，就一定不要放弃这种机会，慢慢就会成长起来。最重要的，你会养成关注技术，勤于思考的好习惯。当有一天你发现自己对任何技术难题都可以一眼看到其本质，并能够将其分解为一个个可轻松解决的模块，你会由衷的感觉到知识给你带来的快乐，或许那一天，你已经是一个架构师了。</span>
<img src ="http://www.blogjava.net/echo/aggbug/183556.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2008-03-03 20:20 <a href="http://www.blogjava.net/echo/archive/2008/03/03/183556.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Seam expcetion (继续补充...)</title><link>http://www.blogjava.net/echo/archive/2008/02/06/179398.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Wed, 06 Feb 2008 06:35:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2008/02/06/179398.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/179398.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2008/02/06/179398.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/179398.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/179398.html</trackback:ping><description><![CDATA[<span style="color: red"><strong>1、在components.xml中没有声明&lt;transaction&gt;</strong></span><br />
e.g.<br />
<br />
&lt;transaction:entity-transaction entity-manager="#{entityManager}"&gt;<br />
&nbsp;&nbsp; &lt;/transaction:entity-transaction&gt;<br />
------------------------------------------------------------------------------<br />
2008-2-6 14:14:42 org.jboss.seam.jsf.SeamPhaseListener beforePhase<br />
严重: uncaught exception<br />
java.lang.RuntimeException: exception invoking: getTransaction<br />
&nbsp;at org.jboss.seam.util.Reflections.invokeAndWrap(Reflections.java:135)<br />
&nbsp;at org.jboss.seam.Component.callComponentMethod(Component.java:2074)<br />
&nbsp;at org.jboss.seam.Component.unwrap(Component.java:2100)<br />
&nbsp;at org.jboss.seam.Component.getInstance(Component.java:1879)<br />
&nbsp;at org.jboss.seam.Component.getInstance(Component.java:1844)<br />
&nbsp;at org.jboss.seam.Component.getInstance(Component.java:1821)<br />
&nbsp;at org.jboss.seam.Component.getInstance(Component.java:1816)<br />
&nbsp;at org.jboss.seam.transaction.Transaction.instance(Transaction.java:36)<br />
&nbsp;at org.jboss.seam.jsf.SeamPhaseListener.handleTransactionsBeforePhase(SeamPhaseListener.java:301)<br />
&nbsp;at org.jboss.seam.jsf.SeamPhaseListener.beforeServletPhase(SeamPhaseListener.java:142)<br />
&nbsp;at org.jboss.seam.jsf.SeamPhaseListener.beforePhase(SeamPhaseListener.java:116)<br />
&nbsp;at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:222)<br />
&nbsp;at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:117)<br />
&nbsp;at javax.faces.webapp.FacesServlet.service(FacesServlet.java:244)<br />
&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)<br />
&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)<br />
&nbsp;at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:85)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)<br />
&nbsp;at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)<br />
&nbsp;at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:44)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)<br />
&nbsp;at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:141)<br />
&nbsp;at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:281)<br />
&nbsp;at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:60)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)<br />
&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)<br />
&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)<br />
&nbsp;at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)<br />
&nbsp;at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)<br />
&nbsp;at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)<br />
&nbsp;at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)<br />
&nbsp;at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)<br />
&nbsp;at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:263)<br />
&nbsp;at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)<br />
&nbsp;at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:584)<br />
&nbsp;at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)<br />
&nbsp;at java.lang.Thread.run(Thread.java:595)<br />
Caused by: javax.naming.NamingException: Cannot create resource instance<br />
&nbsp;at org.apache.naming.factory.TransactionFactory.getObjectInstance(TransactionFactory.java:113)<br />
&nbsp;at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:304)<br />
&nbsp;at org.apache.naming.NamingContext.lookup(NamingContext.java:793)<br />
&nbsp;at org.apache.naming.NamingContext.lookup(NamingContext.java:140)<br />
&nbsp;at org.apache.naming.NamingContext.lookup(NamingContext.java:781)<br />
&nbsp;at org.apache.naming.NamingContext.lookup(NamingContext.java:153)<br />
&nbsp;at org.apache.naming.SelectorContext.lookup(SelectorContext.java:137)<br />
&nbsp;at javax.naming.InitialContext.lookup(InitialContext.java:351)<br />
&nbsp;at org.jboss.seam.transaction.Transaction.getUserTransaction(Transaction.java:79)<br />
&nbsp;at org.jboss.seam.transaction.Transaction.createUTTransaction(Transaction.java:71)<br />
&nbsp;at org.jboss.seam.transaction.Transaction.getTransaction(Transaction.java:44)<br />
&nbsp;at sun.reflect.GeneratedMethodAccessor36.invoke(Unknown Source)<br />
&nbsp;at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)<br />
&nbsp;at java.lang.reflect.Method.invoke(Method.java:585)<br />
&nbsp;at org.jboss.seam.util.Reflections.invoke(Reflections.java:21)<br />
&nbsp;at org.jboss.seam.util.Reflections.invokeAndWrap(Reflections.java:125)<br />
&nbsp;... 39 more<br />
2008-2-6 14:14:42 org.jboss.seam.jsf.SeamPhaseListener beforePhase<br />
严重: swallowing exception<br />
java.lang.RuntimeException: exception invoking: getTransaction<br />
&nbsp;at org.jboss.seam.util.Reflections.invokeAndWrap(Reflections.java:135)<br />
&nbsp;at org.jboss.seam.Component.callComponentMethod(Component.java:2074)<br />
&nbsp;at org.jboss.seam.Component.unwrap(Component.java:2100)<br />
&nbsp;at org.jboss.seam.Component.getInstance(Component.java:1879)<br />
&nbsp;at org.jboss.seam.Component.getInstance(Component.java:1844)<br />
&nbsp;at org.jboss.seam.Component.getInstance(Component.java:1821)<br />
&nbsp;at org.jboss.seam.Component.getInstance(Component.java:1816)<br />
&nbsp;at org.jboss.seam.transaction.Transaction.instance(Transaction.java:36)<br />
&nbsp;at org.jboss.seam.jsf.SeamPhaseListener.handleTransactionsBeforePhase(SeamPhaseListener.java:301)<br />
&nbsp;at org.jboss.seam.jsf.SeamPhaseListener.beforeServletPhase(SeamPhaseListener.java:142)<br />
&nbsp;at org.jboss.seam.jsf.SeamPhaseListener.beforePhase(SeamPhaseListener.java:116)<br />
&nbsp;at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:222)<br />
&nbsp;at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:117)<br />
&nbsp;at javax.faces.webapp.FacesServlet.service(FacesServlet.java:244)<br />
&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)<br />
&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)<br />
&nbsp;at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:85)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)<br />
&nbsp;at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)<br />
&nbsp;at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:44)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)<br />
&nbsp;at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:141)<br />
&nbsp;at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:281)<br />
&nbsp;at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:60)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)<br />
&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)<br />
&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)<br />
&nbsp;at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)<br />
&nbsp;at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)<br />
&nbsp;at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)<br />
&nbsp;at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)<br />
&nbsp;at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)<br />
&nbsp;at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:263)<br />
&nbsp;at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)<br />
&nbsp;at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:584)<br />
&nbsp;at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)<br />
&nbsp;at java.lang.Thread.run(Thread.java:595)<br />
Caused by: javax.naming.NamingException: Cannot create resource instance<br />
&nbsp;at org.apache.naming.factory.TransactionFactory.getObjectInstance(TransactionFactory.java:113)<br />
&nbsp;at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:304)<br />
&nbsp;at org.apache.naming.NamingContext.lookup(NamingContext.java:793)<br />
&nbsp;at org.apache.naming.NamingContext.lookup(NamingContext.java:140)<br />
&nbsp;at org.apache.naming.NamingContext.lookup(NamingContext.java:781)<br />
&nbsp;at org.apache.naming.NamingContext.lookup(NamingContext.java:153)<br />
&nbsp;at org.apache.naming.SelectorContext.lookup(SelectorContext.java:137)<br />
&nbsp;at javax.naming.InitialContext.lookup(InitialContext.java:351)<br />
&nbsp;at org.jboss.seam.transaction.Transaction.getUserTransaction(Transaction.java:79)<br />
&nbsp;at org.jboss.seam.transaction.Transaction.createUTTransaction(Transaction.java:71)<br />
&nbsp;at org.jboss.seam.transaction.Transaction.getTransaction(Transaction.java:44)<br />
&nbsp;at sun.reflect.GeneratedMethodAccessor36.invoke(Unknown Source)<br />
&nbsp;at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)<br />
&nbsp;at java.lang.reflect.Method.invoke(Method.java:585)<br />
&nbsp;at org.jboss.seam.util.Reflections.invoke(Reflections.java:21)<br />
&nbsp;at org.jboss.seam.util.Reflections.invokeAndWrap(Reflections.java:125)<br />
&nbsp;... 39 more<br />
2008-2-6 14:14:42 org.jboss.seam.jsf.SeamPhaseListener afterPhase<br />
严重: uncaught exception<br />
java.lang.IllegalStateException: Could not commit transaction<br />
&nbsp;at org.jboss.seam.jsf.SeamPhaseListener.commitOrRollback(SeamPhaseListener.java:592)<br />
&nbsp;at org.jboss.seam.jsf.SeamPhaseListener.handleTransactionsAfterPhase(SeamPhaseListener.java:325)<br />
&nbsp;at org.jboss.seam.jsf.SeamPhaseListener.afterServletPhase(SeamPhaseListener.java:226)<br />
&nbsp;at org.jboss.seam.jsf.SeamPhaseListener.afterPhase(SeamPhaseListener.java:184)<br />
&nbsp;at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:280)<br />
&nbsp;at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:117)<br />
&nbsp;at javax.faces.webapp.FacesServlet.service(FacesServlet.java:244)<br />
&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)<br />
&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)<br />
&nbsp;at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:85)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)<br />
&nbsp;at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)<br />
&nbsp;at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:44)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)<br />
&nbsp;at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:141)<br />
&nbsp;at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:281)<br />
&nbsp;at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:60)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)<br />
&nbsp;at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)<br />
&nbsp;at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)<br />
&nbsp;at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)<br />
&nbsp;at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)<br />
&nbsp;at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)<br />
&nbsp;at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)<br />
&nbsp;at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)<br />
&nbsp;at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)<br />
&nbsp;at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:263)<br />
&nbsp;at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)<br />
&nbsp;at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:584)<br />
&nbsp;at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)<br />
&nbsp;at java.lang.Thread.run(Thread.java:595)<br />
Caused by: java.lang.RuntimeException: exception invoking: getTransaction<br />
&nbsp;at org.jboss.seam.util.Reflections.invokeAndWrap(Reflections.java:135)<br />
&nbsp;at org.jboss.seam.Component.callComponentMethod(Component.java:2074)<br />
&nbsp;at org.jboss.seam.Component.unwrap(Component.java:2100)<br />
&nbsp;at org.jboss.seam.Component.getInstance(Component.java:1879)<br />
&nbsp;at org.jboss.seam.Component.getInstance(Component.java:1844)<br />
&nbsp;at org.jboss.seam.Component.getInstance(Component.java:1821)<br />
&nbsp;at org.jboss.seam.Component.getInstance(Component.java:1816)<br />
&nbsp;at org.jboss.seam.transaction.Transaction.instance(Transaction.java:36)<br />
&nbsp;at org.jboss.seam.jsf.SeamPhaseListener.commitOrRollback(SeamPhaseListener.java:579)<br />
&nbsp;... 32 more<br />
Caused by: javax.naming.NamingException: Cannot create resource instance<br />
&nbsp;at org.apache.naming.factory.TransactionFactory.getObjectInstance(TransactionFactory.java:113)<br />
&nbsp;at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:304)<br />
&nbsp;at org.apache.naming.NamingContext.lookup(NamingContext.java:793)<br />
&nbsp;at org.apache.naming.NamingContext.lookup(NamingContext.java:140)<br />
&nbsp;at org.apache.naming.NamingContext.lookup(NamingContext.java:781)<br />
&nbsp;at org.apache.naming.NamingContext.lookup(NamingContext.java:153)<br />
&nbsp;at org.apache.naming.SelectorContext.lookup(SelectorContext.java:137)<br />
&nbsp;at javax.naming.InitialContext.lookup(InitialContext.java:351)<br />
&nbsp;at org.jboss.seam.transaction.Transaction.getUserTransaction(Transaction.java:79)<br />
&nbsp;at org.jboss.seam.transaction.Transaction.createUTTransaction(Transaction.java:71)<br />
&nbsp;at org.jboss.seam.transaction.Transaction.getTransaction(Transaction.java:44)<br />
&nbsp;at sun.reflect.GeneratedMethodAccessor36.invoke(Unknown Source)<br />
&nbsp;at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)<br />
&nbsp;at java.lang.reflect.Method.invoke(Method.java:585)<br />
&nbsp;at org.jboss.seam.util.Reflections.invoke(Reflections.java:21)<br />
&nbsp;at org.jboss.seam.util.Reflections.invokeAndWrap(Reflections.java:125)<br />
&nbsp;... 40 more
<img src ="http://www.blogjava.net/echo/aggbug/179398.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2008-02-06 14:35 <a href="http://www.blogjava.net/echo/archive/2008/02/06/179398.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用热门选择：元标记(Meta tags)和网页搜索 [Z]</title><link>http://www.blogjava.net/echo/archive/2008/01/22/176879.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Mon, 21 Jan 2008 16:37:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2008/01/22/176879.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/176879.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2008/01/22/176879.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/176879.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/176879.html</trackback:ping><description><![CDATA[<h3><a name="8534751565401106731">使用热门选择：元标记(Meta tags)和网页搜索</a></h3>
<p class="byline-timestamp"><span id="time8534751565401106731">2008年1月14日 下午 07:08:00</span></p>
<script language="javascript">
uT("time8534751565401106731");
</script>
<div style="clear: both"></div>
<br />
<br />
原文：<a href="http://googlewebmastercentral.blogspot.com/2007/12/answering-more-popular-picks-meta-tags.html" target="_blank">Answering more popular picks: meta tags and web search</a><br />
<br />
如果你能写好和维持准确的元标记（例如，描述性标题和为搜索机器人提供的信息），谷歌就可以更准确地爬行、索引并在搜索结果中显示你的网站。元标记为各种各样的客户端（例如浏览器和搜索引擎）提供信息。请记住，每一个客户端可能只解析对该客户端有用的元标记，而忽略了其他元标记（虽然它们有其他用处）。<br />
<br />
下面是谷歌如何解析以下 HTML 页的元标记：<br />
<p>&nbsp;</p>
<table width="100%" valign="top">
    <tbody>
        <tr>
            <td width="50%"><span style="font-family: courier new">&lt;!DOCTYPE &#8230;&gt;&lt;head&gt;</span></td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td><span style="font-family: courier new">&lt;title&gt;传统瑞士奶酪火锅食谱&lt;title&gt;</span></td>
            <td>谷歌使用此标记，网站管理员应非常注意它的准确性</td>
        </tr>
        <tr>
            <td><span style="font-family: courier new">&lt;meta name="description" content="奶酪火锅是 &#8230;"&gt;</span></td>
            <td>谷歌使用此标记，我们的搜索结果会显示它</td>
        </tr>
        <tr>
            <td><span style="font-family: courier new">&lt;meta name="revisit-after" content="14 days"&gt;</span></td>
            <td>谷歌不使用此标记，其他主要搜索引擎也不使用</td>
        </tr>
        <tr>
            <td><span style="font-family: courier new">&lt;META name="verify-v1" content="e8JG&#8230;Nw=" /&gt;</span></td>
            <td>可选，谷歌网络管理员工具用到此标记</td>
        </tr>
        <tr>
            <td><span style="font-family: courier new">&lt;meta name="GoogleBot" content="noOdp"&gt;</span></td>
            <td>可选</td>
        </tr>
        <tr>
            <td><span style="font-family: courier new">&lt;meta &#8230;&gt;</span></td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td><span style="font-family: courier new">&lt;meta &#8230;&gt;</span></td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td><span style="font-family: courier new">&lt;/head&gt;</span></td>
            <td><br />
            </td>
        </tr>
    </tbody>
</table>
<p><strong>&lt;meta name="description" content="对本页的描述"&gt;</strong> <br />
<br />
<strong>&lt;meta name="description" content="对本页的描述"&gt;</strong>此标记提供了对当前页面一个简短描述。在很多情况下该描述会作为页面摘要（snippet）显示在谷歌的搜索结果中。详情请参阅我们的博客文章&#8220;<a href="http://www.googlechinawebmaster.com/2008/01/blog-post.html" target="_blank">使用更好的元描述来改善页面摘要</a>&#8221;以及帮助中心的文章&#8220;<a href="http://www.google.com/support/webmasters/bin/answer.py?answer=35264" target="_blank">如何更改网站的标题和描述</a>&#8221;。虽然描述元标记是可选的，并且不会影响到您的排名，一个好的描述可以产生一个更好的页面摘要，这反过来又可以帮助提高我们的搜索结果质量和你的网页的访问者数量。<br />
<br />
<strong>&lt;title&gt;页面标题&lt;/title&gt;</strong>从技术上讲，标题标记并不是一个元标记，它经常与"description"标记一起使用。此标记的内容（即标题）一般显示在搜索结果中（当然，当用户使用浏览器来浏览网页或察看书签时也能看到页面标题）。我们的博客文章"<a href="http://www.googlechinawebmaster.com/2007/08/blog-post_22.html" target="_blank">针对访问者，还是针对搜索引擎？</a>"尤其是"充分利用网页标题"中有关于标题标记的更多信息。<br />
<br />
<strong>&lt;meta name="robots" content="&#8230;, &#8230;"&gt;<br />
&lt;meta name="googlebot" content="&#8230;, &#8230;"&gt;</strong>这些元标记控制搜索引擎如何抓取和索引页。 "robots"元标记指定的规则适用于所有搜索引擎，"googlebot"元标记指定的规则只适用于谷歌。谷歌可以理解以下值（当指定多个值时，用逗号将它们分开） ：<br />
<br />
* noindex: 防止网页被索引（见"<a href="http://www.google.com/support/webmasters/bin/answer.py?answer=61050">使用元标记拦截或删除网页</a>")<br />
* nofollow: 不要通过当前页的链接来寻找并抓取新的网页（也见"<a href="http://www.google.com/support/webmasters/bin/answer.py?answer=61050" target="_blank">使用元标记拦截或删除网页</a>")<br />
* nosnippet: 在搜索结果中显示当前页时，不要显示页面摘要（见"<a href="http://www.google.com/support/webmasters/bin/answer.py?answer=35304" target="_blank">防止显示或删除页面摘要</a>")<br />
* noodp: 在为本页产生标题或页面摘要时，不要使用开放式目录项目（又名dmoz.org）中的文本（见"<a href="http://www.google.com/support/webmasters/bin/answer.py?answer=35264" target="_blank">如何更改网站的标题和描述？</a>")<br />
* noarchive: 在显示本网页于搜索结果中时，不要显示一个"网页快照"链接（见"<a href="http://www.google.com/support/webmasters/bin/answer.py?answer=35306" target="_blank">防止显示或删除缓存的网页</a>")<br />
* unavailable_after:[日期]:在指定的日期和时间后从搜索结果中删除这个网页（见"<a href="http://googleblog.blogspot.com/2007/07/robots-exclusion-protocol-now-with-even.html" target="_blank">机器人排除协议：现在更灵活</a>") <br />
<br />
当你完全省略此标记或当你指定content= "all"时，默认规则是"index, follow"。"使用 robots 元标记"中有关于"robots"元标记的更多信息。作为一个说明，你现在也可以在你的页面首部通过"X-Robots-标签"HTTP 头指令来指定这一信息。这特别有用，尤其是当你想微调抓取和索引诸如 PDF、图片或其他类型的非 HTML 文件时。<br />
<br />
<strong>&lt;meta name="google" value="notranslate"&gt;</strong>当我们认识到一个页面的内容并不是用用户可能想读的语言所写时，我们往往在搜索结果中提供一个链接以自动翻译你的网页。一般来说，这让你有机会提供独特和令人折服的内容给一个更广大的用户群。不过，在特定情况下，你可能不想你的网页被翻译。用这个元标记，你可以表明你不想让谷歌提供一个翻译此页的链接。这个元标记一般不影响该页为任何特定语言的排名。更多的信息请参阅"<a href="http://www.google.com/help/faq_translation.html#donttrans" target="_blank">谷歌翻译常见问题解答</a>"。<br />
<br />
<strong>&lt;meta name="verify-v1" content="&#8230;"&gt;</strong>这是一个<a href="http://www.google.com/webmasters/tools/" target="_blank">谷歌网站管理员工具</a>的特定元标记，它是被用在你网站的高层页面，以在网站管理员中核实一个网站的所有者（另一种核实方法是上传一个HTML文件）。你为这个标记所设置的 "content="的值是由你的网站管理员工具帐户提供的。请注意，这一元标记的 content 值（包括大小写）必须和你的帐户提供给你的值完全一样，这和你是否从 XHTML 改变标记为 HTML 无关，也和你标签的格式是否与你的网页相符无关。详情请见" <a href="http://www.google.com/support/webmasters/bin/answer.py?answer=35659" target="_blank">如何通过向网站主页中添加元标记来验证网站</a>？"<br />
<br />
<strong>&lt;meta http-equiv="Content-Type" content="&#8230;; charset=&#8230;"&gt;</strong>这个元标记定义该页的内容类型和字符集。使用这个元标记时，content 属性的值必须放在引号中;否则字符属性可能被错误理解。如果你决定 使用这个元标记，不用说，你应该确保你的内容实际上用的是指定的字符集。"<a href="http://code.google.com/webstats/2005-12/metadata.html" target="_blank">谷歌的网络作者统计</a>"里有一些关于这个元标记的使用的有趣数据。<br />
<br />
<strong>&lt;meta http-equiv="refresh" content="&#8230;;url=&#8230;"&gt;</strong>这个元标记在一定的时间后将用户指引到一个新的 URL，有时它被用来作为一种简单的重定向形式。不是所有浏览器都支持这种重定向。它也可能混淆用户。对显示在搜索引擎结果中的某一页面，如果你需要改变它的 URL，我们建议您使用服务器端的 301 重定向。此外，W3C 的"<a href="http://www.w3.org/TR/WCAG20-TECHS/#F41" target="_blank">网页内容易读性技巧和故障指南 2.0</a>"把它列在应该被废弃的标记中。<br />
<br />
<strong>(X)HTML 和大小写</strong><br />
谷歌既能阅读 HTML 式的元标记，也能阅读 XHTML 式的元标记（无论网页用的是哪种编码）。此外，元标记的大小写一般并不重要--我们把&lt;TITLE&gt; and &lt;title&gt;看作是同样的。但是，"verify-v1"元标记是一个例外，它是区分大小写的。<br />
<br />
<strong>revisit-after 网站地图的 lastmod 和 changefreq 标记</strong><br />
偶尔，网络管理员不必要地包含了"revisit-after"标记以加快一个搜索引擎的爬行速度，不幸的是，这个元标记大多数情况下是被忽略的。如果你想 让搜索引擎知道你更改页面的信息，你可以提交一个 <a href="http://www.google.com/support/webmasters/bin/topic.py?topic=8477" target="_blank">XML 格式的网站地图</a>。在该文件中，你可以说明你网站的最后修改日期(lastmod)和 URL 页面的改变频率(changefreq)。<br />
<br />
如果您想要更多的例子，或有对如上所述的元标记有任何疑问，请到我们的<a href="http://groups.google.com/group/Google_Webmaster_Help/" target="_blank">谷歌网站管理员讨论组</a>参与讨论。<br />
<br />
又及：你可以阅读网络管理员帮助讨论组里的关于<a href="http://groups.google.com/group/Google_Webmaster_Help-Indexing/browse_thread/thread/dd35b20e7835ea06/7bb06f2958e46b17" target="_blank">其他热门选择</a>的一个讨论。</p>
<img src ="http://www.blogjava.net/echo/aggbug/176879.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2008-01-22 00:37 <a href="http://www.blogjava.net/echo/archive/2008/01/22/176879.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何有效编写软件的75条建议</title><link>http://www.blogjava.net/echo/archive/2008/01/05/172910.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Sat, 05 Jan 2008 02:43:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2008/01/05/172910.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/172910.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2008/01/05/172910.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/172910.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/172910.html</trackback:ping><description><![CDATA[1. 你们的项目组使用源代码管理工具了么？<br />
应该用。VSS、CVS、PVCS、ClearCase、CCC/Harvest、FireFly都可以。我的选择是VSS。<br />
<br />
2. 你们的项目组使用缺陷管理系统了么？<br />
应该用。ClearQuest太复杂，我的推荐是BugZilla。 <br />
<br />
3. 你们的测试组还在用Word写测试用例么？ <br />
不要用Word写测试用例（Test Case）。应该用一个专门的系统，可以是Test Manager，也可以是自己开发一个ASP.NET的小网站。主要目的是Track和Browse。<br />
<br />
4. 你们的项目组有没有建立一个门户网站？<br />
要有一个门户网站，用来放Contact Info、Baselined Schedule、News等等。推荐Sharepoint Portal
Server 2003来实现，15分钟就搞定。买不起SPS 2003可以用WSS (Windows Sharepoint Service)。 <br />
<br />
5. 你们的项目组用了你能买到最好的工具么？<br />
应该用尽量好的工具来工作。比如，应该用VS.NET而不是Notepad来写C#。用Notepad写程序多半只是一种炫耀。但也要考虑到经费，所以说是&#8220;你能买到最好的&#8221;。 <br />
<br />
6. 你们的程序员工作在安静的环境里么？<br />
需要安静环境。这点极端重要，而且要保证每个人的空间大于一定面积。 <br />
<br />
7. 你们的员工每个人都有一部电话么？<br />
需要每人一部电话。而且电话最好是带留言功能的。当然，上这么一套带留言电话系统开销不小。不过至少每人一部电话要有，千万别搞得经常有人站起来喊：&#8220;某某某电话&#8221;。《人件》里面就强烈谴责这种做法。 <br />
<br />
8. 你们每个人都知道出了问题应该找谁么？<br />
应该知道。任何一个Feature至少都应该有一个Owner，当然，Owner可以继续Dispatch给其他人。<br />
<br />
9. 你遇到过有人说&#8220;我以为&#8230;&#8221;么？<br />
要消灭&#8220;我以为&#8221;。Never assume anything。 <br />
<br />
10. 你们的项目组中所有的人都坐在一起么？<br />
需要。我反对Virtual Team，也反对Dev在美国、Test在中国这种开发方式。能坐在一起就最好坐在一起，好处多得不得了。 <br />
<br />
11. 你们的进度表是否反映最新开发进展情况？ <br />
应该反映。但是，应该用Baseline的方法来管理进度表：维护一份稳定的Schedule，再维护一份最新更改。Baseline的方法也应该用于其它的Spec。Baseline是变更管理里面的一个重要手段。<br />
<br />
12. 你们的工作量是先由每个人自己估算的么？<br />
应该让每个人自己估算。要从下而上估算工作量，而不是从上往下分派。除非有其他原因，比如政治任务工期固定等。 <br />
<br />
13. 你们的开发人员从项目一开始就加班么？<br />
不要这样。不要一开始就搞疲劳战。从项目一开始就加班，只能说明项目进度不合理。当然，一些对日软件外包必须天天加班，那属于剥削的范畴。 <br />
<br />
14. 你们的项目计划中Buffer Time是加在每个小任务后面的么？<br />
不要。Buffer Time加在每个小任务后面，很容易轻易的就被消耗掉。Buffer Time要整段的加在一个Milestone或者checkpoint前面。 <br />
<br />
15. 值得再多花一些时间，从95%做到100%好值得，非常值得。<br />
尤其当项目后期人困马乏的时候，要坚持。这会给产品带来质的区别。 <br />
<br />
16. 登记新缺陷时，是否写清了重现步骤？<br />
要。这属于Dev和Test之间的沟通手段。面对面沟通需要，详细填写Repro Steps也需要。 <br />
<br />
17. 写新代码前会把已知缺陷解决么？<br />
要。每个人的缺陷不能超过10个或15个，否则必须先解决老的bug才能继续写新代码。 <br />
<br />
18. 你们对缺陷的轻重缓急有事先的约定么？<br />
必须有定义。Severity要分1、2、3，约定好：蓝屏和Data Lost算Sev 1，Function Error算Sev 2，界面上的算Sev 3。但这种约定可以根据产品质量现状适当进行调整。<br />
<br />
19. 你们对意见不一的缺陷有三国会议么？<br />
必须要有。要有一个明确的决策过程。这类似于CCB (Change Control Board)的概念。 <br />
<br />
20. 所有的缺陷都是由登记的人最后关闭的么？ <br />
Bug应该由Opener关闭。Dev不能私自关闭Bug。 <br />
<br />
21. 你们的程序员厌恶修改老的代码么？<br />
厌恶是正常的。解决方法是组织Code Review，单独留出时间来。XP也是一个方法。<br />
<br />
22. 你们项目组有Team Morale Activity么？<br />
每个月都要搞一次，吃饭、唱歌、Outing、打球、开卡丁车等等，一定要有。不要剩这些钱。 <br />
<br />
23. 你们项目组有自己的Logo么？<br />
要有自己的Logo。至少应该有自己的Codename。 <br />
<br />
24. 你们的员工有印有公司Logo的T-Shirt么？<br />
要有。能增强归属感。当然，T-Shirt要做的好看一些，最好用80支的棉来做。别没穿几次就破破烂烂的。<br />
<br />
25. 总经理至少每月参加次项目组会议要的。<br />
要让team member觉得高层关注这个项目。<br />
<br />
26. 你们是给每个Dev开一个分支么？<br />
反对。Branch的管理以及Merge的工作量太大，而且容易出错。 <br />
<br />
27. 有人长期不Check-In代码么？<br />
不可以。对大部分项目来说，最多两三天就应该Check-In。 <br />
<br />
28. 在Check-In代码时都填写注释了么？<br />
要写的，至少一两句话，比如&#8220;解决了Bug No.225&#8221;。如果往高处拔，这也算做&#8220;配置审计&#8221;的一部分。<br />
<br />
29. 有没有设定每天Check-In的最后期限？<br />
要的，要明确Check-In Deadline。否则会Build Break。 <br />
<br />
30. 你们能把所有源码一下子编译成安装文件吗？ <br />
要的。这是每日编译（Daily Build）的基础。而且必须要能够做成自动的。 <br />
<br />
31. 你们的项目组做每日编译么？<br />
当然要做。有三样东西是软件项目/产品开发必备的：1. bug management; 2. source control; 3. daily build。 <br />
<br />
32. 你们公司有没有积累一个项目风险列表？<br />
要。Risk Inventory。否则，下个项目开始的时候，又只能拍脑袋分析Risk了。<br />
<br />
33. 设计越简单越好越简单越好。<br />
设计时候多一句话，将来可能就带来无穷无尽的烦恼。应该从一开始就勇敢的砍。这叫scope management。 <br />
<br />
34.
尽量利用现有的产品、技术、代码千万别什么东西都自己Coding。BizTalk和Sharepoint就是最好的例子，有这两个作为基础，可以把起点
提高很多。或者可以尽量多用现成的Control之类的。或者尽量用XML，而不是自己去Parse一个文本文件；尽量用RegExp，而不是自己从头操
作字符串，等等等等。这就是&#8220;软件复用&#8221;的体现。<br />
<br />
35. 你们会隔一段时间就停下来夯实代码么？<br />
要。最好一个月左右一次。传言去年年初Windows组在Stevb的命令下停过一个月增强安全。Btw，&#8220;夯&#8221;这个字念&#8220;hang&#8221;，第一声。 <br />
<br />
36. 你们的项目组每个人都写Daily Report么？<br />
要写。五分钟就够了，写10句话左右，告诉自己小组的人今天我干了什么。一则为了沟通，二则鞭策自己（要是游手好闲一天，自己都会不好意思写的）。<br />
<br />
37. 你们的项目经理会发出Weekly Report么？<br />
要。也是为了沟通。内容包括目前进度，可能的风险，质量状况，各种工作的进展等。<br />
<br />
38. 你们项目组是否至少每周全体开会一次？<br />
要。一定要开会。程序员讨厌开会，但每个礼拜开会时间加起来至少应该有4小时。包括team meeting, spec review meeting, bug triage meeting。千万别大家闷头写code。 <br />
<br />
39. 你们项目组的会议、讨论都有记录么？<br />
会前发meeting request和agenda，会中有人负责主持和记录，会后有人负责发meeting minutes，这都是effective meeting的要点。而且，每个会议都要形成agreements和action items。<br />
<br />
40. 其他部门知道你们项目组在干什么么？<br />
要发一些Newsflash给整个大组织。Show your team&#8217;s value。否则，当你坐在电梯里面，其他部门的人问：&#8220;你们在干嘛&#8221;，你回答&#8220;ABC项目&#8221;的时候，别人全然不知，那种感觉不太好。<br />
<br />
41. 通过Email进行所有正式沟通 <br />
Email的好处是免得抵赖。但也要避免矫枉过正，最好的方法是先用电话和当面说，然后Email来确认。 <br />
<br />
42. 为项目组建立多个Mailing Group <br />
如果在AD+Exchange里面，就建Distribution List。比如，我会建ABC Project Core Team，ABC
Project Dev Team，ABC Project All Testers，ABC Project Extended
Team等等。这样发起Email来方便，而且能让该收到email的人都收到、不该收到不被骚扰。 <br />
<br />
43. 每个人都知道哪里可以找到全部的文档么？<br />
应该每个人都知道。这叫做知识管理（Knowledge Management）。最方便的就是把文档放在一个集中的File Share，更好的方法是用Sharepoint。 <br />
<br />
44. 你做决定、做变化时，告诉大家原因了么？<br />
要告诉大家原因。Empower team
member的手段之一是提供足够的information，这是MSF一开篇的几个原则之一。的确如此，tell me why是人之常情，tell
me
why了才能有understanding。中国人做事喜欢搞限制，限制信息，似乎能够看到某一份文件的人就是有身份的人。大错特错。权威、权力，不在于
是不是能access information/data，而在于是不是掌握资源。 <br />
<br />
45. Stay agile and expect change 要这样。<br />
需求一定会变的，已经写好的代码一定会被要求修改的。做好心理准备，对change不要抗拒，而是expect change。 <br />
<br />
46. 你们有没有专职的软件测试人员？<br />
要有专职测试。如果人手不够，可以peer test，交换了测试。千万别自己测试自己的。 <br />
<br />
47. 你们的测试有一份总的计划来规定做什么和怎么做么？<br />
这就是Test Plan。要不要做性能测试？要不要做Usability测试？什么时候开始测试性能？测试通过的标准是什么？用什么手段，自动的还是手动的？这些问题需要用Test Plan来回答。<br />
<br />
48. 你是先写Test Case然后再测试的么？<br />
应该如此。应该先设计再编程、先test case再测试。当然，事情是灵活的。我有时候在做第一遍测试的同时补上test case。至于先test case再开发，我不喜欢，因为不习惯，太麻烦，至于别人推荐，那试试看也无妨。 <br />
<br />
49. 你是否会为各种输入组合创建测试用例？<br />
不要，不要搞边界条件组合。当心组合爆炸。有很多test case工具能够自动生成各种边界条件的组合??但要想清楚，你是否有时间去运行那么多test case。 <br />
<br />
50. 你们的程序员能看到测试用例么？<br />
要。让Dev看到Test Case吧。我们都是为了同一个目的走到一起来的：提高质量。<br />
<br />
51. 你们是否随便抓一些人来做易用性测试？ <br />
要这么做。自己看自己写的程序界面，怎么看都是顺眼的。这叫做审美疲劳??臭的看久了也就不臭了，不方便的永久了也就习惯了。<br />
<br />
52. 你对自动测试的期望正确么？<br />
别期望太高。依我看，除了性能测试以外，还是暂时先忘掉&#8220;自动测试&#8221;吧，忘掉WinRunner和LoadRunner吧。对于国内的软件测试的现状来说，只能&#8220;矫枉必须过正&#8221;了。<br />
<br />
53. 你们的性能测试是等所有功能都开发完才做的么？<br />
不能这样。性能测试不能被归到所谓的&#8220;系统测试&#8221;阶段。早测早改正，早死早升天。<br />
<br />
54. 你注意到测试中的杀虫剂效应了么？<br />
虫子有抗药性，Bug也有。发现的新Bug越来越少是正常的。这时候，最好大家交换一下测试的area，或者用用看其他工具和手法，就又会发现一些新bug了。<br />
<br />
55. 你们项目组中有人能说出产品的当前整体质量情况么？<br />
要有。当老板问起这个产品目前质量如何，Test Lead/Manager应该负责回答。 <br />
<br />
56. 你们有单元测试么？<br />
单元测试要有的。不过没有单元测试也不是不可以，我做过没有单元测试的项目，也做成功了??可能是侥幸，可能是大家都是熟手的关系。还是那句话，软件工程是非常实践、非常工程、非常灵活的一套方法，某些方法在某些情况下会比另一些方法好，反之亦然。 <br />
<br />
57. 你们的程序员是写完代码就扔过墙的么？<br />
大忌。写好一块程序以后，即便不做单元测试，也应该自己先跑一跑。虽然有了专门的测试人员，做开发的人也不可以一点测试都不做。微软还有Test Release Document的说法，程序太烂的话，测试有权踢回去。<br />
<br />
58. 你们的程序中所有的函数都有输入检查么？<br />
不要。虽然说做输入检查是write secure code的要点，但不要做太多的输入检查，有些内部函数之间的参数传递就不必检查输入了，省点功夫。同样的道理，未必要给所有的函数都写注释。写一部分主要的就够了。<br />
<br />
59. 产品有统一的错误处理机制和报错界面么？<br />
要有。最好能有统一的error message，然后每个error message都带一个error
number。这样，用户可以自己根据error number到user manual里面去看看错误的具体描述和可能原因，就像SQL
Server的错误那样。同样，ASP.NET也要有统一的Exception处理。可以参考有关的Application Block。<br />
<br />
60. 你们有统一的代码书写规范么？<br />
要有。Code Convention很多，搞一份来发给大家就可以了。当然，要是有FxCop这种工具来检查代码就更好了。 <br />
<br />
61. 你们的每个人都了解项目的商业意义么？<br />
要。这是Vision的意思。别把项目只当成工作。有时候要想着自己是在为中国某某行业的信息化作先驱者，或者时不时的告诉team
member，这个项目能够为某某某国家部门每年节省多少多少百万的纳税人的钱，这样就有动力了。平凡的事情也是可以有个崇高的目标的。<br />
<br />
62. 产品各部分的界面和操作习惯一致么？<br />
要这样。要让用户觉得整个程序好像是一个人写出来的那样。<br />
<br />
63. 有可以作为宣传亮点的Cool Feature么？<br />
要。这是增强团队凝聚力、信心的。而且，&#8220;一俊遮百丑&#8221;，有亮点就可以掩盖一些问题。这样，对于客户来说，会感觉产品从质量角度来说还是acceptable的。或者说，cool feature或者说亮点可以作为质量问题的一个事后弥补措施。 <br />
<br />
64. 尽可能缩短产品的启动时间要这样。<br />
软件启动时间（Start-Up time）是客户对性能好坏的第一印象。<br />
<br />
65. 不要过于注重内在品质而忽视了第一眼的外在印象程序员容易犯这个错误：太看重性能、稳定性、存储效率，但忽视了外在感受。而高层经理、客户正相反。这两方面要兼顾，协调这些是PM的工作。<br />
<br />
66. 你们根据详细产品功能说明书做开发么？<br />
要这样。要有设计才能开发，这是必须的。设计文档，应该说清楚这个产品会怎么运行，应该采取一些讲故事的方法。设计的时候千万别钻细节，别钻到数据库、代码等具体实现里面去，那些是后面的事情，一步步来不能着急。<br />
<br />
67. 开始开发和测试之前每个人都仔细审阅功能设计么？<br />
要做。Function Spec review是用来统一思想的。而且，review过以后形成了一致意见，将来再也没有人可以说&#8220;你看，当初我就是反对这么设计的，现在吃苦头了吧&#8221;<br />
<br />
68. 所有人都始终想着The Whole Image么？<br />
要这样。项目里面每个人虽然都只是在制造一片叶子，但每个人都应该知道自己在制造的那片叶子所在的树是怎么样子的。我反对软件蓝领，反对过分的把软件制造看成流水线、车间。参见第61条。<br />
<br />
69. Dev工作的划分是单纯纵向或横向的么？<br />
不能单纯的根据功能模块分，或者单纯根据表现层、中间层、数据库层分。我推荐这么做：首先根据功能模块分，然后每个&#8220;层&#8221;都有一个Owner来Review所有人的设计和代码，保证consistency。 <br />
<br />
70. 你们的程序员写程序设计说明文档么？<br />
要。不过我听说微软的程序员1999年以前也不写。所以说，写不写也不是绝对的，偷懒有时候也是可以的。参见第56条。<br />
<br />
71. 你在招人面试时让他写一段程序么？<br />
要的。我最喜欢让人做字符串和链表一类的题目。这种题目有很多循环、判断、指针、递归等，既不偏向过于考算法，也不偏向过于考特定的API。<br />
<br />
72. 你们有没有技术交流讲座？<br />
要的。每一两个礼拜搞一次内部的Tech Talk或者Chalk Talk吧。让组员之间分享技术心得，这笔花钱送到外面去培训划算。<br />
<br />
73. 你们的程序员都能专注于一件事情么？<br />
要让程序员专注一件事。例如说，一个部门有两个项目和10个人，一种方法是让10个人同时参加两个项目，每个项目上每个人都花50%时间；另一种方
法是5个人去项目A，5个人去项目B，每个人都100%在某一个项目上。我一定选后面一种。这个道理很多人都懂，但很多领导实践起来就把属下当成可以任意
拆分的资源了。 <br />
<br />
74. 你们的程序员会夸大完成某项工作所需要的时间么？<br />
会的，这是常见的，尤其会在项目后期夸大做某个change所需要的时间，以次来抵制change。解决的方法是坐下来慢慢磨，磨掉程序员的逆反心理，一起分析，并把估算时间的颗粒度变小。 <br />
<br />
75. 尽量不要用Virtual Heads 最好不要用Virtual Heads。<br />
Virtual heads意味着resource is not secure，shared
resource会降低resource的工作效率，容易增加出错的机会，会让一心二用的人没有太多时间去review spec、review
design。一个dedicated的人，要强过两个只能投入50%时间和精力的人。我是吃过亏的：7个part
time的tester，发现的Bug和干的活，加起来还不如两个full-time的。参见第73条。73条是针对程序员的，75条是针对
Resource Manager的。<br />
<br />
A excerption from http://developer.e800.com.cn/articles/2007/1229/1198891618101_1.html<br />
<img src ="http://www.blogjava.net/echo/aggbug/172910.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2008-01-05 10:43 <a href="http://www.blogjava.net/echo/archive/2008/01/05/172910.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Web开发设计的五大准则</title><link>http://www.blogjava.net/echo/archive/2007/12/13/167584.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Thu, 13 Dec 2007 12:03:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/12/13/167584.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/167584.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/12/13/167584.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/167584.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/167584.html</trackback:ping><description><![CDATA[<div id="article_body">Excerpted from http://www.yeeyan.com/articles/view/6559/3448<br />
<br />
<p>如果仓促而为，设计一个专题或者网站一定会成为恶梦。Web设计需要遵循一些准则并有计划地去做。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Rule #1 : 先出设计图</p>
<p>这是必须的。不要假设设计图在你的头脑中就开始设计web，必须要放到纸上。可以这样做：</p>
<p>1，&nbsp; 拿尺子、笔和纸，按照具体的尺寸一行一行地画下来；</p>
<p>2，&nbsp; 记得考虑分界线的长度等，这样才能符合CSS的像素；</p>
<p>3，&nbsp; 记下设计的每一个细节免得忘记，如果把所有细节都累积到最后将是巨大的麻烦。</p>
<p>Rule #2 :配色</p>
<p>这是设计的核心部分，只有颜色搭配合适才能使你的网页看起来不错。首先要决定的是主色，也即你在网页中多数使用的颜色；然后选择跟主色调搭配的第二颜色；不要选择超过三种颜色不然你的设计看起来会很乱。如果你想要更多的颜色，可以使用浅色或者深色的阴影来搭配主色调。</p>
<p>1，&nbsp; 浏览十个跟你网页有同样主色调的网页；</p>
<p>2，&nbsp; 给几个人看你的配色方案并取得反馈；</p>
<p>3，&nbsp; 从浏览的网页和反馈你将更好地完善你的颜色搭配。</p>
<p>Rule #3 : 从基本的版块开始构建</p>
<p>定下配色和设计图之后，从最基本的框架开始构建——我的意思是说不添加任何文本。因为在版面中加入文本会使得架构混乱。方法如下：</p>
<p>1，&nbsp; 每一个版块设定边界线，这样能够看到具体的尺寸和位置；</p>
<p>2，&nbsp; 对不同的版块使用不同的颜色，在完成版块后再改成你想要的颜色。</p>
<p>Rule #4 : 理清CSS</p>
<p>不要在你的HTML文件中将styling元素搞得太复杂，不然等到你修改的时候你就不得不到处搜索。所以将所有styling元素归置在一个单独的CSS文档中。</p>
<p>在styling之前理清你的CSS免得太过杂乱导致你多次重复同一件事。CSS支持继承，也即parent block的style可以用于child
block.，充分利用这条特性。命名CSS分类名也要易懂易记。比如使用&#8220;main_content&#8221;而不是&#8220;div_1&#8221;。</p>
<p>Rule #5 : 制订多重 CSS 文档</p>
<p>我们都知道，使用浏览器可以轻易地看到网页的输出，但使用另一浏览器的时候则可能发现输出不正常。这不是什么稀奇事儿，因为每个浏览器对HTML和CSS的处理方式都不一样。</p>
<p>为避免这种情况，每个浏览器准备一个CSS文档，这样所有浏览器都可以正常浏览。虽然这有一定的难度，但是记着指望一个CSS文档来满足所有浏览器是不可能的。</p>
</div>
<img src ="http://www.blogjava.net/echo/aggbug/167584.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-12-13 20:03 <a href="http://www.blogjava.net/echo/archive/2007/12/13/167584.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>注重实效的程序员（The Pragmatic Programmer） </title><link>http://www.blogjava.net/echo/archive/2007/11/28/163811.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Wed, 28 Nov 2007 13:03:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/11/28/163811.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/163811.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/11/28/163811.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/163811.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/163811.html</trackback:ping><description><![CDATA[<div class="postTitle"><br />
&nbsp;</div>
<p><a name="1"></a><strong>1、关心你的技艺</strong> <br />
Care About Your Craft <br />
除非你在乎能否漂亮地开发出软件，否则其它事情都是没有意义的。 </p>
<p><a name="2"></a><strong>2、思考！你的工作</strong> <br />
Think!About Your Work <br />
在你做某件事情的时候思考你在做什么。不间断地思考，实时地批判你的工作。这将占据你的一些宝贵时间，酬劳则是更为活跃地参与你喜爱的工作、感觉到自己在掌握范围日增的各种主题以及因感受到持续的进步而欢愉。从长远来说，你在时间上的投入将会随着你和你的团队变得更为高效、编写出更易于维护的代码以及开会时间的减少而得到回报。 <br />
</p>
<p><a name="3"></a><strong>3、提供各种选择，不要找蹩脚的借口</strong> <br />
Provide Options,Don't Make Lame Excuses <br />
不要说事情做不到；要说明<em>能够</em>做什么来挽回局面。不要害怕提出要求，也不要害怕承认你需要帮助。 </p>
<p><a name="4"></a><strong>4、不要容忍破窗户</strong> <br />
Don't Live With Broken Windows <br />
不要留着&#8220;破窗户&#8221;（低劣的设计、错误的决策、或者糟糕的代码）不修。发现一个就修一个。如果没有足够的时间进行适当的修理，采取<em>某种</em>行动防止进一步的破坏，并说明情势处在你的控制之下。 <br />
如果你发现你所在团队和项目的代码十分漂亮——编写整洁、设计良好，并且很优雅，<em>你</em>不会想成为第一个弄脏东西的人。 </p>
<p><a name="5"></a><strong>5、做变化的催化剂</strong> <br />
Be a Catalyst for Change <br />
你不能强迫人们改变。相反，要向他们展示未来可能会怎样，并帮助他们参与对未来的创造。 <br />
设计出你<em>可以</em>合理要求的东西，好好开发它。一旦完成，就拿给大家看，让他们大吃一惊。然后说：&#8220;要是我们增加...<em>可能</em>就会更好。&#8221;假装那并不重要。坐回椅子上，等着他们开始要你增加你本来就想要的功能。人们发现，参与正在发生的成功要更容易。让他们瞥见未来，你就能让他们聚集在你周围。 </p>
<p><a name="6"></a><strong>6、记住大图景</strong> <br />
Remember the Big Picture <br />
如果你抓一只青蛙放进沸水里，它会一下子跳出来。但是，如果你把青蛙放进冷水里，然后慢慢加热，青蛙不会注意到温度的缓慢变化，会呆在锅里，直到被煮熟。 <br />
不要像青蛙一样。留心大图景。要持续不断地观察周围发生的事情，而不只是你自己在做的事情。 </p>
<p><a name="7"></a><strong>7、使质量成为需求问题</strong> <br />
Make Quality a Requirements Issue <br />
你所制作的系统的范围和质量应该作为系统需求的一部分规定下来。让你的用户参与权衡，知道何时止步，提供<em>足够好的软件</em>。 </p>
<p><a name="8"></a><strong>8、定期为你的知识资产投资</strong> <br />
Invest Regularly in Your Knowledge Portfolio </p>
<li>让学习成为习惯。
<li>持续投入十分重要。一旦你熟悉了某种新语言或新技术，继续前进，学习另一种。
<li>是否在某个项目中使用这些技术，或者是否把它们放入你的简历，这并不重要。学习的过程将扩展你的思维，使你向着新的可能性和新的做事方式拓展。思维的&#8220;异花授粉&#8221;十分重要；设法把你学到的东西应用到你当前的项目中。即使你的项目没有使用该技术，你或许也能借鉴一些想法。例如，熟悉了面向对象，你就会用不同的方式编写纯C程序。
<li>如果你自己找不到答案，就去找出能找到答案的人。不要把问题搁在那里。
<p>&nbsp;</p>
<p><a name="9"></a><strong>9、批判地分析你读到的和听到的</strong> <br />
Critically Analyze What You Read and Hear <br />
不要被供应商、媒体炒作、或教条左右。要依照你自己的看法和你的项目的情况去对信息进行分析。 </p>
<p><a name="10"></a><strong>10、你说什么和你怎么说同样重要</strong> <br />
It's Both What You Say and the Way You Say It </p>
<li>作为开发者，我们必须在许多层面上进行交流。我们的时间有很大部分都花在交流上，所以我们需要把它做好。
<li>如果你不能有效地向他人传达你的了不起的想法，这些想法就毫无用处。
<li>知道你想要说什么；了解你的听众；选择时机；选择风格；让文档美观；让听众参与；做倾听者；回复他人。
<li>交流越有效，你就越有影响力。
<p>&nbsp;</p>
<p><a name="11"></a><strong>11、DRY原则——不要重复你自己</strong> <br />
DRY - Don't Repeat Yourself <br />
系统中的每一项知识都必须具有单一、无歧义、权威的表示。与此不同的做法是在两个或更多地方表达同一事物。如果你改变其中一处，你必须记得改变其它各处。这不是你能否记住的问题，而是你何时忘记的问题。 </p>
<p><a name="12"></a><strong>12、让复用变得容易</strong> <br />
Make it Easy to Reuse <br />
你要做的是营造一种环境，在其中要找到并复用已有的东西，比自己编写更容易。如果复用很容易，人们就会去复用。而如果不复用，你们就会有重复知识的风险。 </p>
<p><a name="13"></a><strong>13、消除无关事物之间的影响</strong> <br />
Eliminate Effects Between Unrelated Things <br />
我们想要设计自足（self-contained）的组件：独立，具有单一、良好定义的目的。如果组件是相互隔离的，你就知道你能够改变其中一个，而不用担心其余组件。只要你不改变组件的外部接口，你就可以放心：你不会造成波及整个系统的问题。 <br />
你得到两个主要好处：提高生产率与降低风险。 </p>
<p><a name="14"></a><strong>14、不存在最终决策</strong> <br />
There Are No Final Decisions <br />
没有什么永远不变——而如果你严重依赖某一事实，你几乎可以确定它将会变化。与我们开发软件的速度相比，需求、用以及硬件变得更快。通过<a href="http://www.cnblogs.com/guoadou/archive/2005/03/14/the_pragmatic_programmer.html#11">DRY原则</a>、<a href="http://www.cnblogs.com/guoadou/archive/2005/03/14/the_pragmatic_programmer.html#36">解耦</a>以及<a href="http://www.cnblogs.com/guoadou/archive/2005/03/14/the_pragmatic_programmer.html#37">元数据的使用</a>，我们不必做出许多关键的、不可逆转的决策。有许多人会设法保持代码的灵活性，而你还需要考虑维持架、部署及供应商集成等领域的灵活性。 </p>
<p><a name="15"></a><strong>15、用曳光弹找到目标</strong> <br />
Use Tracer Bullets to Find the Target <br />
曳光弹能通过试验各种事物并检查它们离目标有多远来让你追踪目标。 <br />
曳光弹代码含有任何一段产品代码都拥有的完整的错误检查、结构、文档、以及自查。它只不过功能不全而已。但是，一旦你在系统的各组件之间实现了端到端（end-to-end）的连接，你就可以检查你离目标还有多远，并在必要的情况下进行调整。一旦你完全瞄准，增加功能将是一件容易的事情。 </p>
<p><a name="16"></a><strong>16、为了学习而制作原型</strong> <br />
Prototype to Learn <br />
任何带有风险的事物。以前没有试过的事物，或是对于最终系统极其关键的事物。任何未被证明的、试验性的、或有疑问的事物。任何让你觉得不舒服的东西。都可以通过制作原型来研究。比如：架构；已有系统中的新功能；外部数据的结构或内容；第三方工具或组件；性能问题；用户界面设计等等。 <br />
原型制作是一种学习经验，其价值并不在于所产生的代码，而在于所学到的经验教训。 </p>
<p><a name="17"></a><strong>17、靠近问题领域编程</strong> <br />
Program Close to The Problem domain <br />
计算机语言会影响你思考问题的方式，以及你看待交流的方式。用你的用户的语言进行设计和编码。 </p>
<p><a name="18"></a><strong>18、估算，以避免发生意外</strong> <br />
Estimate to Avoid Surprises <br />
在着手之前先进行估算。你将提前发现潜在的问题。 <br />
1）要选择能反映你想要传达的精确度的单位； <br />
2）基本的估算诀窍：去问已经做过这件事情的人； <br />
3）理解提问内容； <br />
4）根据对问题的理解，建立粗略、就绪的思维模型骨架； <br />
5）把模型分解为组件，找出描述这些组件怎样交互的数学规则，确定每个组件的参数； <br />
6）给每个参数指定值，找出哪些参数对结果的影响最大，并致力于让它们大致正确； <br />
7）进行多次计算，改变关键参数的值，然后根据那些参数表达你的答案； <br />
8）在被要求进行估算时说的话：&#8220;我等会回答你&#8221;。 </p>
<p><a name="19"></a><strong>19、通过代码对进度表进行迭代</strong> <br />
Iterate the Schedule with the Code <br />
实行增量开发。追踪你的估算能力，提炼对迭代次数、以及在每次迭代中可以包含的内容的猜想。提炼会变得一次比一次好，对进度表的信心也将随之增长。你将给予管理部门你所能给予的最精确的进度估算。 </p>
<p><a name="20"></a><strong>20、用纯文本保存知识</strong> <br />
Keep Knowledge in Plain Text </p>
<li>保证不过时；
<li>杠杆作用：每一样工具，都能够在纯文本上进行操作；
<li>更易于测试；
<li>你需要确保所有各方能够使用公共标准进行通信。纯文本就是那个标准。
<p>&nbsp;</p>
<p><a name="21"></a><strong>21、利用命令shell的力量</strong> <br />
Use the Power of Command Shells <br />
GUI环境通常受限于它们的设计者想要提供的能力。当你想要快速地组合一些命令，以完成一次查询或某种其他的任务时，命令行要更为适宜。多使用你的命令shell，你会惊讶它能使你的生产率得到怎样的提高。 </p>
<p><a name="22"></a><strong>22、用好一种编辑器</strong> <br />
Use a Single Editor Well <br />
选一种编辑器，彻底了解它，并将其用于所有的编辑任务。如果你用一种编辑器进行所有的文本编辑活动，你就不必停下来思考怎样完成文本操纵：必需的键击将成为本能反应。编辑器将成为你双手的延伸；键会在滑过文本和思想时歌唱起来。这就是我们的目标。 </p>
<p><a name="23"></a><strong>23、总是使用源码控制</strong> <br />
Always Use Source Code Control </p>
<li>总是。即使你的团队只有你一个人，你的项目只有一周时间；确保<em>每样东西</em>都处在源码控制之下。
<li>源码控制是你的工作的时间机器——你<em>能够</em>回到过去。
<li>把整个项目置于源码控制系统的保护之下具有一项很大的、隐蔽的好处：你可以进行自动的和可重复的产品构建。
<p>&nbsp;</p>
<p><a name="24"></a><strong>24、要修正问题，而不是发出指责</strong> <br />
Fix the Problem,Not the Blame <br />
要接受事实：调试就是解决问题，要据此发起进攻。Bug是你的过错还是别人的过错，并不是真的很有关系。它仍然是你的问题。 </p>
<p><a name="25"></a><strong>25、不要恐慌</strong> <br />
Don't Panic <br />
做一次深呼吸，<strong>思考</strong>什么可能是bug的原因。 </p>
<li>要总是设法找出问题的根源，而不只是问题的特定表现；
<li>搜集所有的相关数据；
<li>开始修正bug的最佳途径是让其可再现；
<li>使你的数据可视化；
<li>跟踪：观察程序或数据结构随时间变化的状态；
<li>找到问题的原因的一种非常简单、却又特别有用的技术是向别人解释它。你只是一步步解释代码要做什么，常常就能让问题从屏幕上跳出来，宣布自己的存在。
<p>&nbsp;</p>
<p><a name="26"></a><strong>26、&#8220;Select&#8221;没有问题</strong> <br />
"Select" Isn't Broken <br />
Bug有可能存在于OS、编译器、或是第三方产品中——但这不应该是你的第一想法。有大得多的可能性的是，bug存在于正在开发的应用代码中。与假定库本身出了问题相比，假定应用代码对库的调用不正确通常更有好处。即使问题确实应归于第三方，在提交bug报告之前，你也必须先消除你的代码中的bug。 </p>
<p><a name="27"></a><strong>27、不要假定，要证明</strong> <br />
Don't Assume it - Prove It <br />
不要因为你&#8220;知道&#8221;它能工作而轻易放过与bug有牵连的例程或代码。证明它。在实际环境中——使用真正的数据和边界条件——证明你的假定。 </p>
<p><a name="28"></a><strong>28、学习一种文本操作语言</strong> <br />
Learn a Text Manipulation Language <br />
你用每天的很大一部分时间处理文本，为什么不让计算机替你完成部分工作呢？ <br />
应用示例： </p>
<li>数据库schema维护;
<li>Java、C#属性(Property)访问;
<li>测试数据生成。
<p>&nbsp;</p>
<p><a name="29"></a><strong>29、编写能编写代码的代码</strong> <br />
Write Code That Writes Code <br />
代码生成器能提高你的生产率，并有助于避免重复。 </p>
<p><a name="30"></a><strong>30、你不可能写出完美的软件</strong> <br />
You Can't Write Perfect Software <br />
这刺痛了你？不应该。把它视为生活的公理，接受它，拥抱它，庆祝它。因为完美的软件不存在。在计算机简短的历史中，没有一个人曾经写出过一个完美的软件。你也不大可能成为第一个。除非你把这作为事实接受下来，否则你最终会把时间和精力浪费在追逐不可能实现的梦想上。 </p>
<p><a name="31"></a><strong>31、通过合约进行设计</strong> <br />
Design with Contracts <br />
什么是正确的程序？不多不少，做它声明要做的事情的程序。用文档记载这样的声明，并进行校验，是按合约设计（简称DBC）的核心所在。 <br />
这里，强调的重点是在&#8220;懒惰&#8221;的代码上：对在开始之前接受的东西要严格，而允诺返回的东西要尽可能少。 <br />
使用DBC的最大好处也许是它迫使需求与保证的问题走到前台来。在设计时简单地列举输入域的范围是什么、边界条件是什么、例程允诺交付什么——或者，更重要的，它不允诺交付什么——是向着编写更好的软件的一次飞跃。不对这些事项作出陈述，你就回到了靠巧合编程，那是许多项目开始、结束、失败的地方。 </p>
<p><a name="32"></a><strong>32、早崩溃</strong> <br />
Crash Early <br />
死程序不说谎。 <br />
当你的代码发现，某件被认为不可能发生的事情已经发生时，你的程序就不再有存活能力。从此时开始，它所做的任何事情都会变得可疑，所以要尽快终止它。死程序带来的危害通常比有问题的程序要小得多。 </p>
<p><a name="33"></a><strong>33、如果它不可能发生，用断言确保它不会发生</strong> <br />
If It Can't Happen,Use Assertions to Ensure That It Won't <br />
断言验证你的各种假定。在一个不确定的世界里，用断言保护你的代码。 <br />
不要用断言代替真正的错误处理。断言检查的是决不应该发生的事情。 </p>
<p><a name="34"></a><strong>34、将异常用于异常的问题</strong> <br />
Use Exceptions for Exceptional Problems <br />
异常表示即使的、非局部的控制转移——这是一种级联的（cascading）goto。异常应保留给意外事件。那些把异常用作其正常处理的一部分的程序，将遭受所有可读性和可维护性问题的折磨。这些程序破坏了封装：通过异常处理，例程和它们的调用者被更紧密地耦合在一起。 </p>
<p><a name="35"></a><strong>35、要有始有终</strong> <br />
Finish What You Start <br />
只要可能，分配某资源的例程或对象也应该负责解除其分配。 </p>
<p><a name="36"></a><strong>36、使模块之间的耦合减至最少</strong> <br />
Minimize Coupling Between Modules </p>
<li>编写&#8220;羞怯&#8221;的代码；
<li>函数的得墨忒耳(Demeter)法则规定，某个对象的任何方法都应该只调用属于以下情形的方法： <br />
1）它自身； <br />
2）传入该方法的任何参数； <br />
3）它创建的任何对象； <br />
4）任何直接持有的组件对象。
<li>物理解耦。
<p>&nbsp;</p>
<p><a name="37"></a><strong>37、要配置，不要集成</strong> <br />
Configure,Don't Integrate <br />
细节会弄乱我们整洁的代码——特别是如果它们经常变化。把它们赶出代码。当我们在与它作斗争时，我们可以让我们的代码变得高度可配置和&#8220;软和&#8221;——也就是，容易适应变化。 <br />
要用元数据（metadata）描述应用的配置选项：调谐参数、用户偏好（user preference）、安装目录，等等。 </p>
<p><a name="38"></a><strong>38、将抽象放进代码，细节放进元数据</strong> <br />
Put Abstractions in Code,Details in Metadata <br />
但我们不只是想把元数据用于简单的偏好。我们想要尽可能多地通过元数据配置和驱动应用。我们的目标是以声明方式思考（规定要做什么，而不是怎么做），并创建高度灵活和可适应的应用。我们通过采用一条一般准则来做到这一点：为一般情况编写程序，把具体情况放在别处——在编译的代码库之外。 <br />
也许你在编写一个具有可怕的工作流需求的系统。动作会根据复杂的（和变化的）商业规则启动和停止。考虑在某种基于规则的系统（即专家系统）中对它们进行编码，并嵌入到你的应用中。这样，你将通过编写规则、而不是修改代码来配置它。 </p>
<p><a name="39"></a><strong>39、分析工作流，以改善并发性</strong> <br />
Analyze Workflow to Improve Concurrency <br />
时间是软件架构的一个常常被忽视的方面。时间有两个方面对我们很重要：并发（事情在同一时间发生）和次序（事情在时间中的相对位置）。 <br />
我们在编写程序时，通常并没有把这两个方面放在心上。当人们最初坐下来开始设计架构，或是编写代码时，事情往往是线性的。那是大多数人的思考方式——总是先做这个，然后再做那个。但这样思考会带来时间耦合：方法A必须总是在方法B之前调用；同时只能运行一个报告；在接收到按钮点击之前，你必须等待屏幕重画。&#8220;嘀&#8221;必须在&#8220;嗒&#8221;之前发生。 <br />
这样的方法不那么灵活，也不那么符合实际。 <br />
我们需要容许并发，并考虑解除任何时间或者次序上的依赖。 </p>
<p><a name="40"></a><strong>40、用服务进行设计</strong> <br />
Design Using Services <br />
实际上我们创建的并不是组件，而是<em>服务</em>——位于定义良好的、一致的接口之后的独立、并发的对象。 <br />
通过把你的系统架构成多个独立的服务，你可以让配置成为动态的。 </p>
<p><a name="41"></a><strong>41、总是为并发进行设计</strong> <br />
Always Design for Concurrency <br />
首先，必须对任何全局或静态变量加以保护，使其免于并发访问，现在也许是问问你自己、你最初为何需要全局变量的好时候。此外，不管调用的次序是什么，你都需要确保你给出的是一致的状态信息。 <br />
在被调用时，对象必须总是处在有效的状态中，而且它们可能会在最尴尬的时候被调用。你必须确保，在任何可能被调用的时刻，对象都处在有效的状态中。这一问题常常出现在构造器与初始化例程分开定义的类中（构造器没有使对象进入已初始化状态）。 <br />
一旦你设计了具有并发要素的架构，你可以灵活地处理应用的部署方式：单机、客户-服务器、或是n层。 </p>
<p><a name="42"></a><strong>42、使视图与模型分离</strong> <br />
Separate Views from Models <br />
也就是常说的MVC模式（Model-View-Controller）。 </p>
<li>模型。表示目标对象的抽象数据模型。模型对任何视图或控制器都没有直接的了解。
<li>视图。解释模型的方式。它订阅模型中的变化和来自控制器的逻辑事件。
<li>控制器。控制视图、并向模型提供新数据的途径。 <br />
通过松解模型与视图/控制器之间的耦合，你用低廉的代价为自己换来了许多灵活性。
<p>&nbsp;</p>
<p><a name="43"></a><strong>43、用黑板协调工作流</strong> <br />
Use Blackboards to Coordinate Workflow <br />
用黑板协调完全不同的事实和因素，同时又使各参与方保持独立和隔离。 <br />
现代的分布式类黑板（blackboard-like）系统，比如JavaSpaces和T Spaces。 </p>
<p><a name="44"></a><strong>44、不要靠巧合编程</strong> <br />
Don't Program by Coincidence </p>
<li>总是意识到你在做什么。
<li>不要盲目地编程。试图构建你不完全理解的应用，或是使用你不熟悉的技术，就是希望自己被巧合误导。
<li>按照计划行事。
<li>依靠可靠的事物。如果你无法说出各种特定情形的区别，就假定是最坏的。
<li>为你的假定建立文档。&#8220;按合约编程&#8221;有助于澄清你头脑中的假定，并且有助于把它们传达给别人。
<li>不要只是测试你的代码，还要测试你的假定。
<li>为你的工作划分优先级。
<li>不要做历史的奴隶。不要让已有的代码支配将来的代码。 <br />
所以下次有什么东西看起来能工作，而你却不知道为什么，要确定它不是巧合。
<p>&nbsp;</p>
<p><a name="45"></a><strong>45、估算你的算法的阶</strong> <br />
Estimate the Order of Your Algorithms <br />
在你编写代码<em>之前</em>，先大致估算事情需要多长时间。 </p>
<p><a name="46"></a><strong>46、测试你的估算</strong> <br />
Test Your Estimates <br />
对算法的数学分析并不会告诉你每一件事情。在你的代码的目标环境中测定它的速度。 </p>
<p><a name="47"></a><strong>47、早重构，常重构</strong> <br />
Refactor Early,Refactor Often <br />
在需要时对代码进行重写、重做和重新架构。要铲除问题的根源。<a href="http://www.cnblogs.com/guoadou/archive/2005/03/14/the_pragmatic_programmer.html#4">不要容忍破窗户</a>。 <br />
关于重构，详见Martin Fowler的<a href="http://www.china-pub.com/computers/common/info.asp?id=12901" target="new">《重构》</a>一书。 </p>
<p><a name="48"></a><strong>48、为测试而设计</strong> <br />
Design to Test <br />
在你还没有编写代码时就开始思考测试问题。测试驱动开发？ </p>
<p><a name="49"></a><strong>49、测试你的软件，否则你的用户就得测试</strong> <br />
Test Your Software,or Your Users Will <br />
测试是技术，但更是文化。一点预先的准备可以大大降低维护费用、减少客户服务电话。 </p>
<p><a name="50"></a><strong>50、不要使用你不理解的向导代码</strong> <br />
Don't Use Wizard Code You Don't Understand <br />
向导很了不起。只需要点击一个按钮，回答一些简单的问题，向导就会自动为你生成骨架代码（skeleton code）。但如果你使用向导，却不理解它制作出的<em>所有</em>代码，你就无法控制你自己的应用。你没有能力维护它，而且在调试时会遇到很大的困难。 </p>
<p><a name="51"></a><strong>51、不要搜集需求——挖掘它们</strong> <br />
Don't Gather Requirements - Dig for Them <br />
需求很少存在于表面上。它们深深地埋藏在层层假定、误解和政治手段的下面。 </p>
<p><a name="52"></a><strong>52、与用户一同工作，以像用户一样思考</strong> <br />
Work with a User to Think Like a User <br />
要了解系统<em>实际上</em>将如何被使用，这是最好的方法。开采需求的过程也是开始与用户群建立和谐的关系、了解他们对你正在构建的系统的期许和希望的时候。 </p>
<p><a name="53"></a><strong>53、抽象比细节活得更长久</strong> <br />
Abstractions Live Longer than Details <br />
&#8220;投资&#8221;于抽象，而不是实现。抽象能在来自不同的实现和新技术的变化的&#8220;攻击&#8221;之下存活下去。 </p>
<p><a name="54"></a><strong>54、使用项目词汇表</strong> <br />
Use a Project Glossary <br />
如果用户和开发者用不同的名称指称同一事物，或是更糟，用同一名称指称不同事物，这样的项目很难取得成功。 </p>
<p><a name="55"></a><strong>55、不要在盒子外面思考——要找到盒子</strong> <br />
Don't Think Outside the Box - Find the Box <br />
在遇到不可能解决的问题时，问问自己以下问题： </p>
<li>有更容易的方法吗？
<li>你是在设法解决真正的问题，还是被外围的技术问题转移了注意力？
<li>这件事情为什么是一个问题？
<li>是什么使它如此难以解决？
<li>它必须以这种方式完成吗？
<li>它真的必须完成吗？ <br />
很多时候，当你设法回答这些问题时，你会有让自己吃惊的发现。很多时候，对需求的重新诠释能让整个问题全部消失。 <br />
你所需要的只是<em>真正的</em>约束、令人误解的约束、还有区分它们的智慧。
<p>&nbsp;</p>
<p><a name="56"></a><strong>56、倾听反复出现的疑虑——等你准备好再开始</strong> <br />
Listen to Nagging Doubts - Start When You're Ready <br />
你的一生都在积累经验与智慧。当你面对一件任务时，如果你反复感觉到疑虑，或是体验到某种勉强，要注意它。你可能无法准确地指出问题所在，但给它时间，你的疑虑很可能就会结晶成某种更坚实的东西，某种你可以处理的东西。软件开发仍然不是科学。让你的直觉为你的表演做出贡献。 </p>
<p><a name="57"></a><strong>57、对有些事情&#8220;做&#8221;胜于&#8220;描述&#8221;</strong> <br />
Some Things Are Better Done Than Described <br />
你应该倾向于把需求搜集、设计、以及实现视为同一个过程——交付高质量的系统——的不同方面。不要掉进规范的螺旋，在某个时刻，你需要开始编码。 </p>
<p><a name="58"></a><strong>58、不要做形式方法的奴隶</strong> <br />
Don't Be a Slave to Formal Methods <br />
如果你没有把某项技术放进你的开发实践和能力的语境中，不要盲目地采用它。 </p>
<p><a name="59"></a><strong>59、昂贵的工具不一定能制作出更好的设计</strong> <br />
Expensive Tools Do Not Produce Better Designs <br />
小心供应商的炒作、行业教条、以及价格标签的诱惑。在考察工具的产出时，试着不要考虑它值多少钱。 </p>
<p><a name="60"></a><strong>60、围绕功能、而不是工作职务进行组织</strong> <br />
Organize Around Functionality,Not Job Functions <br />
把你的人划分成小团队，分别负责最终系统的特定方面的功能。让团队按照个人的能力，在内部自行进行组织。 <br />
但是，只有在项目拥有负责的开发者、以及强有力的项目管理时，这种途径才有效。创立一组自行其是的团队并放任自流，是一种灾难性的处方。 <br />
要记住，团队是由个体组成的。让每个成员都能以他们自己的方式闪亮。 </p>
<p><a name="61"></a><strong>61、不要使用手工流程</strong> <br />
Don't Use Manual Procedures <br />
shell脚本或批处理文件会一次次地以同一顺序执行同样的指令。我们可以自动安排备份、夜间构建、网站维护、以及其他任何可以无人照管地完成的事情。让计算机去做重复、庸常的事情——它会做得比我们更好。我们有更重要、更困难的事情要做。 </p>
<p><a name="62"></a><strong>62、早测试，常测试，自动测试。</strong> <br />
Test Early.Test Often.Test Automatically. <br />
与呆在书架上的测试计划相比，每次构建时运行的测试要有效得多。 </p>
<p><a name="63"></a><strong>63、要等到通过全部测试，编码才算完成</strong> <br />
Coding Ain't Done 'Til All the Tests Run <br />
就是这样。 </p>
<p><a name="64"></a><strong>64、通过&#8220;蓄意破坏&#8221;测试你的测试</strong> <br />
Use Saboteurs to Test Your Testing <br />
在单独的软件副本上故意引人bug，以检验测试能够抓住它们。 </p>
<p><a name="65"></a><strong>65、测试状态覆盖，而不是代码覆盖</strong> <br />
Test State Coverage,Not Code Coverage <br />
确定并测试重要的程序状态。只是测试代码行是不够的。即时具有良好的代码覆盖，你用于测试的数据仍然会有巨大的影响，而且，更为重要的是，你遍历代码的次序的影响可能是最大的。 </p>
<p><a name="66"></a><strong>66、一个bug只抓一次</strong> <br />
Find Bugs Once <br />
一旦测试员找到一个bug，这应该是测试员<em>最后</em>一次找到它。此后自动测试应该对其进行检查。 </p>
<p><a name="67"></a><strong>67、把英语当作又一种编程语言</strong> <br />
Treat English as Just Another Programming Language <br />
像你编写代码一样编写文档：遵守<a href="http://www.cnblogs.com/guoadou/archive/2005/03/14/the_pragmatic_programmer.html#11">DRY原则</a>、<a href="http://www.cnblogs.com/guoadou/archive/2005/03/14/the_pragmatic_programmer.html#37">使用元数据</a>、<a href="http://www.cnblogs.com/guoadou/archive/2005/03/14/the_pragmatic_programmer.html#42">MVC</a>、<a href="http://www.cnblogs.com/guoadou/archive/2005/03/14/the_pragmatic_programmer.html#28">自动生成</a>，等等。 </p>
<p><a name="68"></a><strong>68、把文档建在里面，不要拴在外面</strong> <br />
Build Documentation In,Don't Bolt It On <br />
与代码分离的文档不太可能被修正和更新。使用像JavaDoc和NDoc这样的工具，我们可以根据源码生成API级的文档。 <br />
文档和代码是同一底层模型的不同视图，但视图是<em>唯一</em>应该不同的东西。 </p>
<p><a name="69"></a><strong>69、温和地超出用户的期望</strong> <br />
Gently Exceed Your Users' Expectations <br />
要设法让你的用户惊讶。请注意，不是惊吓他们，而是要让他们高兴。要理解用户的期望，然后给他们的东西要多那么一点。给系统增加某种面向用户的特性所需的一点额外努力将一次又一次在商誉上带来回报。 </p>
<p><a name="70"></a><strong>70、在你的作品上签名</strong> <br />
Sign Your Work <br />
我们想要看到对所有权的自豪。&#8220;这是我编写的，我对自己的工作负责。&#8221;你的签名应该被视为质量的保证。当人们在一段代码上看到你的名字时，应该期望它是可靠的、用心编写的、测试过的和有文档的，一个真正的专业作品，由真正的专业人员编写。 <br />
一个<strong>注重实效的程序员</strong>。 </p>
</li>
<img src ="http://www.blogjava.net/echo/aggbug/163811.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-11-28 21:03 <a href="http://www.blogjava.net/echo/archive/2007/11/28/163811.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[z] JDK5.0中的enum</title><link>http://www.blogjava.net/echo/archive/2007/11/10/159565.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Sat, 10 Nov 2007 08:13:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/11/10/159565.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/159565.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/11/10/159565.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/159565.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/159565.html</trackback:ping><description><![CDATA[在像C这样强调数据结构的语言里，枚举是必不可少的一种数据类型。然而在java的早期版本中，是没有一种叫做enum的独立数据结构的。所以在以前的java版本中，我们经常使用interface来<font face="Arial">simulate一个enum。
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">interface</span><span> Color {&nbsp;&nbsp;&nbsp;</span></span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">static</span><span> </span><span class="keyword">int</span><span> RED&nbsp;&nbsp; = </span><span class="number">1</span><span>;&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">static</span><span> </span><span class="keyword">int</span><span> GREEN&nbsp;&nbsp;&nbsp;&nbsp; = </span><span class="number">2</span><span>;&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">static</span><span> </span><span class="keyword">int</span><span> BLUE = </span><span class="number">3</span><span>;&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>虽然这种simulation比较麻烦，但在以前也还应付的过去。可是随着java语言的发展，越来越多的呼声要求把enum这种数据结构独立出来，加入到java中。所以从java 1.5以后，就有了enum，这也是这篇blog要学习的topic。</p>
<p>学习的最好方式就是例子，先来一个：</p>
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> EnumDemo {&nbsp;&nbsp;&nbsp;</span></span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span> </span><span class="keyword">enum</span><span> Color {red, blue, green}</span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //there is not a ";" </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">void</span><span> main(String[] args) {&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">for</span><span>(Color s : Color.values()) {&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//enum的values()返回一个数组，这里就是Seasons[] </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(s);&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<div class="code_title">console results</div>
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span>red&nbsp;&nbsp;&nbsp;</span></span> </li>
    <li><span>blue&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>green&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>注意事项已经在code中注释出，还要说明一点的是，这个java文件编译完成后不只有一个EnumDemo.class，还会有一个<font face="Arial">EnumDemo$Color.class，奇怪吧！</font></p>
<p>Another e.g.</p>
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> EnumDemo {&nbsp;&nbsp;&nbsp;</span></span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span> </span><span class="keyword">enum</span><span> Color {red, blue, green}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span class="comment">//there is not a ";" </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">void</span><span> main(String[] args) {&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Color s = Color.blue;&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">switch</span><span> (s) {&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">case</span><span> red:</span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //notice: Color.red will lead to compile error </span><span>&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(</span><span class="string">"red case"</span><span>);&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">break</span><span>;&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">case</span><span> blue:&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(</span><span class="string">"blue case"</span><span>);&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">break</span><span>;&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">case</span><span> green:&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(</span><span class="string">"green case"</span><span>);&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">break</span><span>;&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">default</span><span>:&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">break</span><span>;&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>这个例子要说明的就是case的情况。</p>
<p>就这么多吗，当然不是，我们的enum结构还可以定义自己的方法和属性。</p>
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> EnumDemo {&nbsp;&nbsp;&nbsp;</span></span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span> </span><span class="keyword">enum</span><span> Color {&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; red, blue, green;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span class="comment">//there is a ";" </span><span>&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//notic: enum's method should be "static" </span><span>&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span> </span><span class="keyword">static</span><span> Color getColor(String s){&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>(s.equals(</span><span class="string">"red flag"</span><span>)){&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span> red;&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </span><span class="keyword">else</span><span> </span><span class="keyword">if</span><span>(s.equals(</span><span class="string">"blue flag"</span><span>)){&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span> blue;&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </span><span class="keyword">else</span><span> {&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span> green;&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp; }</span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //there is not ";" </span><span>&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">void</span><span> main(String[] args) {&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EnumDemo demo = </span><span class="keyword">new</span><span> EnumDemo();&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(demo.getFlagColor(</span><span class="string">"red flag"</span><span>));&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span> Color getFlagColor(String string){&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span> Color.getColor(string);&nbsp;&nbsp;&nbsp;</span> </li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;</span> </li>
    <li class="alt"><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
</font>
<img src ="http://www.blogjava.net/echo/aggbug/159565.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-11-10 16:13 <a href="http://www.blogjava.net/echo/archive/2007/11/10/159565.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDK1.5中的泛型 - [Z]</title><link>http://www.blogjava.net/echo/archive/2007/10/23/155141.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Mon, 22 Oct 2007 17:57:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/10/23/155141.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/155141.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/10/23/155141.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/155141.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/155141.html</trackback:ping><description><![CDATA[<div class="g_w_100" id="blogContent__fks_WjB3zv6M8IhTQU4rvvQ6c7lUiBrDr3uX" style="overflow: hidden">
<div class="g_t_left c07 content" id="blogtext__fks_WjB3zv6M8IhTQU4rvvQ6c7lUiBrDr3uX">
<p>不小心看到有人批判jdk1.5，先说java要强制转型不好的问题没解决，容器不能放基类型不好，接着说泛型没用。而恰恰Jdk1.5中解决了这些问题，所以感叹之余，把这篇文章改一下，详细的说说泛型。<br />
一，Java中的泛型：<br />
&nbsp;&nbsp;&nbsp; 在Java中能使用到泛型的多是容器类,如各种list map set，因为Java是单根继承，所以容器里边可以放的内容是任何Object，所以从意义上讲原本的设计才是泛型。但用过Java的人是否感觉每次转型很麻烦呢？ 而且会有些错误，比如一个容器内放入了异质对象，强制转型的时候会出现cast异常。而这中错误在编译器是<br />
无从发现的。所以jdk1.5中提供了泛型，这个泛型其实是向c++靠拢了.好，我们先看几个实例再细说原理。</p>
<p>二，泛型的用法:(多个实例)<br />
</p>
<div style="border-right: rgb(204,204,204) 1px solid; padding-right: 5px; border-top: rgb(204,204,204) 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: rgb(204,204,204) 1px solid; width: 98%; padding-top: 4px; border-bottom: rgb(204,204,204) 1px solid; background-color: rgb(238,238,238)"><span style="color: rgb(0,128,128)">1</span> <img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /> <span style="color: rgb(0,0,0)">实例A<br />
</span><span style="color: rgb(0,128,128)">2</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" />ArrayList</span> <span style="color: rgb(0,0,0)">&lt;</span> <span style="color: rgb(0,0,0)">String</span> <span style="color: rgb(0,0,0)">&gt;</span> <span style="color: rgb(0,0,0)">&nbsp;strList&nbsp;</span> <span style="color: rgb(0,0,0)">=</span> <span style="color: rgb(0,0,0)">&nbsp;</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,0,0)">&nbsp;ArrayList</span> <span style="color: rgb(0,0,0)">&lt;</span> <span style="color: rgb(0,0,0)">String</span> <span style="color: rgb(0,0,0)">&gt;</span> <span style="color: rgb(0,0,0)">();<br />
</span><span style="color: rgb(0,128,128)">3</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" />strList.add(</span> <span style="color: rgb(0,0,0)">"</span> <span style="color: rgb(0,0,0)">1</span> <span style="color: rgb(0,0,0)">"</span> <span style="color: rgb(0,0,0)">);<br />
</span><span style="color: rgb(0,128,128)">4</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" />strList.add(</span> <span style="color: rgb(0,0,0)">"</span> <span style="color: rgb(0,0,0)">2</span> <span style="color: rgb(0,0,0)">"</span> <span style="color: rgb(0,0,0)">);<br />
</span><span style="color: rgb(0,128,128)">5</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" />strList.add(</span> <span style="color: rgb(0,0,0)">"</span> <span style="color: rgb(0,0,0)">3</span> <span style="color: rgb(0,0,0)">"</span> <span style="color: rgb(0,0,0)">);<br />
</span><span style="color: rgb(0,128,128)">6</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /> </span><span style="color: rgb(0,128,0)">//</span> <span style="color: rgb(0,128,0)">关键点（1）&nbsp;注意下边这行，没有强制转型</span> <span style="color: rgb(0,128,0)"><br />
</span><span style="color: rgb(0,128,128)">7</span> <span style="color: rgb(0,128,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /> </span><span style="color: rgb(0,0,0)">String&nbsp;str&nbsp;</span> <span style="color: rgb(0,0,0)">=</span> <span style="color: rgb(0,0,0)">&nbsp;strList.get(</span> <span style="color: rgb(0,0,0)">1</span> <span style="color: rgb(0,0,0)">);<br />
</span><span style="color: rgb(0,128,128)">8</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /> </span><span style="color: rgb(0,128,0)">//</span> <span style="color: rgb(0,128,0)">关键点（2）然後我们加入，这个时候你会发现编译器报错，错误在编译器被发现，错误当然是发现的越早越好</span> <span style="color: rgb(0,128,0)"><br />
</span><span style="color: rgb(0,128,128)">9</span> <span style="color: rgb(0,128,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /> </span><span style="color: rgb(0,0,0)">strList.add(</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,0,0)">&nbsp;Object());</span> </div>
<br />
<div style="border-right: rgb(204,204,204) 1px solid; padding-right: 5px; border-top: rgb(204,204,204) 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: rgb(204,204,204) 1px solid; width: 98%; padding-top: 4px; border-bottom: rgb(204,204,204) 1px solid; background-color: rgb(238,238,238)"><span style="color: rgb(0,128,128)">1</span> <img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /> <span style="color: rgb(0,0,0)">实例B<br />
</span><span style="color: rgb(0,128,128)">2</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" />ArrayList</span> <span style="color: rgb(0,0,0)">&lt;</span> <span style="color: rgb(0,0,0)">Integer</span> <span style="color: rgb(0,0,0)">&gt;</span> <span style="color: rgb(0,0,0)">&nbsp;iList&nbsp;</span> <span style="color: rgb(0,0,0)">=</span> <span style="color: rgb(0,0,0)">&nbsp;</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,0,0)">&nbsp;ArrayList</span> <span style="color: rgb(0,0,0)">&lt;</span> <span style="color: rgb(0,0,0)">Integer</span> <span style="color: rgb(0,0,0)">&gt;</span> <span style="color: rgb(0,0,0)">();<br />
</span><span style="color: rgb(0,128,128)">3</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /> </span><span style="color: rgb(0,128,0)">//</span> <span style="color: rgb(0,128,0)">关键点（3）&nbsp;注意直接把整数放入了集合中，而没有用Integer包裹</span> <span style="color: rgb(0,128,0)"><br />
</span><span style="color: rgb(0,128,128)">4</span> <span style="color: rgb(0,128,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /> </span><span style="color: rgb(0,0,0)">iList.add(</span> <span style="color: rgb(0,0,0)">1</span> <span style="color: rgb(0,0,0)">);<br />
</span><span style="color: rgb(0,128,128)">5</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" />iList.add(</span> <span style="color: rgb(0,0,0)">2</span> <span style="color: rgb(0,0,0)">);<br />
</span><span style="color: rgb(0,128,128)">6</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" />iList.add(</span> <span style="color: rgb(0,0,0)">3</span> <span style="color: rgb(0,0,0)">);<br />
</span><span style="color: rgb(0,128,128)">7</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /> </span><span style="color: rgb(0,128,0)">//</span> <span style="color: rgb(0,128,0)">关键点（4）同样直接取出就是int</span> <span style="color: rgb(0,128,0)"><br />
</span><span style="color: rgb(0,128,128)">8</span> <span style="color: rgb(0,128,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /> </span><span style="color: rgb(0,0,255)">int</span> <span style="color: rgb(0,0,0)">&nbsp;num&nbsp;</span> <span style="color: rgb(0,0,0)">=</span> <span style="color: rgb(0,0,0)">&nbsp;iList.get(</span> <span style="color: rgb(0,0,0)">1</span> <span style="color: rgb(0,0,0)">);</span> </div>
<br />
<div style="border-right: rgb(204,204,204) 1px solid; padding-right: 5px; border-top: rgb(204,204,204) 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: rgb(204,204,204) 1px solid; width: 98%; padding-top: 4px; border-bottom: rgb(204,204,204) 1px solid; background-color: rgb(238,238,238)"><span style="color: rgb(0,128,128)">1</span> <img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /> <span style="color: rgb(0,0,0)">实例C<br />
</span><span style="color: rgb(0,128,128)">2</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /> </span><span style="color: rgb(0,128,0)">//</span> <span style="color: rgb(0,128,0)">关键点（5）展示一下key-value的时候要怎么写，同时key和value也可以是基本类型了。</span> <span style="color: rgb(0,128,0)"><br />
</span><span style="color: rgb(0,128,128)">3</span> <span style="color: rgb(0,128,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /> </span><span style="color: rgb(0,0,0)">HashMap</span> <span style="color: rgb(0,0,0)">&lt;</span> <span style="color: rgb(0,0,0)">Integer,Integer</span> <span style="color: rgb(0,0,0)">&gt;</span> <span style="color: rgb(0,0,0)">&nbsp;map&nbsp;</span> <span style="color: rgb(0,0,0)">=</span> <span style="color: rgb(0,0,0)">&nbsp;</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,0,0)">&nbsp;HashMap</span> <span style="color: rgb(0,0,0)">&lt;</span> <span style="color: rgb(0,0,0)">Integer,Integer</span> <span style="color: rgb(0,0,0)">&gt;</span> <span style="color: rgb(0,0,0)">();<br />
</span><span style="color: rgb(0,128,128)">4</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" />map.put(</span> <span style="color: rgb(0,0,0)">1</span> <span style="color: rgb(0,0,0)">,&nbsp;</span> <span style="color: rgb(0,0,0)">11</span> <span style="color: rgb(0,0,0)">);<br />
</span><span style="color: rgb(0,128,128)">5</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" />map.put(</span> <span style="color: rgb(0,0,0)">2</span> <span style="color: rgb(0,0,0)">,&nbsp;</span> <span style="color: rgb(0,0,0)">22</span> <span style="color: rgb(0,0,0)">);<br />
</span><span style="color: rgb(0,128,128)">6</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" />map.put(</span> <span style="color: rgb(0,0,0)">3</span> <span style="color: rgb(0,0,0)">,&nbsp;</span> <span style="color: rgb(0,0,0)">33</span> <span style="color: rgb(0,0,0)">);<br />
</span><span style="color: rgb(0,128,128)">7</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /> </span><span style="color: rgb(0,0,255)">int</span> <span style="color: rgb(0,0,0)">&nbsp;inum&nbsp;</span> <span style="color: rgb(0,0,0)">=</span> <span style="color: rgb(0,0,0)">&nbsp;map.get(</span> <span style="color: rgb(0,0,0)">1</span> <span style="color: rgb(0,0,0)">);<br />
</span><span style="color: rgb(0,128,128)">8</span> <span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /> </span></div>
<br />
三，看完了实例了，详细来说说为什么吧<br />
首先jdk1.5中的泛型，第一个解决的问题，就是Java中很多不必要的强制转型了，具体的实现,我们以ArrayList<br />
为例,下边是ArrayList中的片断代码:<br />
<br />
<div style="border-right: rgb(204,204,204) 1px solid; padding-right: 5px; border-top: rgb(204,204,204) 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: rgb(204,204,204) 1px solid; width: 98%; padding-top: 4px; border-bottom: rgb(204,204,204) 1px solid; background-color: rgb(238,238,238)"><span style="color: rgb(0,128,128)">&nbsp;1</span><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /><span style="color: rgb(0,0,0)">ArrayList类的定义，这里加入了</span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,0)">E</span><span style="color: rgb(0,0,0)">&gt;</span><span style="color: rgb(0,0,0)"><br />
</span><span style="color: rgb(0,128,128)">&nbsp;2</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /></span><span style="color: rgb(0,0,255)">public</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">class</span><span style="color: rgb(0,0,0)">&nbsp;ArrayList</span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,0)">E</span><span style="color: rgb(0,0,0)">&gt;</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">extends</span><span style="color: rgb(0,0,0)">&nbsp;AbstractList</span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,0)">E</span><span style="color: rgb(0,0,0)">&gt;</span><span style="color: rgb(0,0,0)"><br />
</span><span style="color: rgb(0,128,128)">&nbsp;3</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">implements</span><span style="color: rgb(0,0,0)">&nbsp;List</span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,0)">E</span><span style="color: rgb(0,0,0)">&gt;</span><span style="color: rgb(0,0,0)">,&nbsp;RandomAccess,&nbsp;Cloneable,&nbsp;java.io.Serializable<br />
</span><span style="color: rgb(0,128,128)">&nbsp;4</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /><br />
</span><span style="color: rgb(0,128,128)">&nbsp;5</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /></span><span style="color: rgb(0,128,0)">//</span><span style="color: rgb(0,128,0)">get方法,返回不再是Object&nbsp;而是E</span><span style="color: rgb(0,128,0)"><br />
</span><span style="color: rgb(0,128,128)">&nbsp;6</span><span style="color: rgb(0,128,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/ExpandedBlockStart.gif" align="top" display="inline"  ;?="" ;="" none?;="" codehighlighter1_196_246_open_text.style. codehighlighter1_196_246_closed_image.style. codehighlighter1_196_246_closed_text.style.  alt="" /><img style="display: none" src="http://www.java3z.com/cwbwebhome/article/article2/img1/ContractedBlock.gif" align="top" display="none"  ;?="" ;="" none?;="" codehighlighter1_196_246_open_text.style. codehighlighter1_196_246_closed_text.style. codehighlighter1_196_246_open_image.style.  alt="" /></span><span style="color: rgb(0,0,255)">public</span><span style="color: rgb(0,0,0)">&nbsp;E&nbsp;get(</span><span style="color: rgb(0,0,255)">int</span><span style="color: rgb(0,0,0)">&nbsp;index)&nbsp;</span><span style="border-right: rgb(128,128,128) 1px solid; border-top: rgb(128,128,128) 1px solid; display: none; border-left: rgb(128,128,128) 1px solid; border-bottom: rgb(128,128,128) 1px solid; background-color: rgb(255,255,255)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/dot.gif"  alt="" /></span><span><span style="color: rgb(0,0,0)">{<br />
</span><span style="color: rgb(0,128,128)">&nbsp;7</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;RangeCheck(index);<br />
</span><span style="color: rgb(0,128,128)">&nbsp;8</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">return</span><span style="color: rgb(0,0,0)">&nbsp;elementData[index];<br />
</span><span style="color: rgb(0,128,128)">&nbsp;9</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: rgb(0,0,0)"><br />
</span><span style="color: rgb(0,128,128)">10</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /></span><span style="color: rgb(0,128,0)">//</span><span style="color: rgb(0,128,0)">add方法,参数不再是Object&nbsp;而是E</span><span style="color: rgb(0,128,0)"><br />
</span><span style="color: rgb(0,128,128)">11</span><span style="color: rgb(0,128,0)"><img style="display: inline" src="http://www.java3z.com/cwbwebhome/article/article2/img1/ExpandedBlockStart.gif" align="top" display="inline"  ;?="" ;="" none?;="" codehighlighter1_296_391_open_text.style. codehighlighter1_296_391_closed_image.style. codehighlighter1_296_391_closed_text.style.  alt="" /><img style="display: none" src="http://www.java3z.com/cwbwebhome/article/article2/img1/ContractedBlock.gif" align="top" display="none"  ;?="" ;="" none?;="" codehighlighter1_296_391_open_text.style. codehighlighter1_296_391_closed_text.style. codehighlighter1_296_391_open_image.style.  alt="" /></span><span style="color: rgb(0,0,255)">public</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">boolean</span><span style="color: rgb(0,0,0)">&nbsp;add(E&nbsp;o)&nbsp;</span><span style="border-right: rgb(128,128,128) 1px solid; border-top: rgb(128,128,128) 1px solid; display: none; border-left: rgb(128,128,128) 1px solid; border-bottom: rgb(128,128,128) 1px solid; background-color: rgb(255,255,255)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/dot.gif"  alt="" /></span><span style="display: inline"><span style="color: rgb(0,0,0)">{<br />
</span><span style="color: rgb(0,128,128)">12</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;ensureCapacity(size&nbsp;</span><span style="color: rgb(0,0,0)">+</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,0)">1</span><span style="color: rgb(0,0,0)">);&nbsp;&nbsp;</span><span style="color: rgb(0,128,0)">//</span><span style="color: rgb(0,128,0)">&nbsp;Increments&nbsp;modCount!!</span><span style="color: rgb(0,128,0)"><br />
</span><span style="color: rgb(0,128,128)">13</span><span style="color: rgb(0,128,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/InBlock.gif" align="top"  alt="" /></span><span style="color: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;elementData[size</span><span style="color: rgb(0,0,0)">++</span><span style="color: rgb(0,0,0)">]&nbsp;</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">&nbsp;o;<br />
</span><span style="color: rgb(0,128,128)">14</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">return</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">true</span><span style="color: rgb(0,0,0)">;<br />
</span><span style="color: rgb(0,128,128)">15</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/ExpandedBlockEnd.gif" align="top"  alt="" />}</span></span><span style="color: rgb(0,0,0)"><br />
</span><span style="color: rgb(0,128,128)">16</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /></span></div>
<p><br />
四，Boxing 和UnBoxing<br />
看到上边的关键点（3）和（4）是否感觉惊奇呢，因为Java中烦人的除了强制转型，另一个就是基础类型了<br />
放入容器的时候要包装，取出了还要转回。Jdk1.5中解决了这个问题.如上边的使用方法<br />
<br />
五，泛型的生命周期（使用注意事项）<br />
如果我们试着把ArrayList&lt;String&gt; list的内容序列化，然後再读取出来，在使用的过程中会发现出错，<br />
为什么呢？用Stream读取一下回来的数据，你会发现&lt;String&gt;不见了，list变成了普通的ArrayList，而不是<br />
参数化型别的ArrayList了，为什么会这样呢 ？见下边的比较</p>
<p>六，C++的泛型和Java的泛型<br />
在泛型的实现上，C++和Java有着很大的不同，<br />
Java是擦拭法实现的<br />
C++是膨胀法实现的<br />
因为Java原本实现就是泛型的，现在加入型别，其实是"窄化",所以采用擦拭法，在实现上，其实是封装了原本的<br />
ArrayList,这样的话，对于下边这些情况，Java的实现类只有一个。<br />
<br />
</p>
<div style="border-right: rgb(204,204,204) 1px solid; padding-right: 5px; border-top: rgb(204,204,204) 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: rgb(204,204,204) 1px solid; width: 98%; padding-top: 4px; border-bottom: rgb(204,204,204) 1px solid; background-color: rgb(238,238,238)"><span style="color: rgb(0,128,128)">1</span><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /><span style="color: rgb(0,0,0)">ArrayList</span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,0)">Integer</span><span style="color: rgb(0,0,0)">&gt;</span><span style="color: rgb(0,0,0)">&nbsp;&nbsp;<img src="http://www.java3z.com/cwbwebhome/article/article2/img1/dot.gif"  alt="" />.;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">public</span><span style="color: rgb(0,0,0)">&nbsp;</span><span style="color: rgb(0,0,255)">class</span><span style="color: rgb(0,0,0)">&nbsp;ArrayList<br />
</span><span style="color: rgb(0,128,128)">2</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" />ArrayList</span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,0)">String</span><span style="color: rgb(0,0,0)">&gt;</span><span style="color: rgb(0,0,0)">&nbsp;&nbsp;<img src="http://www.java3z.com/cwbwebhome/article/article2/img1/dot.gif"  alt="" />..;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,0)">--</span><span style="color: rgb(0,0,0)">同上</span><span style="color: rgb(0,0,0)">--</span><span style="color: rgb(0,0,0)"><br />
</span><span style="color: rgb(0,128,128)">3</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" />ArrayList</span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,0)">Double</span><span style="color: rgb(0,0,0)">&gt;</span><span style="color: rgb(0,0,0)">&nbsp;&nbsp;<img src="http://www.java3z.com/cwbwebhome/article/article2/img1/dot.gif"  alt="" />..;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,0)">--</span><span style="color: rgb(0,0,0)">同上</span><span style="color: rgb(0,0,0)">--</span><span style="color: rgb(0,0,0)"><br />
</span><span style="color: rgb(0,128,128)">4</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" />而C</span><span style="color: rgb(0,0,0)">++</span><span style="color: rgb(0,0,0)">采用的是膨胀法,对于上边的三种情况实际是每一种型别都对应一个实现，实现类有多个<br />
</span><span style="color: rgb(0,128,128)">5</span><span style="color: rgb(0,0,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" />list</span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,255)">int</span><span style="color: rgb(0,0,0)">&gt;</span><span style="color: rgb(0,0,0)">&nbsp;li;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">class</span><span style="color: rgb(0,0,0)">&nbsp;list;&nbsp;</span><span style="color: rgb(0,128,0)">//</span><span style="color: rgb(0,128,0)">int&nbsp;版本</span><span style="color: rgb(0,128,0)"><br />
</span><span style="color: rgb(0,128,128)">6</span><span style="color: rgb(0,128,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /></span><span style="color: rgb(0,0,0)">list</span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,0)">string</span><span style="color: rgb(0,0,0)">&gt;</span><span style="color: rgb(0,0,0)">&nbsp;ls;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">class</span><span style="color: rgb(0,0,0)">&nbsp;list;&nbsp;</span><span style="color: rgb(0,128,0)">//</span><span style="color: rgb(0,128,0)">string&nbsp;版本</span><span style="color: rgb(0,128,0)"><br />
</span><span style="color: rgb(0,128,128)">7</span><span style="color: rgb(0,128,0)"><img src="http://www.java3z.com/cwbwebhome/article/article2/img1/None.gif" align="top"  alt="" /></span><span style="color: rgb(0,0,0)">list</span><span style="color: rgb(0,0,0)">&lt;</span><span style="color: rgb(0,0,255)">double</span><span style="color: rgb(0,0,0)">&gt;</span><span style="color: rgb(0,0,0)">&nbsp;ld;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0,0,255)">class</span><span style="color: rgb(0,0,0)">&nbsp;list;&nbsp;</span><span style="color: rgb(0,128,0)">//</span><span style="color: rgb(0,128,0)">double&nbsp;版本&nbsp;&nbsp;&nbsp;&nbsp;</span></div>
<p>这就造成了，在序列化后，Java不能分清楚原来的ArrayList是<br />
ArrayList&lt;Integer&gt;还是ArrayList<br />
<br />
七，题外话，在很多东西的实现上C++和Java有很多不同<br />
例如运算符的问题i=i++问题，<a href="http://www.blogjava.net/dreamstone/archive/2006/11/04/79058.html">详细看这里</a><br />
例如在C++中能很好实现的double-checked locking单态模式，在Java中几乎很难实现 <a href="http://www.blogjava.net/dreamstone/archive/2006/11/04/79026.html">详细看这里</a><br />
还有就是上边提到的泛型实现上。<br />
</p>
<p>八，Jdk 1.5加入了不少新东西，有些能很大的提高开发质量，例如Jdk1.4&nbsp;，Jdk.15中StringBuffer的不同<br />
因为从1。4转入1。5不久，所以慢慢会发一些在1。5的使用过程中发现的东西。<br />
<br />
最后，我们还可以自己写类似ArrayList这样的泛型类，至于如何自定义泛型类，泛型方法请参见候捷先生的文章</p>
</div>
</div>
<img src ="http://www.blogjava.net/echo/aggbug/155141.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-10-23 01:57 <a href="http://www.blogjava.net/echo/archive/2007/10/23/155141.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Z]JSP标签自定义 --- useBean </title><link>http://www.blogjava.net/echo/archive/2007/10/15/152828.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Sun, 14 Oct 2007 16:57:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/10/15/152828.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/152828.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/10/15/152828.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/152828.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/152828.html</trackback:ping><description><![CDATA[<p>今天要实现的功能是useBean标签。下表是它的一些属性和用途。（我只选了个比较重要的属性，并没有实现所有属性）</p>
<p>
<table bordercolordark="#ffffff" bordercolorlight="#4499ff" align="center" border="1" bordercolor="#ffffff" cellspacing="0" width="55%">
    <tbody>
        <tr class="COLORED">
            <th>属性 </th><th>用途 </th>
        </tr>
        <tr>
            <td><code>id</code> </td>
            <td>给将要应用bean的变量一个名字，如果发现有相同id和scope的bean对象，则应用此对象而不会产生一个新的例示。 </td>
        </tr>
        <tr>
            <td><code>class</code> </td>
            <td>指明了bean的整个包名。 </td>
        </tr>
        <tr>
            <td><code>scope</code> </td>
            <td>表
            明了此bean的作用范围，共有四个值：page, request, session, 和
            application，缺省的是page属性，表明此bean只能应用于当前页（保存在当前页的PageContext
            中）；request属性表明此bean只能应用于当前的用户请求中（保存在ServletRequest对象中）；session属性表明此bean能
            应用于当前HttpSession生命周期内的所有页面；application属性值则表明此bean能应用于共享ServletContext的所有
            页面。需要注意的是，当没有具有相同的id和scope对象时，一个jsp:useBean
            实体只能作用于一个新的例示中，反之，则作用于以前的对象，这时，在jsp:useBean标签之间的任何jsp:setParameter和其它实体都
            将被忽略。 </td>
        </tr>
        <tr>
            <td><code>type</code> </td>
            <td>说明将要索引对象的变量类型，它必须与类名及父类名相匹配。记住，这个变量的名字是由id属性值代替的。 </td>
        </tr>
        <tr>
            <td><code>beanName</code> </td>
            <td>给定此bean的名字，可以将其提供给bean的例示方法，只提供beanName和type而忽略class属性的情况是允许的。</td>
        </tr>
    </tbody>
</table>
</p>
<p class="head">&nbsp;下面是标签处理方法类:UseBean.java：</p>
<p>import javax.servlet.jsp.*;</p>
<p>import javax.servlet.jsp.tagext.*;</p>
<p>import java.lang.reflect.*;</p>
<p>//</p>
<p>public class UseBean extends TagSupport{&nbsp; //继承自TagSupport类</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private String scope;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private String type;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public UseBean(){super();}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *设置属性存取方法，这个方法由容器自动调用。setId()和getId()由系统自动实现</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void setScope(String s) {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.scope = s;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public String getScope(){return this.scope;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void setType(String type){</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.type=type;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public String getType(){return this.type;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /**</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *覆盖doStartTag方法</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int doStartTag() throws JspTagException&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object o = null;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // find the bean in the specified scope</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (scope.equals("page")) {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; o = pageContext.getAttribute(getId(),PageContext.PAGE_SCOPE);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (scope.equals("request")) {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; o = pageContext.getAttribute(getId(), PageContext.REQUEST_SCOPE);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (scope.equals("session")) {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; o = pageContext.getAttribute(getId(), PageContext.SESSION_SCOPE);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (scope.equals("application")) {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; o = pageContext.getAttribute(getId(), PageContext.APPLICATION_SCOPE);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(o==null)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("o is null!");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try{</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Class u=Class.forName(type);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; o=u.newInstance();//无参构造方法</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("create success!");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(Exception e){</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new JspTagException("error to created a "+getId()+" object!");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pageContext.setAttribute(getId(), o); //保存实例对象到上下文对象中</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return EVAL_BODY_INCLUDE; //返回类型</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>}</p>
<p>现
在我们已经把对象实例放到pageContext里了，是不是这样就可以在JSP页面中直接引用了？当然不是了，直接将JAVA对象放进
pageContext中与在脚本中直接引用是不同的。差别在于JSP容器要负责取得这个对象，以脚本变量的形式提供给页面。即JSP容器负责来维护脚本
变量与pageContext中相应对象的状态。有两种方法可以为自定义标签来声明脚本变量。</p>
<p>一种是声明variable，一种是通过TagExtraInfo类声明变量。前者是JDK1.2后的方法，优点是比较方便。后者因为要再写一个类文件，所以显得麻烦些，但更灵活，出于兼容性与功能上的考虑，建议还是采用后者。（关于此类的详细说明，请参考PPT文档）</p>
<p>&nbsp;import javax.servlet.jsp.*;</p>
<p>import javax.servlet.jsp.tagext.*;</p>
<p>&nbsp;public class UseBeanTag extends TagExtraInfo { </p>
<p>&nbsp;&nbsp;&nbsp; public VariableInfo[] getVariableInfo(TagData data) {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new VariableInfo[] {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new VariableInfo(</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data.getId(),</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data.getAttributeString("type"),</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true,</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VariableInfo.AT_BEGIN)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; };</p>
<p>&nbsp; }</p>
<p>}</p>
<p>&nbsp;</p>
<p>现在，定义一个useBean标签的工作已进行大半，下面该定义标签库描述（TLD）文件了，该文件是一个XML文档，主要定义标签的属性、处理类和扩展信息类的声明。主要声明部分如下：(tag.tld)</p>
<p>&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;（省去标头部分）</p>
<p>&lt;!-- useBEAN 标签--&gt;</p>
<p>&nbsp;&lt;tag&gt; </p>
<p>&lt;name&gt;useBEAN&lt;/name&gt;</p>
<p>&lt;!—声明标签处理类--&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;tag-class&gt;cn.dever.tag.UseBean&lt;/tag-class&gt;</p>
<p>&lt;!—声明标签扩展信息类--&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;tei-class&gt;cn.dever.taginfo.UseBeanTag&lt;/tei-class&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;!—主体内容类型--&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;body-content&gt;jsp&lt;/body-content&gt;</p>
<p>&lt;!—属性设置--&gt;</p>
<p>&nbsp;&nbsp; &lt;attribute&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;name&gt;scope&lt;/name&gt;</p>
<p>&lt;!—是否必选--&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;required&gt;true&lt;/required&gt;</p>
<p>&lt;!—是否可以使用JSP表达式--&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/attribute&gt;</p>
<p>&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;attribute&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;name&gt;id&lt;/name&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;required&gt;true&lt;/required&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/attribute&gt;</p>
<p>&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;attribute&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;name&gt;type&lt;/name&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;required&gt;true&lt;/required&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/attribute&gt;</p>
<p>&nbsp;&lt;/tag&gt;</p>
<p>其实这个标签库描述文件应该是最先建立的，因为我们主要是为了说明实现的方法，所以标签描述放在后边了。接下就是将刚才做的这些东西部署到我们的应用中去。在目标JSP页面中引用一下就OK了。</p>
<p>&lt;%@ taglib uri="/WEB-INF/tag.tld" prefix="dever" %&gt;</p>
<p>&lt;dever:useBEAN id="test" type="cn.dever.common.User" scope="page" /&gt;</p>
<p><br />
OK，到此为止</p>
<img src ="http://www.blogjava.net/echo/aggbug/152828.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-10-15 00:57 <a href="http://www.blogjava.net/echo/archive/2007/10/15/152828.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>写自定义标签时标记attribute里rtexprvalue的用法</title><link>http://www.blogjava.net/echo/archive/2007/10/14/152821.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Sun, 14 Oct 2007 15:45:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/10/14/152821.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/152821.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/10/14/152821.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/152821.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/152821.html</trackback:ping><description><![CDATA[其实以前也有写过自定义标签， 但是没有注意到过<strong>&lt;rtexprvalue&gt;</strong>的用法， 最近这几天又用上自定义标签了， 突然发现&lt;rtexprvalue&gt;的用法是有讲究的.<br />
<br />
<strong>rtexprvalue的全称是 Run-time Expression Value， 它用于表示是否可以使用JSP表达式.</strong><br />
<br />
<strong>当在&lt;attribute&gt;标签里指定&lt;rtexprvalue&gt;<span style="color: red;">true</span>&lt;/rtexprvalue&gt;时</strong>， 表示该自定义标签的某属性的值可以直接指定或者通过动态计算指定,&nbsp; example as follow:<br />
<br />
&lt;sql:query var="result" &gt;<br />
&nbsp;&nbsp;&nbsp; select * from mytable order by nameid<br />
&lt;/sql:query&gt;<br />
&lt;%request.setAttribute("nameid", "2"); %&gt;<br />
&lt;myTag:cupSize cupSize=<span style="color: red;">"1"</span> cupSizes="${result}"&gt;&lt;/myTag:cupSize&gt;<br />
&lt;myTag:cupSize cupSize=<span style="color: red;">"${nameid}"</span> cupSizes="${result}"&gt;&lt;/myTag:cupSize&gt;<br />
<br />
<br />
<strong>当在&lt;attribute&gt;标签里指定&lt;rtexprvalue&gt;<span style="color: red;">false</span>&lt;/rtexprvalue&gt;时</strong>， 表示该自定义标签的某属性的值只能直接指定,&nbsp; example as follow:<br />
&lt;myTag:cupSize cupSize=<span style="color: red;">"1"</span> cupSizes="${result}"&gt;&lt;/myTag:cupSize&gt;<br />
<img src ="http://www.blogjava.net/echo/aggbug/152821.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-10-14 23:45 <a href="http://www.blogjava.net/echo/archive/2007/10/14/152821.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>################################### Java学习清单 #########################################</title><link>http://www.blogjava.net/echo/archive/2007/10/12/152187.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Thu, 11 Oct 2007 16:11:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/10/12/152187.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/152187.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/10/12/152187.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/152187.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/152187.html</trackback:ping><description><![CDATA[<span style="color: red;">
<p>1．Java基础</p>
<p>（1）参考书：java编程思想</p>
<p>2．java&nbsp;web编程</p>
<p>（1）HTTP协议</p>
<p>（2）java网络编程：参考书：O'reilly的《java网络编程（第三版）》</p>
<p>（3）java多线程：参考书：O'reilly的《java线程》</p>
<p>（4）java&nbsp;I/O：参考书：O'reilly的《java&nbsp;I/O》、《java&nbsp;NIO》</p>
<p>2．J2EE编程</p>
<p>（１）JNDI：定位服务器资源（EJB组件，Datasouce，JMS）查找方法，难点在于服务器资源文件的配置。</p>
<p>（２）JTA：事务的控制的方法，以及在什么场合使用JTA（保证不同数据库操作的原子性）</p>
<p>（３）RMI：Remote&nbsp;Method&nbsp;Invocation，RMI是EJB的基础O'reilly的《java&nbsp;RMI》</p>
<p>（４）EJB：理解EJB是如何通过RMI来实现对远端对象的调用的，以及在什么情况下要用到。参考书：O'reilly的《Head&nbsp;First&nbsp;EJB》、《Master&nbsp;EJB&nbsp;3.0》</p>
<p>（５）JMS：</p>
<p>（6）Servlet/JSP：O'reilly的《java&nbsp;Servlet&nbsp;2.3》、《Head&nbsp;First&nbsp;JSP/Servlet》</p>
<p>（7）JDBC：O'reilly的《JDBC编程》</p>
<p>（8）<font face="Verdana">XML：O'reilly的《Java&nbsp;and&nbsp;XML》</font></p>
<p>2、领域知识的学习</p>
<p>（1）UML：</p>
<p>（2）Design&nbsp;Pattern：设计模式和框架的学习，包括EJB的设计模式和J2EE的核心模式，参考书：<font face="Verdana">O'reilly的</font>《Head&nbsp;First&nbsp;Design&nbsp;Pattern》、Gang&nbsp;of&nbsp;Four的《设计模式》、《J2EE设计模式》、《EJB设计模式》</p>
<p>3、Web&nbsp;Services</p>
<p>Web&nbsp;Services像是一种黏合剂，可以把不同的服务统一起来提供一个统一的调用接口，作为使用者来说，只要获得服务提供者的WSDL（对服务的描述）参考书：</p>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp;当你发现你已经可以掌握此程序语言之后，你可以选择：&nbsp;</p>
<p>（1）向上延伸：学习OOA、OOD、Design&nbsp;Patterns、以及软件工程，以培养做大型计划的能力&nbsp;<br />
（2）向下深入：深入了解系统内部的运作机制，例如操作系统、虚拟机器（Virtual&nbsp;Machine）、甚至硬件（hardware）内部。<br />
（3）向旁延伸：学习不同的API，例如：多媒体、数据库、企业运算（Enterprise&nbsp;Computing）&#8230;<br />
另外，数据结构（data&nbsp;structure）、算法（algorithm）等基础也很重要。</p>
</span>
<img src ="http://www.blogjava.net/echo/aggbug/152187.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-10-12 00:11 <a href="http://www.blogjava.net/echo/archive/2007/10/12/152187.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>From java.lang.reflect.Array source code To JVM</title><link>http://www.blogjava.net/echo/archive/2007/10/11/152174.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Thu, 11 Oct 2007 15:03:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/10/11/152174.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/152174.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/10/11/152174.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/152174.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/152174.html</trackback:ping><description><![CDATA[java.lang.reflect.Array的源码，里面全部都是一些native方法，即一些和操作系统打交道的方法，真正的实现方法和原理据说由C/C++在java虚拟机中实现了。
<p>所以java为什么跨平台，它和底层操作系统的交互全部由java虚拟机实现。一般的高级语言需要在不同平台运行则需要编译成不同的
目标代码，但是java却不需要，java使用java虚拟机屏蔽了与具体平台相关的信息，使得java编译程序生成在java虚拟机下运行的目标代
码，即字节码，即可在不同的平台上不加修改运行。java虚拟机在执行字节码的时候，把字节码解释成具体平台上的机器指令。</p>
<p>java代码要编译成class字节码文件，需要由JDK的javac进行编译（至于如何编译，其中的一些编译原理可参看sun的<strong><em>The&nbsp;Java</em><sup><font size="-1">TM</font></sup><em>&nbsp;Virtual&nbsp;Machine&nbsp;Specification</em></strong>），而jre则负责将class文件装载（装载原理略），对其进行安全检测等，最后由java解释器解释为具体平台上的机器指令。</p>
<img src ="http://www.blogjava.net/echo/aggbug/152174.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-10-11 23:03 <a href="http://www.blogjava.net/echo/archive/2007/10/11/152174.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TCP/IP和OSI分层模型比较</title><link>http://www.blogjava.net/echo/archive/2007/10/08/151155.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Mon, 08 Oct 2007 12:57:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/10/08/151155.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/151155.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/10/08/151155.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/151155.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/151155.html</trackback:ping><description><![CDATA[<div forimg="1">1、TCP/IP分层</div>
<div forimg="1">TCP/IP共分四层，分别是：网络连接层，网络层，传输层，应用层。我们一般做应用层的开发，用到的协议有HTTP协议，FTP协议，SMTP，POP3等协议。</div>
<div forimg="1"></div>
<div forimg="1"></div>
<div forimg="1">
<table cellspacing="1" cellpadding="0" border="0">
    <tbody>
        <tr>
            <td>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 12pt">4</span></p>
            </td>
            <td>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><strong><span style="font-size: 12pt">应用层</span></strong></p>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><em><span style="font-size: 12pt"><span>&nbsp;</span>(OSI</span></em><em><span style="font-size: 12pt">对应的<span>5-7</span>层<span>)</span></span></em></p>
            </td>
            <td>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 12pt"><a title="HTTP" href="http://zh.wikipedia.org/wiki/HTTP"><span style="color: rgb(51,51,51); text-decoration: none">HTTP</span></a>,&nbsp;<a title="File transfer protocol" href="http://zh.wikipedia.org/w/index.php?title=File_transfer_protocol&amp;action=edit"><span style="color: rgb(51,51,51); text-decoration: none">FTP</span></a>,&nbsp;<a title="DNS" href="http://zh.wikipedia.org/wiki/DNS"><span style="color: rgb(51,51,51); text-decoration: none">DNS</span></a></span><span style="font-size: 12pt">，<span>POP3</span></span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 12pt">3</span></p>
            </td>
            <td>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><strong><span style="font-size: 12pt">传输层</span></strong></p>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><em><span style="font-size: 12pt">(OSI</span></em><em><span style="font-size: 12pt">对应的<span>4-5</span>层<span>)</span></span></em></p>
            </td>
            <td>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 12pt"><a title="Transmission Control Protocol" href="http://zh.wikipedia.org/w/index.php?title=Transmission_Control_Protocol&amp;action=edit"><span style="color: rgb(51,51,51); text-decoration: none">TCP</span></a>,&nbsp;<a title="User Datagram Protocol" href="http://zh.wikipedia.org/w/index.php?title=User_Datagram_Protocol&amp;action=edit"><span style="color: rgb(51,51,51); text-decoration: none">UDP</span></a></span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 12pt">2</span></p>
            </td>
            <td>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><strong><span style="font-size: 12pt">网络层</span></strong></p>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><em><span style="font-size: 12pt">(OSI</span></em><em><span style="font-size: 12pt">的第<span>3</span>层<span>)</span></span></em></p>
            </td>
            <td>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 12pt">IP</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 12pt">1</span></p>
            </td>
            <td>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><strong><span style="font-size: 12pt">网络连接层</span></strong></p>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><em><span style="font-size: 12pt">(OSI</span></em><em><span style="font-size: 12pt">的<span>1-2</span>层<span>)</span></span></em></p>
            </td>
            <td>
            <p style="margin: 0cm 0cm 0pt; text-align: center" align="center"><span style="font-size: 12pt"><a title="Ethernet" href="http://zh.wikipedia.org/wiki/Ethernet"><span style="color: rgb(51,51,51); text-decoration: none">Ethernet</span></a>,<a title="Wi-Fi" href="http://zh.wikipedia.org/wiki/Wi-Fi"><span style="color: rgb(51,51,51); text-decoration: none">Wi-Fi</span></a>,<a title="Multiprotocol Label Switching" href="http://zh.wikipedia.org/w/index.php?title=Multiprotocol_Label_Switching&amp;action=edit"><span style="color: rgb(51,51,51); text-decoration: none">MPLS</span></a></span><span style="font-size: 12pt">等协议</span></p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<div forimg="1"></div>
<div forimg="1"></div>
<div forimg="1"><a href="http://hiphotos.baidu.com/chenning007/pic/item/3fc680223ba035f2d6cae220.jpg" target="_blank"></a></div>
<div forimg="1">2、ISO分层</div>
<div forimg="1">
<div forimg="1"><a href="http://hiphotos.baidu.com/chenning007/pic/item/3fc680223bbc35f2d6cae22c.jpg" target="_blank">
<p style="margin: 0cm 0cm 0pt"><span><font color="#000000">OSI/RM模型的对应关系是：&nbsp;<br />
<br />
网络连接层——物理层，数据链路层&nbsp;<br />
<br />
网络层——网络层&nbsp;<br />
<br />
传输层——传输层&nbsp;<br />
<br />
应用层——会话层，表示层，应用层</font></span></p>
<p style="margin: 0cm 0cm 0pt"><span><font color="#000000"></font></span></p>
<p style="margin: 0cm 0cm 0pt"><span><font color="#000000"></font></span></p>
</a></div>
</div>
<div forimg="1"></div>
<div forimg="1">3、TCP协议和UDP协议&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<li>传输控制协议TCP&nbsp;(Transport&nbsp;Control&nbsp;Protocol)&nbsp;-&nbsp;数据流传输（面向连接，可靠）&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li>
<li>用户数据报文协议UDP(User&nbsp;Datagram&nbsp;Protocol)&nbsp;-&nbsp;数据报文传输(无连接不可靠&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li>
</div>
<p>4、HTTP请求处理过程</p>
<p>浏览器发起请求获取页面信息，浏览器只和本机传输层对话。传输层将请求截取封装成TCP请求段，添加一些随机数字标识数据，然后把请求传给本地网络层。网络层把数据解析封装成一定大小的本地IP数据报，并且传输给网络连接层/网络连接层把数据报封装成物理介质的模拟信号数据，通过wire将数据传输到通过地址表识的远程机器的网络连接层，远程机器由网络连接层进行解析，一层一层往上解析，直至应用层。</p>
<img src ="http://www.blogjava.net/echo/aggbug/151155.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-10-08 20:57 <a href="http://www.blogjava.net/echo/archive/2007/10/08/151155.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Z]CMM欺骗了中国的软件业</title><link>http://www.blogjava.net/echo/archive/2007/09/18/146249.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Tue, 18 Sep 2007 12:45:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/09/18/146249.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/146249.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/09/18/146249.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/146249.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/146249.html</trackback:ping><description><![CDATA[中国人实际是一个很特殊的人群，中国人的思维方式、价值观和处世方式与西方国家的区别很大，这与中国历史几千年漫长的中国文化和集权管理有直接的关系。<br />
&nbsp;西方历史的发展是以科技为主线的，因此在西方的管理学中明显体现的是科学学科的态度和方法。在西方的管理学中分权和量化是两个重要的特点，而在中国的管理学中，为人处世却是主体，西方管理以事为主体，中国的管理以人为主体。<br />
&nbsp;国内现在通过了CMM/CMMI从二级到五级那么多的企业，有多少企业生存的比以前好？又有多少家企业从此就消失在这个行业中了？<br />
&nbsp;纵观国内软件行业的大局，究其原因有如下：<br />
&nbsp;1. 引入了模型却引入不了文化：<br />
&nbsp;&nbsp;任何一项管理制度和管理的方法模型都有其生长的根源和文化背景。比如独裁的管理、民主的管理等等。CMM起源于西方的软件行业，很多考虑问题的思路是有其背景的。比如分权治之的思想、量化管理的思想等。<br />
&nbsp;&nbsp;管理不仅仅是科学，尽管我个人认为过程管理更多是一门科学。但是管理离不开对人的管理，只要涉及到人在中国就不是一件单纯的事情了。<br />
&nbsp;&nbsp;另外国内的软件企业很少有成熟的企业文化的，这也是不论是CMM还是ISO9K都面临失败的原因之一。实施CMM更是一种文化的塑造和改革，是全体意识的提高和变革。自己本身都没有成熟的企业价值观和文化观，怎么可能让CMM在企业生根？不能在企业每个人的头脑中生根的CMM又怎么能发芽、开花、结果呢？国内企业通过CMM基本上都只是一个研发部或者产品部通过的。<br />
&nbsp;2. 软件，人的因素更重要：<br />
&nbsp;&nbsp;从软件技术开始，其质量和产出就是人的创造性和智力的结晶。尽管很多人鼓吹&#8220;软件蓝领&#8221;、&#8220;软件工厂&#8221;的概念，但是至少在二十年内，还看不到曙光。凡是可以用蓝领进行工厂化实现的技术具有如下的特点：<br />
&nbsp;&nbsp;■ 机械性，可明确切割动作（如泰勒实验中描述的）；<br />
&nbsp;&nbsp;■ 可替代性，入门容易，任何一个人的工作是可替代的，或者替代的成本是比较低的；<br />
&nbsp;&nbsp;■ 成本主要是材料，而不是人工；<br />
&nbsp;&nbsp;■ 标准化，生成工艺和成品是可以标准化的。<br />
&nbsp;&nbsp;从上面可以看到，软件行业明显与此是不同的。软件从最开始的Coding、Debug阶段都引入工程的概念在生产效率上提高了很多。但是目前不论是组件开发和面向对象还是代码生成都没有显著改变软件开发的质量和效率。我不否认软件工程或者传统行业的很多实践是可以引入到软件行业中的，但是我反对把软件生产当作传统行业生产的。至少在目前是做不到的，也许到了未来的人比现在聪明数倍、软件的标准和工具发展到想现在的扳手和车床一样。这似乎是个奢望。<br />
&nbsp;&nbsp;大家知道，同一个学校出来的学软件的学生，其生产效率和开发质量相差几倍甚至十倍是非常正常的事情，即便是同一个人，在受到公司重视，心情好的时候比他即将离职，对公司不抱有希望的时候的生产效率差几倍也是再正常不过的事情了。<br />
&nbsp;&nbsp;软件行业的人比其他行业的材料、工具和技术工人更复杂，其工作的动机更复杂、其社会和心理需求层次更高、人的个性差异性比较大。因此对于软件企业的人力资源的管理就更富有挑战性和以人为本。而CMM是过程模型，因此除了培训过程几乎是不关心人的。<br />
&nbsp;3. CMM更适合大型项目<br />
&nbsp;&nbsp;这是不争的事实，因为当初CMM的起源就是美国国防部为了有效控制和管理其项目而委托SEI的研究成果。国防部的项目100人月的项目就算是小项目，大部分都是几百人月甚至上千人月的项目。这种情况下没有规范的过程是不可行的事情。回头看看中国国内的情况，100人月的项目绝对算是大项目了，超过500万合同额的软件项目很少，有些甲方为了将项目分给更多的关系企业，往往人为地分成不同的项目来分包给不同的开发商。这些小项目往往是3-6个月的工期，交付的压力很大，客户的不成熟又往往看眼前的进度，而不是日后的质量。这就导致了国内很多项目是摇摇晃晃上线，提心吊胆维护，最好软件改的差不多稳定了，钱也花的差不多了。看起来是花很少的钱开发完成了，但是花更多的钱来修补。其实如果前期就能够按部就班，按照客观规律来做事，Total Cost就会减少很多。<br />
&nbsp;4. 分权与量化的尴尬<br />
&nbsp;&nbsp;在中国的历史中，最高管理者往往利用制衡的手段来统治和管理国家的。但是大家注意的是制衡，而不是分权。5000年的历史形成的文化和价值取向，分权是不现实的。从台湾的民主分权政治中我们也会发现缘由，中国人的民主分权意味着低效和成为独裁的幌子。再看软件企业，实施CMM的单位大部分都是在部门级或者技术范围内，很难看到分权和监督的作用。<br />
&nbsp;&nbsp;关于量化也是一样，我相信大多数中国人不是太相信数字的。因为中国人的头脑中都有自己的标准，而很少有人优先想到别人或者另外的标准。台湾曾仕强老师讲过一个例子，就是一家德国的机床厂家发现卖到中国的机床很容易坏，经常更换配件，对质量一贯比较严谨的德国人派人到中国考察原因。原来是说明书中说在机床底座固定螺丝在安装的时候必须要做到拧四圈后要放半圈。自以为聪明的中国人便按照自己的标准计算，拧四圈放半圈，那不就是拧三圈半吗？这样的量化出问题就不奇怪了。<br />
&nbsp;&nbsp;还有就是国家权威部门的统计数字往往是相互矛盾，口径不一，让劳动人民看得一头雾水。&nbsp;&nbsp;<br />
&nbsp;&nbsp;在中国要让数字说话，就很容易滋生造数字，大到国家政府统计部门，小到企业财务，再小就到每个人年龄、财产填报。只要是对自己有利，而别人又不容易发现，那就可以造假，因为造假成本低，打假成本高。<br />
&nbsp;&nbsp;再有就是哪个老板相信别人的数字？<br />
&nbsp;5. 是什么推动了CMM在中国的风行？<br />
&nbsp;&nbsp;CMM其实在欧洲和美国知名度并不高，很多大的软件企业甚至都不知道这是个什么东西，但是在中国，随着各地政府的优惠，加上不成熟的客户的跟风。大部分的企业看中的是一纸证书和政府的买单。很多国内知名的软件企业拿到证书后就解散了CMM的SEPG小组。而且国内的通过率历来是100%的事情，大家相信这其中没有猫腻？不在少数的通过CMM3级甚至5级的软件企业，这一两年过去后反而关门了。因此说如果没有一个正确的态度和企图来过CMM，那么再好的模型可能也起不到它的效果。<br />
<img src ="http://www.blogjava.net/echo/aggbug/146249.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-09-18 20:45 <a href="http://www.blogjava.net/echo/archive/2007/09/18/146249.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Z] Java Serializable（序列化）的理解和总结</title><link>http://www.blogjava.net/echo/archive/2007/09/16/145467.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Sun, 16 Sep 2007 01:49:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/09/16/145467.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/145467.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/09/16/145467.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/145467.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/145467.html</trackback:ping><description><![CDATA[<div class="postDetail" id="detail8a8a8a8f149228010114de76b377090b">
<strong>1、序列化是干什么的？<br />
</strong>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
简单说就是为了保存在内存中的各种对象的状态，并且可以把保存的对象状态再读出来。虽然你可以用你自己的各种各样的方法来保存Object
States，但是Java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。<br />
<br />
<strong>2、什么情况下需要序列化&nbsp;&nbsp;</strong>
<br />
&nbsp;&nbsp;&nbsp; a）当你想把的内存中的对象保存到一个文件中或者数据库中时候；<br />
&nbsp;&nbsp;&nbsp; b）当你想用套接字在网络上传送对象的时候；<br />
&nbsp;&nbsp;&nbsp;
c）当你想通过RMI传输对象的时候；<br />
<br />
<strong>3、当对一个对象实现序列化时，究竟发生了什么？</strong><br />
&nbsp;&nbsp;&nbsp;
在没有序列化前，每个保存在堆（Heap）中的对象都有相应的状态（state），即实例变量（instance ariable）比如：<br />
&nbsp;&nbsp;&nbsp;
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span>Foo&nbsp;&nbsp;myFoo&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Foo();&nbsp;&nbsp;</span></span>
    </li>
    <li class=""><span>myFoo&nbsp;.setWidth(<span class="number">37</span><span>);&nbsp;&nbsp;</span></span>
    </li>
    <li class="alt"><span>myFoo.**(<span class="number">70</span><span>);&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
当
通过下面的代码序列化之后，MyFoo对象中的width和Height实例变量的值（37，70）都被保存到foo.ser文件中，这样以后又可以把它
从文件中读出来，重新在堆中创建原来的对象。当然保存时候不仅仅是保存对象的实例变量的值，JVM还要保存一些小量信息，比如类的类型等以便恢复原来的对 象。<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span>FileOutputStream&nbsp;fs&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;FileOutputStream(</span><span class="string">"foo.ser"</span><span>);&nbsp;&nbsp;</span></span>
    </li>
    <li class=""><span>ObjectOutputStream&nbsp;os&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;ObjectOutputStream(fs);&nbsp;&nbsp;</span></span>
    </li>
    <li class="alt"><span>os.writeObject(myFoo);&nbsp;&nbsp;</span>
    </li>
</ol>
</div>
<br />
<strong>4、实现序列化（保存到一个文件）的步骤<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; </strong>a）Make a
FileOutputStream&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; <strong><span><strong>
</strong>
<div class="code_title"><strong><strong>java 代码</strong></strong></div>
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span><strong><strong>FileOutputStream&nbsp;fs&nbsp;=&nbsp;</strong></strong></span><span class="keyword"><strong><strong>new</strong></strong></span><span><strong><strong>&nbsp;FileOutputStream(</strong></strong></span><span class="string"><strong><strong>"foo.ser"</strong></strong></span><span><strong><strong>);&nbsp;&nbsp;&nbsp;&nbsp;</strong></strong></span></span><strong>
    </strong></li>
</ol>
</div>
<strong></strong></span></strong>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; b）Make a
ObjectOutputStream&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; <br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span>ObjectOutputStream&nbsp;os&nbsp;=&nbsp;&nbsp;</span><span class="keyword">new</span><span>&nbsp;ObjectOutputStream(fs);&nbsp;&nbsp;&nbsp;</span></span>
    </li>
</ol>
</div>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; c）write the object<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span>os.writeObject(myObject1);&nbsp;&nbsp;</span></span>
    </li>
    <li class=""><span>os.writeObject(myObject2);&nbsp;&nbsp;</span>
    </li>
    <li class="alt"><span>os.writeObject(myObject3);&nbsp;&nbsp;</span> </li>
</ol>
</div>
&nbsp;&nbsp;&nbsp; d)
close the ObjectOutputStream<br />
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span>os.close();&nbsp;&nbsp;</span></span>
    </li>
</ol>
</div>
<br />
<strong><br />
</strong><strong>5、举例说明<br />
</strong><strong>
</strong>
<div class="code_title"><strong><strong>java 代码</strong></strong></div>
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span class="keyword"><strong><strong>import</strong></strong></span><span><strong><strong>&nbsp;java.io.*;<br />
    </strong></strong></span></span>
    </li>
    <li class=""><span><strong><strong>&nbsp;&nbsp;</strong></strong></span><strong>
    </strong></li>
    <li class="alt"><span><span class="keyword"><strong><strong>public</strong></strong></span><span><strong><strong>&nbsp;</strong></strong></span><span class="keyword"><strong><strong>class</strong></strong></span><span><strong><strong>&nbsp;&nbsp;Box&nbsp;</strong></strong></span><span class="keyword"><strong><strong>implements</strong></strong></span><span><strong><strong>&nbsp;Serializable&nbsp;&nbsp;</strong></strong></span></span><strong>
    </strong></li>
    <li class=""><span><strong><strong>{&nbsp;&nbsp;</strong></strong></span><strong>
    </strong></li>
    <li class="alt"><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">private</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;width;&nbsp;&nbsp;</span></strong></strong></span><strong>
    </strong></li>
    <li class=""><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">private</span><span>&nbsp;</span><span class="keyword">int</span><span>&amp;nb**;&nbsp;&nbsp;</span></strong></strong></span><strong>
    </strong></li>
    <li class="alt"><span><strong><strong>&nbsp;&nbsp;</strong></strong></span><strong>
    </strong></li>
    <li class=""><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;setWidth(</span><span class="keyword">int</span><span>&nbsp;width){&nbsp;&nbsp;</span></strong></strong></span><strong>
    </strong></li>
    <li class="alt"><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">this</span><span>.width&nbsp;&nbsp;=&nbsp;width;&nbsp;&nbsp;</span></strong></strong></span><strong>
    </strong></li>
    <li class=""><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</strong></strong></span><strong>
    </strong></li>
    <li class="alt"><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;**(</span><span class="keyword">int</span><span>&amp;nb**){&nbsp;&nbsp;</span></strong></strong></span><strong>
    </strong></li>
    <li class=""><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">this</span><span>.height&nbsp;=&amp;nb**;&nbsp;&nbsp;</span></strong></strong></span><strong>
    </strong></li>
    <li class="alt"><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</strong></strong></span><strong>
    </strong></li>
    <li class=""><span><strong><strong>&nbsp;&nbsp;</strong></strong></span><strong>
    </strong></li>
    <li class="alt"><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args){&nbsp;&nbsp;</span></strong></strong></span><strong>
    </strong></li>
    <li class=""><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Box&nbsp;myBox&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;Box();&nbsp;&nbsp;</span></strong></strong></span><strong>
    </strong></li>
    <li class="alt"><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myBox.setWidth(<span class="number">50</span><span>);&nbsp;&nbsp;</span></strong></strong></span><strong>
    </strong></li>
    <li class=""><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myBox.**(<span class="number">30</span><span>);&nbsp;&nbsp;</span></strong></strong></span><strong>
    </strong></li>
    <li class="alt"><span><strong><strong>&nbsp;&nbsp;</strong></strong></span><strong>
    </strong></li>
    <li class=""><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">try</span><span>{&nbsp;&nbsp;</span></strong></strong></span><strong>
    </strong></li>
    <li class="alt"><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileOutputStream&nbsp;fs&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;FileOutputStream(</span><span class="string">"foo.ser"</span><span>);&nbsp;&nbsp;</span></strong></strong></span><strong>
    </strong></li>
    <li class=""><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ObjectOutputStream&nbsp;os&nbsp;=&nbsp;&nbsp;<span class="keyword">new</span><span>&nbsp;ObjectOutputStream(fs);&nbsp;&nbsp;</span></strong></strong></span><strong>
    </strong></li>
    <li class="alt"><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;os.writeObject(myBox);&nbsp;&nbsp;</strong></strong></span><strong>
    </strong></li>
    <li class=""><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;os.close();&nbsp;&nbsp;</strong></strong></span><strong>
    </strong></li>
    <li class="alt"><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span class="keyword">catch</span><span>(Exception&nbsp;ex){&nbsp;&nbsp;</span></strong></strong></span><strong>
    </strong></li>
    <li class=""><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ex.printStackTrace();&nbsp;&nbsp;</strong></strong></span><strong>
    </strong></li>
    <li class="alt"><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</strong></strong></span><strong>
    </strong></li>
    <li class=""><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</strong></strong></span><strong>
    </strong></li>
    <li class="alt"><span><strong><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</strong></strong></span><strong>
    </strong></li>
    <li class=""><span><strong><strong>}&nbsp;
    <br />
    </strong></strong></span></li>
</ol>
</div>
<br />
<strong>6、相关注意事项<br />
</strong>&nbsp;&nbsp;&nbsp;
a）当一个父类实现序列化，子类自动实现序列化，不需要显式实现Serializable接口；<br />
&nbsp;&nbsp;&nbsp;
b）当一个对象的实例变量引用其他对象，序列化该对象时也把引用对象进行序列化；<br />
&nbsp;&nbsp;&nbsp;
c）并非所有的对象都可以序列化，,至于为什么不可以，有很多原因了,比如：<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
1.安全方面的原因，比如一个对象拥有private，public等field，对于一个要传输的对象，比如写到文件，或者进行rmi传输&nbsp;
等等，在序列化进行传输的过程中，这个对象的private等域是不受保护的。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.
资源分配方面的原因，比如socket，thread类，如果可以序列化，进行传输或者保存，也无法对他们进行重新的资源分&nbsp; 配，而且，也是没有必要这样实现。
</div>
<img src ="http://www.blogjava.net/echo/aggbug/145467.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-09-16 09:49 <a href="http://www.blogjava.net/echo/archive/2007/09/16/145467.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Coding Guidelines for URL Rewriting</title><link>http://www.blogjava.net/echo/archive/2007/09/01/141894.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Sat, 01 Sep 2007 03:48:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/09/01/141894.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/141894.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/09/01/141894.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/141894.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/141894.html</trackback:ping><description><![CDATA[There are some general guidelines for how your code should handle URLs in order to support URL rewriting.
<ul type="square">
    <p><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="123247"></a></p>
    <li type="square">Avoid writing a URL straight to the output stream, as shown here:
    <blockquote>
    <pre><font color="#000000" face="Courier"><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="100778"></a>out.println("&lt;a href=\"/myshop/catalog.jsp\"&gt;catalog&lt;/a&gt;");</font></pre>
    </blockquote>
    <dl><dt>
    <p class="listpara"><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="100779"></a>Instead, use the <font class="code">HttpServletResponse.encodeURL()</font> method, for example:</p>
    <blockquote>
    <pre><font color="#000000" face="Courier"><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="100780"></a>out.println("&lt;a href=\""<br />
    + response.encodeURL("myshop/catalog.jsp") <br />
    + "\"&gt;catalog&lt;/a&gt;");</font></pre>
    </blockquote>
    </dt><dt>
    <p class="listpara"><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="100781"></a>Calling the <font class="code">encodeURL()</font>
    method determines if the URL needs to be rewritten, and if so, it
    rewrites it by including the session ID in the URL. The session ID is
    appended to the URL and begins with a semicolon.</p>
    </dt></dl>
    <p><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="100782"></a></p>
    </li>
    <li type="square">In addition to URLs that are returned as a response to WebLogic Server, also encode URLs that send redirects. For example:
    <blockquote>
    <pre><font color="#000000" face="Courier"><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="100783"></a>if (session.isNew())<br />
    &nbsp;&nbsp;response.sendRedirect (response.encodeRedirectUrl(welcomeURL));  </font></pre>
    </blockquote>
    <dl><dt>
    <p class="listpara"><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="100784"></a>WebLogic
    Server uses URL rewriting when a session is new, even if the browser
    does accept cookies, because the server cannot tell whether a browser
    accepts cookies in the first visit of a session. </p>
    </dt></dl>
    <p><a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&amp;file=anchor.gif);" name="109664"></a></p>
    </li>
    <li type="square">Your servlet can determine whether a given session ID was received from a cookie by checking the Boolean returned from the <strong><font class="code"><span style="color: red;">HttpServletRequest.isRequestedSessionIdFromCookie()</span></font></strong> method. Your application may respond appropriately, or simply rely on URL rewriting by WebLogic Server.
    </li>
</ul>
<img src ="http://www.blogjava.net/echo/aggbug/141894.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-09-01 11:48 <a href="http://www.blogjava.net/echo/archive/2007/09/01/141894.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Session详解 - (Z)</title><link>http://www.blogjava.net/echo/archive/2007/09/01/141891.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Sat, 01 Sep 2007 03:39:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/09/01/141891.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/141891.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/09/01/141891.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/141891.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/141891.html</trackback:ping><description><![CDATA[<p>目录：<br />
一、术语session<br />
二、HTTP协议与状态保持<br />
三、理解cookie机制<br />
四、理解session机制<br />
五、理解javax.servlet.http.HttpSession<br />
六、HttpSession常见问题<br />
七、跨应用程序的session共享<br />
八、总结<br />
参考文档</p>
<p>一、术语session<br />
在我的经验里，session这个词被滥用的程度大概仅次于transaction，更加有趣的是transaction与session在某些语境下的含义是相同的。</p>
<p>session，
中文经常翻译为会话，其本来的含义是指有始有终的一系列动作/消息，比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个
session。有时候我们可以看到这样的话&#8220;在一个浏览器会话期间，...&#8221;，这里的会话一词用的就是其本义，是指从一个浏览器窗口打开到关闭这个期间
①。最混乱的是&#8220;用户（客户端）在一次会话期间&#8221;这样一句话，它可能指用户的一系列动作（一般情况下是同某个具体目的相关的一系列动作，比如从登录到选购
商品到结账登出这样一个网上购物的过程，有时候也被称为一个transaction），然而有时候也可能仅仅是指一次连接，也有可能是指含义①，其中的差
别只能靠上下文来推断②。</p>
<p>然而当session一词与网络协议相关联时，它又往往隐含了&#8220;面向连接&#8221;和/或&#8220;保持状态&#8221;这样两个含义，
&#8220;面向连接&#8221;指的是在通信双方在通信之前要先建立一个通信的渠道，比如打电话，直到对方接了电话通信才能开始，与此相对的是写信，在你把信发出去的时候你
并不能确认对方的地址是否正确，通信渠道不一定能建立，但对发信人来说，通信已经开始了。&#8220;保持状态&#8221;则是指通信的一方能够把一系列的消息关联起来，使得
消息之间可以互相依赖，比如一个服务员能够认出再次光临的老顾客并且记得上次这个顾客还欠店里一块钱。这一类的例子有&#8220;一个TCP
session&#8221;或者 &#8220;一个POP3 session&#8221;③。</p>
<p>而到了web服务器蓬勃发展的时代，session在web开发语境下的语义
又有了新的扩展，它的含义是指一类用来在客户端与服务器之间保持状态的解决方案④。有时候session也用来指这种解决方案的存储结构，如&#8220;把xxx保
存在session
里&#8221;⑤。由于各种用于web开发的语言在一定程度上都提供了对这种解决方案的支持，所以在某种特定语言的语境下，session也被用来指代该语言的解决
方案，比如经常把Java里提供的javax.servlet.http.HttpSession简称为session⑥。</p>
<p>鉴于这种混乱已不可改变，本文中session一词的运用也会根据上下文有不同的含义，请大家注意分辨。<br />
在本文中，使用中文&#8220;浏览器会话期间&#8221;来表达含义①，使用&#8220;session机制&#8221;来表达含义④，使用&#8220;session&#8221;表达含义⑤，使用具体的&#8220;HttpSession&#8221;来表达含义⑥</p>
<p>二、HTTP协议与状态保持<br />
HTTP
协议本身是无状态的，这与HTTP协议本来的目的是相符的，客户端只需要简单的向服务器请求下载某些文件，无论是客户端还是服务器都没有必要纪录彼此过去
的行为，每一次请求之间都是独立的，好比一个顾客和一个自动售货机或者一个普通的（非会员制）大卖场之间的关系一样。</p>
<p>然而聪明（或者贪
心？）的人们很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用，就像给有线电视加上点播功能一样。这种需求一方面迫使HTML逐步添加
了表单、脚本、DOM等客户端行为，另一方面在服务器端则出现了CGI规范以响应客户端的动态请求，作为传输载体的HTTP协议也添加了文件上载、
cookie这些特性。其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的session机制则是又一种在客户端
与服务器之间保持状态的解决方案。</p>
<p>让我们用几个例子来描述一下cookie和session机制之间的区别与联系。笔者曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠，然而一次性消费5杯咖啡的机会微乎其微，这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案：<br />
1、该店的店员很厉害，能记住每位顾客的消费数量，只要顾客一走进咖啡店，店员就知道该怎么对待了。这种做法就是协议本身支持状态。<br />
2、发给顾客一张卡片，上面记录着消费的数量，一般还有个有效期限。每次消费时，如果顾客出示这张卡片，则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。<br />
3、发给顾客一张会员卡，除了卡号之外什么信息也不纪录，每次消费时，如果顾客出示该卡片，则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。</p>
<p>由
于HTTP协议是无状态的，而出于种种考虑也不希望使之成为有状态的，因此，后面两种方案就成为现实的选择。具体来说cookie机制采用的是在客户端保
持状态的方案，而session机制采用的是在服务器端保持状态的方案。同时我们也看到，由于采用服务器端保持状态的方案在客户端也需要保存一个标识，所
以session机制可能需要借助于cookie机制来达到保存标识的目的，但实际上它还有其他选择。</p>
<p>三、理解cookie机制 <br />
cookie机制的基本原理就如上面的例子一样简单，但是还有几个问题需要解决：&#8220;会员卡&#8221;如何分发；&#8220;会员卡&#8221;的内容；以及客户如何使用&#8220;会员卡&#8221;。</p>
<p>正统的cookie分发是通过扩展HTTP协议来实现的，服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie。然而纯粹的客户端脚本如JavaScript或者VBScript也可以生成cookie。</p>
<p>而cookie
的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie，如果某个cookie所声明的作用范围大于等于将要请求的
资源所在的位置，则把该cookie附在请求资源的HTTP请求头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示，如果某家分店还发行了自
己的会员卡，那么进这家店的时候除了要出示麦当劳的会员卡，还要出示这家店的会员卡。</p>
<p>cookie的内容主要包括：名字，值，过期时间，路径和域。<br />
其中域可以指定某一个域比如.google.com，相当于总店招牌，比如宝洁公司，也可以指定一个域下的具体某台机器比如<a href="http://www.google.com/">www.google.com</a>或者froogle.google.com，可以用飘柔来做比。<br />
路径就是跟在域名后面的URL路径，比如/或者/foo等等，可以用某飘柔专柜做比。<br />
<span style="color: red;">
<p>路径与域合在一起就构成了cookie的作用范围。<br />
如
果不设置过期时间，则表示这个cookie的生命期为浏览器会话期间，只要关闭浏览器窗口，cookie就消失了。这种生命期为浏览器会话期的
cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里，当然这种行为并不是规范规定的。如果设置了过期时间，浏览器
就会把cookie保存到硬盘上，关闭后再次打开浏览器，这些cookie仍然有效直到超过设定的过期时间。</p>
<p>存储在硬盘上的cookie
可以在不同的浏览器进程间共享，比如两个IE窗口。而对于保存在内存里的cookie，不同的浏览器有不同的处理方式。对于IE，在一个打开的窗口上按
Ctrl-N（或者从文件菜单）打开的窗口可以与原窗口共享，而使用其他方式新开的IE进程则不能共享已经打开的窗口的内存cookie；对于
Mozilla
Firefox0.8，所有的进程和标签页都可以共享同样的cookie。一般来说是用javascript的window.open打开的窗口会与原窗
口共享内存cookie。浏览器对于会话cookie的这种只认cookie不认人的处理方式经常给采用session机制的web应用程序开发者造成很
大的困扰。</p>
</span></p>
<p>&nbsp;</p>
<p>下面就是一个goolge设置cookie的响应头的例子<br />
HTTP/1.1 302 Found<br />
Location: <a href="http://www.google.com/intl/zh-CN/">http://www.google.com/intl/zh-CN/</a><br />
Set-Cookie:
PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8;
expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com<br />
Content-Type: text/html</p>
<p>这是使用HTTPLook这个HTTP Sniffer软件来俘获的HTTP通讯纪录的一部分<br />
浏览器在再次访问goolge的资源时自动向外发送cookie<br />
使用Firefox可以很容易的观察现有的cookie的值<br />
使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。<br />
IE也可以设置在接受cookie前询问<br />
这是一个询问接受cookie的对话框。</p>
<p>四、理解session机制<br />
session机制是一种服务器端的机制，服务器使用一种类似于散列表的结构（也可能就是使用散列表）来保存信息。</p>
<p><span style="color: red;">当
程序需要为某个客户端的请求创建一个session的时候，服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为
session id，如果已包含一个session id则说明以前已经为此客户端创建过session，服务器就按照session id把这个
session检索出来使用（如果检索不到，可能会新建一个），如果客户端请求不包含session
id，则为此客户端创建一个session并且生成一个与此session相关联的session id，session
id的值应该是一个既不会重复，又不容易被找到规律以仿造的字符串，这个 session id将被在本次响应中返回给客户端保存。</span></p>
<p>保存这
个session
id的方式可以采用cookie，这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于
SEEESIONID，而。比如weblogic对于web应用程序生成的cookie，JSESSIONID=
ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764，它的名字就是
JSESSIONID。</p>
<p>由于cookie可以被人为的禁止，必须有其他机制以便在cookie被禁止时仍然能够把session
id传递回服务器。经常被使用的一种技术叫做URL重写，就是把session
id直接附加在URL路径的后面，附加方式也有两种，一种是作为URL路径的附加信息，表现形式为<a href="http://...../xxx;jsessionid">http://...../xxx;jsessionid</a>= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764<br />
另一种是作为查询字符串附加在URL后面，表现形式为<a href="http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng%21-145788764">http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764</a><br />
这两种方式对于用户来说是没有区别的，只是服务器在解析的时候处理的方式不同，采用第一种方式也有利于把session id的信息和正常程序参数区分开来。<br />
为了在整个交互过程中始终保持状态，就必须在每个客户端可能请求的路径后面都包含这个session id。</p>
<p>另一种技术叫做表单隐藏字段。就是服务器会自动修改表单，添加一个隐藏字段，以便在表单提交时能够把session id传递回服务器。比如下面的表单<br />
&lt;form name="testform" action="/xxx"&gt;<br />
&lt;input type="text"&gt;<br />
&lt;/form&gt;<br />
在被传递给客户端之前将被改写成<br />
&lt;form name="testform" action="/xxx"&gt;<br />
&lt;input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764"&gt;<br />
&lt;input type="text"&gt;<br />
&lt;/form&gt;<br />
这种技术现在已较少应用，笔者接触过的很古老的iPlanet6(SunONE应用服务器的前身)就使用了这种技术。<br />
实际上这种技术可以简单的用对action应用URL重写来代替。</p>
<p><span style="color: red;">在
谈论session机制的时候，常常听到这样一种误解&#8220;只要关闭浏览器，session就消失了&#8221;。其实可以想象一下会员卡的例子，除非顾客主动对店家提
出销卡，否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的，除非程序通知服务器删除一个session，否则服务器会一直保留，程序
一般都是在用户做log
off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭，因此服务器根本不会有机会知道浏览器已经关闭，之所
以会有这种错觉，是<strong><span style="color: #0040ff;">大部分session机制都使用会话cookie来保存session id，而关闭浏览器后这个 session
id就消失了，再次连接服务器时也就无法找到原来的session。</span></strong>如果服务器设置的cookie被保存到硬盘上，或者使用某种手段改写浏览器发出的
HTTP请求头，把原来的session id发送给服务器，则再次打开浏览器仍然能够找到原来的session。</span></p>
<p>恰恰是由于关闭浏览器不会导致session被删除，迫使服务器为seesion设置了一个失效时间，当距离客户端上一次使用session的时间超过这个失效时间时，服务器就可以认为客户端已经停止了活动，才会把session删除以节省存储空间。</p>
<p>五、理解javax.servlet.http.HttpSession<br />
HttpSession是Java平台对session机制的实现规范，因为它仅仅是个接口，具体到每个web应用服务器的提供商，除了对规范支持之外，仍然会有一些规范里没有规定的细微差异。这里我们以BEA的Weblogic Server8.1作为例子来演示。</p>
<p>首
先，Weblogic
Server提供了一系列的参数来控制它的HttpSession的实现，包括使用cookie的开关选项，使用URL重写的开关选项，session持
久化的设置，session失效时间的设置，以及针对cookie的各种设置，比如设置cookie的名字、路径、域， cookie的生存时间等。</p>
<p>一
般情况下，session都是存储在内存里，当服务器进程被停止或者重启的时候，内存里的session也会被清空，如果设置了session的持久化特
性，服务器就会把session保存到硬盘上，当服务器进程重新启动或这些信息将能够被再次使用， Weblogic
Server支持的持久性方式包括文件、数据库、客户端cookie保存和复制。</p>
<p>复制严格说来不算持久化保存，因为session实际上还是保存在内存里，不过同样的信息被复制到各个cluster内的服务器进程中，这样即使某个服务器进程停止工作也仍然可以从其他进程中取得session。</p>
<p>cookie生存时间的设置则会影响浏览器生成的cookie是否是一个会话cookie。默认是使用会话cookie。有兴趣的可以用它来试验我们在第四节里提到的那个误解。</p>
<p>cookie的路径对于web应用程序来说是一个非常重要的选项，Weblogic Server对这个选项的默认处理方式使得它与其他服务器有明显的区别。后面我们会专题讨论。</p>
<p>关于session的设置参考[5] <a href="http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869">http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869</a></p>
<p>六、HttpSession常见问题<br />
（在本小节中session的含义为⑤和⑥的混合）</p>
<p><br />
1、session在何时被创建<br />
一
个常见的误解是以为session在有客户端访问时就被创建，然而事实是直到某server端程序调用
HttpServletRequest.getSession(true)这样的语句时才被创建，注意如果JSP没有显示的使用 &lt;%
@page session="false"%&gt; 关闭session，则JSP文件在编译成Servlet时将会自动加上这样一条语句
HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的
session对象的来历。</p>
<p>由于session会消耗内存资源，因此，如果不打算使用session，应该在所有的JSP中关闭它。</p>
<p>2、session何时被删除<br />
综合前面的讨论，session在下列情况下被删除a.程序调用HttpSession.invalidate();或b.距离上一次收到客户端发送的session id时间间隔超过了session的超时设置;或c.服务器进程被停止（非持久session）</p>
<p>3、如何做到在浏览器关闭时删除session<br />
严格的讲，做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作，然后向服务器发送一个请求来删除session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。</p>
<p><span style="color: #ff0000;">
<p>4、有个HttpSessionListener是怎么回事<br />
你
可以创建这样的listener去监控session的创建和销毁事件，使得在发生这样的事件时你可以做一些相应的工作。注意是session的创建和销
毁动作触发listener，而不是相反。类似的与HttpSession有关的listener还有
HttpSessionBindingListener，HttpSessionActivationListener和
HttpSessionAttributeListener。</p>
<p>5</p>
</span></p>
<p>、存放在session中的对象必须是可序列化的吗<br />
不是必需的。要
求对象可序列化只是为了session能够在集群中被复制或者能够持久保存或者在必要时server能够暂时把session交换出内存。在
Weblogic Server的session中放置一个不可序列化的对象在控制台上会收到一个警告。我所用过的某个iPlanet版本如果
session中有不可序列化的对象，在session销毁时会有一个Exception，很奇怪。</p>
<p>6、如何才能正确的应付客户端禁止cookie的可能性<br />
对所有的URL使用URL重写，包括超链接，form的action，和重定向的URL，具体做法参见[6]<br />
<a href="http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770">http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770</a></p>
<p>7、开两个浏览器窗口访问应用程序会使用同一个session还是不同的session<br />
参见第三小节对cookie的讨论，对session来说是只认id不认人，因此不同的浏览器，不同的窗口打开方式以及不同的cookie存储方式都会对这个问题的答案有影响。</p>
<p>8、如何防止用户打开两个浏览器窗口操作导致的session混乱<br />
这
个问题与防止表单多次提交是类似的，可以通过设置客户端的令牌来解决。就是在服务器每次生成一个不同的id返回给客户端，同时保存在session里，客
户端提交表单时必须把这个id也返回服务器，程序首先比较返回的id与保存在session里的值是否一致，如果不一致则说明本次操作已经被提交过了。可
以参看《J2EE核心模式》关于表示层模式的部分。需要注意的是对于使用javascript
window.open打开的窗口，一般不设置这个id，或者使用单独的id，以防主窗口无法操作，建议不要再window.open打开的窗口里做修改
操作，这样就可以不用设置。</p>
<p>9、为什么在Weblogic Server中改变session的值后要重新调用一次session.setValue<br />
做这个动作主要是为了在集群环境中提示Weblogic Server session中的值发生了改变，需要向其他服务器进程复制新的session值。</p>
<p>10、为什么session不见了<br />
排
除session正常失效的因素之外，服务器本身的可能性应该是微乎其微的，虽然笔者在iPlanet6SP1加若干补丁的Solaris版本上倒也遇到
过；浏览器插件的可能性次之，笔者也遇到过3721插件造成的问题；理论上防火墙或者代理服务器在cookie处理上也有可能会出现问题。<br />
出现这一问题的大部分原因都是程序的错误，最常见的就是在一个应用程序中去访问另外一个应用程序。我们在下一节讨论这个问题。</p>
<p>七、跨应用程序的session共享</p>
<p>常
常有这样的情况，一个大项目被分割成若干小项目开发，为了能够互不干扰，要求每个小项目作为一个单独的web应用程序开发，可是到了最后突然发现某几个小
项目之间需要共享一些信息，或者想使用session来实现SSO(single sign
on)，在session中保存login的用户信息，最自然的要求是应用程序间能够访问彼此的session。</p>
<p>然而按照Servlet规
范，session的作用范围应该仅仅限于当前应用程序下，不同的应用程序之间是不能够互相访问对方的session的。各个应用服务器从实际效果上都遵
守了这一规范，但是实现的细节却可能各有不同，因此解决跨应用程序session共享的方法也各不相同。</p>
<p>首先来看一下Tomcat是如何实
现web应用程序之间session的隔离的，从
Tomcat设置的cookie路径来看，它对不同的应用程序设置的cookie路径是不同的，这样不同的应用程序所用的session
id是不同的，因此即使在同一个浏览器窗口里访问不同的应用程序，发送给服务器的session id也可以是不同的。</p>
<p>根据这个特性，我们可以推测Tomcat中session的内存结构大致如下。</p>
<p>笔
者以前用过的iPlanet也采用的是同样的方式，估计SunONE与iPlanet之间不会有太大的差别。对于这种方式的服务器，解决的思路很简单，实
际实行起来也不难。要么让所有的应用程序共享一个session id，要么让应用程序能够获得其他应用程序的session id。</p>
<p>iPlanet中有一种很简单的方法来实现共享一个session id，那就是把各个应用程序的cookie路径都设为/（实际上应该是/NASApp，对于应用程序来讲它的作用相当于根）。<br />
&lt;session-info&gt;<br />
&lt;path&gt;/NASApp&lt;/path&gt;<br />
&lt;/session-info&gt;</p>
<p>需
要注意的是，操作共享的session应该遵循一些编程约定，比如在session attribute名字的前面加上应用程序的前缀，使得
setAttribute("name", "neo")变成setAttribute("app1.name",
"neo")，以防止命名空间冲突，导致互相覆盖。</p>
<p><br />
在Tomcat中则没有这么方便的选择。在Tomcat版本3上，我们还可以有
一些手段来共享session。对于版本4以上的Tomcat，目前笔者尚未发现简单的办法。只能借助于第三方的力量，比如使用文件、数据库、JMS或者
客户端cookie，URL参数或者隐藏字段等手段。</p>
<p>我们再看一下Weblogic Server是如何处理session的。</p>
<p>从
截屏画面上可以看到Weblogic Server对所有的应用程序设置的cookie的路径都是/，这是不是意味着在Weblogic
Server中默认的就可以共享session了呢？然而一个小实验即可证明即使不同的应用程序使用的是同一个session，各个应用程序仍然只能访问
自己所设置的那些属性。这说明Weblogic Server中的session的内存结构可能如下</p>
<p>对于这样一种结构，在
session机制本身上来解决session共享的问题应该是不可能的了。除了借助于第三方的力量，比如使用文件、数据库、JMS或者客户端
cookie，URL参数或者隐藏字段等手段，还有一种较为方便的做法，就是把一个应用程序的session放到ServletContext中，这样另
外一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下，</p>
<p>应用程序A<br />
context.setAttribute("appA", session); </p>
<p>应用程序B<br />
contextA = context.getContext("/appA");<br />
HttpSession sessionA = (HttpSession)contextA.getAttribute("appA"); </p>
<p>值得注意的是这种用法不可移植，因为根据ServletContext的JavaDoc，应用服务器可以处于安全的原因对于context.getContext("/appA");返回空值，以上做法在Weblogic Server 8.1中通过。</p>
<p>那
么Weblogic
Server为什么要把所有的应用程序的cookie路径都设为/呢？原来是为了SSO，凡是共享这个session的应用程序都可以共享认证的信息。一
个简单的实验就可以证明这一点，修改首先登录的那个应用程序的描述符weblogic.xml，把cookie路径修改为/appA
访问另外一个应用程序会重新要求登录，即使是反过来，先访问cookie路径为/的应用程序，再访问修改过路径的这个，虽然不再提示登录，但是登录的用户
信息也会丢失。注意做这个实验时认证方式应该使用FORM，因为浏览器和web服务器对basic认证方式有其他的处理方式，第二次请求的认证不是通过
session来实现的。具体请参看[7] secion 14.8 Authorization，你可以修改所附的示例程序来做这些试验。</p>
八、总结<br />
session机制本身并不复杂，然而其实现和配置上的灵活性却使得具体情况复杂多变。这也要求我们不能把仅仅某一次的经验或者某一个浏览器，服务器的经验当作普遍适用的经验，而是始终需要具体情况具体分析。
<img src ="http://www.blogjava.net/echo/aggbug/141891.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-09-01 11:39 <a href="http://www.blogjava.net/echo/archive/2007/09/01/141891.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HTTPLook - 一个HTTP的嗅探器</title><link>http://www.blogjava.net/echo/archive/2007/09/01/141888.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Sat, 01 Sep 2007 03:30:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/09/01/141888.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/141888.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/09/01/141888.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/141888.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/141888.html</trackback:ping><description><![CDATA[<p><font face="Georgia">HTTPLook 是一个 HTTP 的嗅探器，它能捕捉本机与其它任何主机的 HTTP 通讯（不是 HTTPS 哦 <img alt="吐舌笑脸" src="http://messenger.china.msn.com/Resource/emoticons/tongue_smile.gif" />），
然后显示详细的 HTTP 操作（如 GET/POST）、访问资源的 URL 、字节数大小等，这个软件简单易用，不用对 Internet
Explorer 做任何其它设置（有的软件通过在 IE 中设置代理来监控数据），也不需要其它任何软件的支持，是一款较为绿色的、轻量级的软件。</font></p>
<p><font face="Georgia">HTTPLook 的应用场景：</font></p>
<p><strong><font face="Georgia">1、程序开发及调试</font></strong></p>
<p><font face="Georgia">在 CGI、ASP/PHP/JSP、ASP.NET、Web Service 的开发中，经常要查看 GET 或 POST 的数据是否正确，用这个工具能很好地协助完成此工作。</font></p>
<p><strong><font face="Georgia">2、复杂页面分析</font></strong></p>
<p><font face="Georgia">上网有时会碰到的很复杂的页面，查看源码也不能了解它的工作原理，这一般是作者为了保护 Web
在页面而加上了一些保护机制（如使用 Frame/IFrame、捕捉键盘或 Mouse 事件、使用 Script 来访问资源等），使用
HTTPLook 有助于对此页面进行分析，进而破解其保护机制。</font></p>
<p><font face="Georgia">比较典型的一个例子就是 SharePoint Team Services 中使用了
WebBot ，查看源码根本不知道它调用了那些 ASP/Script/CSS 文件，但使用 HTTPLook
之后，一目了然，非常有效，可以据此来自定义原有页面风格，如色彩，字体等。</font></p>
<p><strong><font face="Georgia">3、获得被保护的 Web 资源</font></strong></p>
<p><font face="Georgia">在很多网站上，尤其是 Microsoft 的网站上，经常见到一些制做精美的 Flash
，但是由于 Flash 不是一个单一文件，而是在最先启动的 FLASH 中再调用其它 Flash 资源文件，由于无法获得这些文件的 URL
，所以下载到本地，但如果使用 HTTPLook
，通过对整个播放过程的监视，就可以完全侦测出所有在程序中访问的资源的地址，进而保存到本地，可以离线浏览。当然也可以保存其它资源，如图片等。</font></p>
<p><strong><font face="Georgia">4、学习 HTTP 协议</font></strong></p>
<p><font face="Georgia">可以详细地了解 HTTP 通讯的细节，如 GET/POST、User-Agent、Cookie、Proxy 设置及验证、HTTP 协议出错代码及意义等。</font></p>
<img src ="http://www.blogjava.net/echo/aggbug/141888.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-09-01 11:30 <a href="http://www.blogjava.net/echo/archive/2007/09/01/141888.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>############################# Java - 需要学习的知识 ##########################################</title><link>http://www.blogjava.net/echo/archive/2007/08/30/141557.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Thu, 30 Aug 2007 15:16:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/08/30/141557.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/141557.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/08/30/141557.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/141557.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/141557.html</trackback:ping><description><![CDATA[<strong><span style="color: red;">精通java的必要条件：</span></strong><br />
<span style="color: red;">
1、当然要对java语法和语义有相当的理解及纯熟的应用，比方说对继承体系中的对象的比较复杂初始化顺序的清晰把握，对内部类和无名内部类的理解和使用时机的把握，对反射和序列化机制的掌握，等等，等等；<br />
2、对虚拟机的内部运作机理、垃圾收集机制及其算法的理解；<br />
3、java是一门oo语言，精通java意味着你必需精通面向对象的编程；<br />
4、对java&nbsp;core&nbsp;api的掌握，最起码，对java.lang、java.io、java.nio、java.math、java.util、
java.net、java.sql、javax.sql、java.lang.reflect等包的目的、类层次结构、大多数类的作用与用法、包中的类
与类之间的静态结构和动态交互等内容要深入掌握，如果你要编写GUI程序，那还要加上javax.swing包；<br />
到这里了，大约可以说你精通了java的基本了。然而，在中国，所谓精通java往往意味着对j2ee的掌握，那么，下面还有：<br />
5、对j2ee体系结构的宏观把握；<br />
6、掌握java.rmi、javax.rmi、javax.naming、javax.mail等包；<br />
7、对servlet的掌握，包括servlet规范，servlet容器，javax.servlet、javax.servlet.http包的api<br />
8、对jsp的掌握，包括jsp与servlet的转换关系，jsp的指令和action，el语言，jstl；<br />
9、对ejb的掌握，包括ejb的规范与实现，ejb的部署，javax.ejb包的api，以及ejb的有效运用，ejb陷阱与缺陷的避免；<br />
10、对java安全的平台与api的掌握；<br />
11、java的开源力量不可轻视，利用得好，可以极大地增强你的开发效率，这方面太广，我也只能随便说说。一个MVC框架，struts或
webwork；一个O/R工具，如hiberate或一个jdo的实现；一个测试框架，如junit；一个发布工具，如ant；还有诸如全文检索工具
Lucene，jsp页面布局工具Tiles，spring框架，等等<br />
&nbsp;&nbsp;</span>&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;  <br />
&nbsp;&nbsp;&nbsp; <span style="color: rgb(111, 120, 48);">你需要精通面向对象分析与设计(OOA/OOD)、涉及模式(GOF,J2EEDP)以及综合模式.你应该十分了解UML,尤其是class,object,interaction以及statediagrams.<br />
<br />
你需要学习JAVA语言的基础知识以及它的核心类库(collections,serialization,streams,networking,multithreading,reflection,event,handling,NIO,localization,以及其他).<br />
<br />
你应该了解JVM,classloaders,classreflect,以及垃圾回收的基本工作机制等.你应该有能力反编译一个类文件并且明白一些基本的汇编指令.<br />
<br />
如果你将要写客户端程序,你需要学习WEB的小应用程序(applet),必需掌握GUI设计的思想和方法,以及桌面程序的SWING,AWT,SWT.你还应该对UI部件的JAVABEAN组件模式有所了解.JAVABEANS也被应用在JSP中以把业务逻辑从表现层中分离出来.<br />
<br />
你需要学习java数据库技术,如JDBCAPI并且会使用至少一种persistence/ORM构架,例如Hibernate,JDO,CocoBase,TopLink,InsideLiberator(国产JDO红工厂软件)或者iBatis.你还应该了解对象关系的阻抗失配的含义,以及它是如何影响业务对象的与关系型数据库的交互,和它的运行结果,还需要掌握不同的数据库产品运用,比如:oracle,mysql,mssqlserver.<br />
<br />
你需要学习JAVA的沙盒安全模式(classloaders,bytecodeverification,managers,policyandpermissions,<br />
codesigning,digitalsignatures,cryptography,certification,Kerberos,以及其他)还有不同的安全/认证API,例如JAAS(JavaAuthenticationandAuthorizationService),JCE(JavaCryptographyExtension),JSSE(JavaSecureSocketExtension),以及JGSS(JavaGeneralSecurityService).<br />
<br />
你需要学习Servlets,JSP,以及JSTL(StandardTagLibraries)和可以选择的第三方TagLibraries.<br />
<br />
你需要熟悉主流的网页框架,例如JSF,Struts,Tapestry,Cocoon,WebWork,以及他们下面的涉及模式,如MVC/MODEL2.<br />
<br />
你需要学习如何使用及管理WEB服务器,例如tomcat,resin,Jrun,并且知道如何在其基础上扩展和维护WEB程序.<br />
<br />
你需要学习分布式对象以及远程API,例如RMI和RMI/IIOP.<br />
<br />
你需要掌握各种流行中间件技术标准和与java结合实现,比如Tuxedo、CROBA,当然也包括javaEE本身.<br />
<br />
你需要学习最少一种的XMLAPI,例如JAXP(JavaAPIforXMLProcessing),JDOM(JavaforXMLDocumentObjectModel),DOM4J,或JAXR(JavaAPIforXMLRegistries).<br />
<br />
你应该学习如何利用JAVAAPI和工具来构建WebService.例如JAX-RPC(JavaAPIforXML/RPC),SAAJ(SOAPwithAttachmentsAPIforJava),JAXB(JavaArchitectureforXMLBinding),JAXM(JavaAPIforXMLMessaging),JAXR(JavaAPIforXMLRegistries),或者JWSDP(JavaWebServicesDeveloperPack).<br />
<br />
你需要学习一门轻量级应用程序框架,例如Spring,PicoContainer,Avalon,以及它们的IoC/DI风格(setter,constructor,interfaceinjection).<br />
<br />
你需要熟悉不同的J2EE技术,例如JNDI(JavaNamingandDirectoryInterface),JMS(JavaMessageService),JTA/JTS(JavaTransactionAPI/JavaTransactionService),JMX(JavaManagementeXtensions),以及JavaMail.<br />
<br />
你需要学习企业级JavaBeans(EJB)以及它们的不同组件模式：Stateless/StatefulSessionBeans,EntityBeans(包含Bean-ManagedPersistence[BMP]或者Container-ManagedPersistence[CMP]和它的EJB-QL),或者Message-DrivenBeans(MDB).<br />
<br />
你需要学习如何管理与配置一个J2EE应用程序服务器,如WebLogic,JBoss等,并且利用它的附加服务,例如簇类,连接池以及分布式处理支援.你还需要了解如何在它上面封装和配置应用程序并且能够监控、调整它的性能.<br />
<br />
你需要熟悉面向方面的程序设计以及面向属性的程序设计(这两个都被很容易混淆的缩写为AOP),以及他们的主流JAVA规格和执行.例如AspectJ和AspectWerkz.<br />
<br />
你需要熟悉对不同有用的API和framework等来为你服务.例如Log4J(logging/tracing),Quartz(scheduling),JGroups(networkgroupcommunication),JCache(distributedcaching),Lucene(full-textsearch),JakartaCommons等等.<br />
<br />
如果你将要对接或者正和旧的系统或者本地平台,你需要学习JNI(JavaNativeInterface)andJCA(JavaConnectorArchitecture).<br />
<br />
你需要熟悉JINI技术以及与它相关的分布式系统,比如掌握CROBA.<br />
<br />
你需要JavaCommunityProcess(JCP)以及他的不同JavaSpecificationRequests(JSRs),例如Portlets(168),JOLAP(69),DataMiningAPI(73),等等.<br />
<br />
你应该熟练掌握一种JAVAIDE例如sunOne,netBeans,IntelliJIDEA或者Eclipse.(有些人更喜欢VI或EMACS来编写文件.随便你用什么了：))<br />
<br />
JAVA(精确的说是有些配置)是冗长的,它需要很多的人工代码(例如EJB),所以你需要熟悉代码生成工具,例如XDoclet.<br />
<br />
你需要熟悉一种单元测试体系(JNunit),并且学习不同的生成、部署工具(Ant,Maven).<br />
<br />
你需要熟悉一些在JAVA开发中经常用到的软件工程过程.例如RUP(RationalUnifiedProcess)andAgilemethodologies.<br />
<br />
你需要能够深入了解加熟练操作和配置不同的操作系统,比如GNU/linux,sunsolaris,macOS等,做为跨平台软件的开发者.<br />
<br />
你还需要紧跟java发展的步伐,比如现在可以深入的学习javaME,以及各种java新规范,技术的运用,如新起的web富客户端技术.<br />
<br />
你必需要对opensource有所了解,因为至少java的很多技术直接是靠开源来驱动发展的,如java3D技术.</span><br />
<img src ="http://www.blogjava.net/echo/aggbug/141557.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-08-30 23:16 <a href="http://www.blogjava.net/echo/archive/2007/08/30/141557.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA反射机制</title><link>http://www.blogjava.net/echo/archive/2007/08/30/141131.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Wed, 29 Aug 2007 16:24:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/08/30/141131.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/141131.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/08/30/141131.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/141131.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/141131.html</trackback:ping><description><![CDATA[JAVA反射机制<br>&nbsp;&nbsp;&nbsp;&nbsp;JAVA反射机制是在运行状态中，对于任意一个类，都能够知道这个类的所有属性和方法；对于任意一个对象，都能够调用它的任意一个方法；这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。<br>Java反射机制主要提供了以下功能：&nbsp;在运行时判断任意一个对象所属的类；在运行时构造任意一个类的对象；在运行时判断任意一个类所具有的成员变量和方法；在运行时调用任意一个对象的方法；生成动态代理。<br>1.&nbsp;得到某个对象的属性<br><br>1&nbsp;public&nbsp;Object&nbsp;getProperty(Object&nbsp;owner,&nbsp;String&nbsp;fieldName)&nbsp;throws&nbsp;Exception&nbsp;{<br>2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;ownerClass&nbsp;=&nbsp;owner.getClass();<br>3&nbsp;<br>4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Field&nbsp;field&nbsp;=&nbsp;ownerClass.getField(fieldName);<br>5&nbsp;<br>6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;property&nbsp;=&nbsp;field.get(owner);<br>7&nbsp;<br>8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;property;<br>9&nbsp;}<br>Class&nbsp;ownerClass&nbsp;=&nbsp;owner.getClass()：得到该对象的Class。<br><br>Field&nbsp;field&nbsp;=&nbsp;ownerClass.getField(fieldName)：通过Class得到类声明的属性。<br><br>Object&nbsp;property&nbsp;=&nbsp;field.get(owner)：通过对象得到该属性的实例，如果这个属性是非公有的，这里会报IllegalAccessException。<br><br>2.&nbsp;得到某个类的静态属性<br><br>&nbsp;1&nbsp;public&nbsp;Object&nbsp;getStaticProperty(String&nbsp;className,&nbsp;String&nbsp;fieldName)<br>&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws&nbsp;Exception&nbsp;{<br>&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;ownerClass&nbsp;=&nbsp;Class.forName(className);<br>&nbsp;4&nbsp;<br>&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Field&nbsp;field&nbsp;=&nbsp;ownerClass.getField(fieldName);<br>&nbsp;6&nbsp;<br>&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;property&nbsp;=&nbsp;field.get(ownerClass);<br>&nbsp;8&nbsp;<br>&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;property;<br>10&nbsp;}<br><br>Class&nbsp;ownerClass&nbsp;=&nbsp;Class.forName(className)&nbsp;：首先得到这个类的Class。<br><br>Field&nbsp;field&nbsp;=&nbsp;ownerClass.getField(fieldName)：和上面一样，通过Class得到类声明的属性。<br><br>Object&nbsp;property&nbsp;=&nbsp;field.get(ownerClass)&nbsp;：这里和上面有些不同，因为该属性是静态的，所以直接从类的Class里取。<br><br>3.&nbsp;执行某对象的方法<br><br>&nbsp;1&nbsp;public&nbsp;Object&nbsp;invokeMethod(Object&nbsp;owner,&nbsp;String&nbsp;methodName,&nbsp;Object[]&nbsp;args)&nbsp;throws&nbsp;Exception&nbsp;{<br>&nbsp;2&nbsp;<br>&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;ownerClass&nbsp;=&nbsp;owner.getClass();<br>&nbsp;4&nbsp;<br>&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class[]&nbsp;argsClass&nbsp;=&nbsp;new&nbsp;Class[args.length];<br>&nbsp;6&nbsp;<br>&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0,&nbsp;j&nbsp;=&nbsp;args.length;&nbsp;i&nbsp;&lt;&nbsp;j;&nbsp;i++)&nbsp;{<br>&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;argsClass[i]&nbsp;=&nbsp;args[i].getClass();<br>&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>10&nbsp;<br>11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Method&nbsp;method&nbsp;=&nbsp;ownerClass.getMethod(methodName,&nbsp;argsClass);<br>12&nbsp;<br>13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;method.invoke(owner,&nbsp;args);<br>14&nbsp;}<br>Class&nbsp;owner_class&nbsp;=&nbsp;owner.getClass()&nbsp;：首先还是必须得到这个对象的Class。<br><br>5～9行：配置参数的Class数组，作为寻找Method的条件。<br><br>Method&nbsp;method&nbsp;=&nbsp;ownerClass.getMethod(methodName,&nbsp;argsClass)：通过Method名和参数的Class数组得到要执行的Method。<br><br>method.invoke(owner,&nbsp;args)：执行该Method，invoke方法的参数是执行这个方法的对象，和参数数组。返回值是Object，也既是该方法的返回值。<br><br>4.&nbsp;执行某个类的静态方法<br><br>&nbsp;1&nbsp;public&nbsp;Object&nbsp;invokeStaticMethod(String&nbsp;className,&nbsp;String&nbsp;methodName,<br>&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object[]&nbsp;args)&nbsp;throws&nbsp;Exception&nbsp;{<br>&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;ownerClass&nbsp;=&nbsp;Class.forName(className);<br>&nbsp;4&nbsp;<br>&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class[]&nbsp;argsClass&nbsp;=&nbsp;new&nbsp;Class[args.length];<br>&nbsp;6&nbsp;<br>&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0,&nbsp;j&nbsp;=&nbsp;args.length;&nbsp;i&nbsp;&lt;&nbsp;j;&nbsp;i++)&nbsp;{<br>&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;argsClass[i]&nbsp;=&nbsp;args[i].getClass();<br>&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>10&nbsp;<br>11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Method&nbsp;method&nbsp;=&nbsp;ownerClass.getMethod(methodName,&nbsp;argsClass);<br>12&nbsp;<br>13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;method.invoke(null,&nbsp;args);<br>14&nbsp;}<br><br>基本的原理和实例3相同，不同点是最后一行，invoke的一个参数是null，因为这是静态方法，不需要借助实例运行。<br><br>5.&nbsp;新建实例<br>&nbsp;1&nbsp;<br>&nbsp;2&nbsp;public&nbsp;Object&nbsp;newInstance(String&nbsp;className,&nbsp;Object[]&nbsp;args)&nbsp;throws&nbsp;Exception&nbsp;{<br>&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;newoneClass&nbsp;=&nbsp;Class.forName(className);<br>&nbsp;4&nbsp;<br>&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class[]&nbsp;argsClass&nbsp;=&nbsp;new&nbsp;Class[args.length];<br>&nbsp;6&nbsp;<br>&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0,&nbsp;j&nbsp;=&nbsp;args.length;&nbsp;i&nbsp;&lt;&nbsp;j;&nbsp;i++)&nbsp;{<br>&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;argsClass[i]&nbsp;=&nbsp;args[i].getClass();<br>&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>10&nbsp;<br>11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Constructor&nbsp;cons&nbsp;=&nbsp;newoneClass.getConstructor(argsClass);<br>12&nbsp;<br>13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;cons.newInstance(args);<br>14&nbsp;<br>15&nbsp;}<br><br>这里说的方法是执行带参数的构造函数来新建实例的方法。如果不需要参数，可以直接使用newoneClass.newInstance()来实现。<br><br>Class&nbsp;newoneClass&nbsp;=&nbsp;Class.forName(className)：第一步，得到要构造的实例的Class。<br><br>第5～第9行：得到参数的Class数组。<br><br>Constructor&nbsp;cons&nbsp;=&nbsp;newoneClass.getConstructor(argsClass)：得到构造子。<br><br>cons.newInstance(args)：新建实例。<br><br>6.&nbsp;判断是否为某个类的实例<br><br>1&nbsp;public&nbsp;boolean&nbsp;isInstance(Object&nbsp;obj,&nbsp;Class&nbsp;cls)&nbsp;{<br>2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;cls.isInstance(obj);<br>3&nbsp;}<br><br>7.&nbsp;得到数组中的某个元素<br>1&nbsp;public&nbsp;Object&nbsp;getByArray(Object&nbsp;array,&nbsp;int&nbsp;index)&nbsp;{<br>2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Array.get(array,index);<br>3&nbsp;}<img src ="http://www.blogjava.net/echo/aggbug/141131.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-08-30 00:24 <a href="http://www.blogjava.net/echo/archive/2007/08/30/141131.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Making the right impression</title><link>http://www.blogjava.net/echo/archive/2007/08/21/138466.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Tue, 21 Aug 2007 14:41:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/08/21/138466.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/138466.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/08/21/138466.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/138466.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/138466.html</trackback:ping><description><![CDATA[<span style="font-family: Comic Sans MS;">&nbsp;&nbsp;&nbsp; <span style="color: red; font-weight: bold;">THE FIRST THING</span> to remember when you go for a job interview is that this is not a one-sided affair. Treat it as a negotiation. After all, both you and the prospective employer are selling something. If you approach an interview with the attitude "any job will do", the interview will realize that immediately. If the job is worth anything, you won't get it.<br>&nbsp;&nbsp;&nbsp; You should also prepare yourself for an interview just as you would do for a negotiation. Find out as much as you can about the company and the person who is to interview you. Don't be caught unawares. Go to the internet and look at the company's website. Compare it with that of its competitors. Alternatively, look at the Yellow Pages or trade magazines to see how they advertise themselves. Make enquiries at the Chamber of Commerce and other relevant organizations. Find out at least a little about the sector so that you can ask interesting questions.<br>&nbsp;&nbsp;&nbsp; Think of and note down your strengths and the opportunities that lie ahead. No matter how high unemployment is, regardless of how miserable you are in your current job, it's always an advantage to see things in a positive light. If you have little or no experience in a particular area, consider your capabilities in a similar area. Spend some time trying to imagine what type of employee the company is looking for and what makes you suitable for the job being advertised.<br>&nbsp;&nbsp;&nbsp; First impressions count so look good and feel good before you go. Choose clothes that make you feel confident. Find out what clothes may put the interviewer off. Ensure you arrive at the interview with time to spare. According to more than one recruitment agency we spoke to,interviewees must understand the importance not only of their personal appearance but also of their body language. During the interview , breathe calmly and try not to appear too nervous. Look the interviewer in the eye and adopt similar body language to theirs. Smile and feel relaxed , enthusiastic and assertive. Remember one thing, though: assertive does not mean aggressive.&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; Don't just answer "yes" or "no" to questions. Treat every question as an opportunity to demonstrate that you are suitable for the job, but remember to stick to the point. When asked about your interests, include group as well as individual activities / hobbies. Be on the lookout for tricky questions about your personal life. You don't need to lie; just sell yourself in the best light. This is something the interviewer needs to be able to do as well. You have the right to find out whether or not you want to work for the company.<br>&nbsp;&nbsp;&nbsp; Furthermore, your interest in the nature of the company and how it is run may well end up being your big selling point.<br><br></span>  <img src ="http://www.blogjava.net/echo/aggbug/138466.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-08-21 22:41 <a href="http://www.blogjava.net/echo/archive/2007/08/21/138466.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hypertext Transfer Protocol -- HTTP/1.1(Status Code Definitions)</title><link>http://www.blogjava.net/echo/archive/2007/08/07/134832.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Mon, 06 Aug 2007 16:59:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/08/07/134832.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/134832.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/08/07/134832.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/134832.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/134832.html</trackback:ping><description><![CDATA[<address>part of <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html" rev=Section><u><font color=#0000ff>Hypertext Transfer Protocol -- HTTP/1.1</font></u></a><br>RFC 2616 Fielding, et al.</address>
<h2><a id=sec10>10</a> Status Code Definitions</h2>
<p>Each Status-Code is described below, including a description of which method(s) it can follow and any metainformation required in the response. </p>
<h3><a id=sec10.1>10.1</a> Informational 1xx</h3>
<p>This class of status code indicates a provisional response, consisting only of the Status-Line and optional headers, and is terminated by an empty line. There are no required headers for this class of status code. Since HTTP/1.0 did not define any 1xx status codes, servers MUST NOT send a 1xx response to an HTTP/1.0 client except under experimental conditions. </p>
<p>A client MUST be prepared to accept one or more 1xx status responses prior to a regular response, even if the client does not expect a 100 (Continue) status message. Unexpected 1xx status responses MAY be ignored by a user agent. </p>
<p>Proxies MUST forward 1xx responses, unless the connection between the proxy and its client has been closed, or unless the proxy itself requested the generation of the 1xx response. (For example, if a </p>
<p>proxy adds a "Expect: 100-continue" field when it forwards a request, then it need not forward the corresponding 100 (Continue) response(s).) </p>
<h3><a id=sec10.1.1>10.1.1</a> 100 Continue</h3>
<p>The client SHOULD continue with its request. This interim response is used to inform the client that the initial part of the request has been received and has not yet been rejected by the server. The client SHOULD continue by sending the remainder of the request or, if the request has already been completed, ignore this response. The server MUST send a final response after the request has been completed. See section <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3" rel=xref><u><font color=#0000ff>8.2.3</font></u></a> for detailed discussion of the use and handling of this status code. </p>
<h3><a id=sec10.1.2>10.1.2</a> 101 Switching Protocols</h3>
<p>The server understands and is willing to comply with the client's request, via the Upgrade message header field (section 14.42), for a change in the application protocol being used on this connection. The server will switch protocols to those defined by the response's Upgrade header field immediately after the empty line which terminates the 101 response. </p>
<p>The protocol SHOULD be switched only when it is advantageous to do so. For example, switching to a newer version of HTTP is advantageous over older versions, and switching to a real-time, synchronous protocol might be advantageous when delivering resources that use such features. </p>
<h3><a id=sec10.2>10.2</a> Successful 2xx</h3>
<p>This class of status code indicates that the client's request was successfully received, understood, and accepted. </p>
<h3><a id=sec10.2.1>10.2.1</a> 200 OK</h3>
<p>The request has succeeded. The information returned with the response is dependent on the method used in the request, for example: </p>
<p>GET an entity corresponding to the requested resource is sent in the response; </p>
<p>HEAD the entity-header fields corresponding to the requested resource are sent in the response without any message-body; </p>
<p>POST an entity describing or containing the result of the action; </p>
<p>TRACE an entity containing the request message as received by the end server. </p>
<h3><a id=sec10.2.2>10.2.2</a> 201 Created</h3>
<p>The request has been fulfilled and resulted in a new resource being created. The newly created resource can be referenced by the URI(s) returned in the entity of the response, with the most specific URI for the resource given by a Location header field. The response SHOULD include an entity containing a list of resource characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content-Type header field. The origin server MUST create the resource before returning the 201 status code. If the action cannot be carried out immediately, the server SHOULD respond with 202 (Accepted) response instead. </p>
<p>A 201 response MAY contain an ETag response header field indicating the current value of the entity tag for the requested variant just created, see section <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19" rel=xref><u><font color=#0000ff>14.19</font></u></a>. </p>
<h3><a id=sec10.2.3>10.2.3</a> 202 Accepted</h3>
<p>The request has been accepted for processing, but the processing has not been completed. The request might or might not eventually be acted upon, as it might be disallowed when processing actually takes place. There is no facility for re-sending a status code from an asynchronous operation such as this. </p>
<p>The 202 response is intentionally non-committal. Its purpose is to allow a server to accept a request for some other process (perhaps a batch-oriented process that is only run once per day) without requiring that the user agent's connection to the server persist until the process is completed. The entity returned with this response SHOULD include an indication of the request's current status and either a pointer to a status monitor or some estimate of when the user can expect the request to be fulfilled. </p>
<h3><a id=sec10.2.4>10.2.4</a> 203 Non-Authoritative Information</h3>
<p>The returned metainformation in the entity-header is not the definitive set as available from the origin server, but is gathered from a local or a third-party copy. The set presented MAY be a subset or superset of the original version. For example, including local annotation information about the resource might result in a superset of the metainformation known by the origin server. Use of this response code is not required and is only appropriate when the response would otherwise be 200 (OK). </p>
<h3><a id=sec10.2.5>10.2.5</a> 204 No Content</h3>
<p>The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation. The response MAY include new or updated metainformation in the form of entity-headers, which if present SHOULD be associated with the requested variant. </p>
<p>If the client is a user agent, it SHOULD NOT change its document view from that which caused the request to be sent. This response is primarily intended to allow input for actions to take place without causing a change to the user agent's active document view, although any new or updated metainformation SHOULD be applied to the document currently in the user agent's active view. </p>
<p>The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields. </p>
<h3><a id=sec10.2.6>10.2.6</a> 205 Reset Content</h3>
<p>The server has fulfilled the request and the user agent SHOULD reset the document view which caused the request to be sent. This response is primarily intended to allow input for actions to take place via user input, followed by a clearing of the form in which the input is given so that the user can easily initiate another input action. The response MUST NOT include an entity. </p>
<h3><a id=sec10.2.7>10.2.7</a> 206 Partial Content</h3>
<p>The server has fulfilled the partial GET request for the resource. The request MUST have included a Range header field (section 14.35) indicating the desired range, and MAY have included an If-Range header field (section <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.27" rel=xref><u><font color=#0000ff>14.27</font></u></a>) to make the request conditional. </p>
<p>The response MUST include the following header fields: </p>
<pre>      - Either a Content-Range header field (section 14.16) indicating
the range included with this response, or a multipart/byteranges
Content-Type including Content-Range fields for each part. If a
Content-Length header field is present in the response, its
value MUST match the actual number of OCTETs transmitted in the
message-body.
</pre>
<pre>      - Date
</pre>
<pre>      - ETag and/or Content-Location, if the header would have been sent
in a 200 response to the same request
</pre>
<pre>      - Expires, Cache-Control, and/or Vary, if the field-value might
differ from that sent in any previous response for the same
variant
</pre>
<p>If the 206 response is the result of an If-Range request that used a strong cache validator (see section 13.3.3), the response SHOULD NOT include other entity-headers. If the response is the result of an If-Range request that used a weak validator, the response MUST NOT include other entity-headers; this prevents inconsistencies between cached entity-bodies and updated headers. Otherwise, the response MUST include all of the entity-headers that would have been returned with a 200 (OK) response to the same request. </p>
<p>A cache MUST NOT combine a 206 response with other previously cached content if the ETag or Last-Modified headers do not match exactly, see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.4" rel=xref><u><font color=#0000ff>13.5.4</font></u></a>. </p>
<p>A cache that does not support the Range and Content-Range headers MUST NOT cache 206 (Partial) responses. </p>
<h3><a id=sec10.3>10.3</a> Redirection 3xx</h3>
<p>This class of status code indicates that further action needs to be taken by the user agent in order to fulfill the request. The action required MAY be carried out by the user agent without interaction with the user if and only if the method used in the second request is GET or HEAD. A client SHOULD detect infinite redirection loops, since such loops generate network traffic for each redirection. </p>
<pre>      Note: previous versions of this specification recommended a
maximum of five redirections. Content developers should be aware
that there might be clients that implement such a fixed
limitation.
</pre>
<h3><a id=sec10.3.1>10.3.1</a> 300 Multiple Choices</h3>
<p>The requested resource corresponds to any one of a set of representations, each with its own specific location, and agent- driven negotiation information (section 12) is being provided so that the user (or user agent) can select a preferred representation and redirect its request to that location. </p>
<p>Unless it was a HEAD request, the response SHOULD include an entity containing a list of resource characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content- Type header field. Depending upon the format and the capabilities of </p>
<p>the user agent, selection of the most appropriate choice MAY be performed automatically. However, this specification does not define any standard for such automatic selection. </p>
<p>If the server has a preferred choice of representation, it SHOULD include the specific URI for that representation in the Location field; user agents MAY use the Location field value for automatic redirection. This response is cacheable unless indicated otherwise. </p>
<h3><a id=sec10.3.2>10.3.2</a> 301 Moved Permanently</h3>
<p>The requested resource has been assigned a new permanent URI and any future references to this resource SHOULD use one of the returned URIs. Clients with link editing capabilities ought to automatically re-link references to the Request-URI to one or more of the new references returned by the server, where possible. This response is cacheable unless indicated otherwise. </p>
<p>The new permanent URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s). </p>
<p>If the 301 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued. </p>
<pre>      Note: When automatically redirecting a POST request after
receiving a 301 status code, some existing HTTP/1.0 user agents
will erroneously change it into a GET request.
</pre>
<h3><a id=sec10.3.3>10.3.3</a> 302 Found</h3>
<p>The requested resource resides temporarily under a different URI. Since the redirection might be altered on occasion, the client SHOULD continue to use the Request-URI for future requests. This response is only cacheable if indicated by a Cache-Control or Expires header field. </p>
<p>The temporary URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s). </p>
<p>If the 302 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued. </p>
<pre>      Note: RFC 1945 and RFC 2068 specify that the client is not allowed
to change the method on the redirected request.  However, most
existing user agent implementations treat 302 as if it were a 303
response, performing a GET on the Location field-value regardless
of the original request method. The status codes 303 and 307 have
been added for servers that wish to make unambiguously clear which
kind of reaction is expected of the client.
</pre>
<h3><a id=sec10.3.4>10.3.4</a> 303 See Other</h3>
<p>The response to the request can be found under a different URI and SHOULD be retrieved using a GET method on that resource. This method exists primarily to allow the output of a POST-activated script to redirect the user agent to a selected resource. The new URI is not a substitute reference for the originally requested resource. The 303 response MUST NOT be cached, but the response to the second (redirected) request might be cacheable. </p>
<p>The different URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s). </p>
<pre>      Note: Many pre-HTTP/1.1 user agents do not understand the 303
status. When interoperability with such clients is a concern, the
302 status code may be used instead, since most user agents react
to a 302 response as described here for 303.
</pre>
<h3><a id=sec10.3.5>10.3.5</a> 304 Not Modified</h3>
<p>If the client has performed a conditional GET request and access is allowed, but the document has not been modified, the server SHOULD respond with this status code. The 304 response MUST NOT contain a message-body, and thus is always terminated by the first empty line after the header fields. </p>
<p>The response MUST include the following header fields: </p>
<pre>      - Date, unless its omission is required by section 14.18.1
</pre>
<p>If a clockless origin server obeys these rules, and proxies and clients add their own Date to any response received without one (as already specified by [RFC 2068], section <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19" rel=xref><u><font color=#0000ff>14.19</font></u></a>), caches will operate correctly. </p>
<pre>      - ETag and/or Content-Location, if the header would have been sent
in a 200 response to the same request
</pre>
<pre>      - Expires, Cache-Control, and/or Vary, if the field-value might
differ from that sent in any previous response for the same
variant
</pre>
<p>If the conditional GET used a strong cache validator (see section 13.3.3), the response SHOULD NOT include other entity-headers. Otherwise (i.e., the conditional GET used a weak validator), the response MUST NOT include other entity-headers; this prevents inconsistencies between cached entity-bodies and updated headers. </p>
<p>If a 304 response indicates an entity not currently cached, then the cache MUST disregard the response and repeat the request without the conditional. </p>
<p>If a cache uses a received 304 response to update a cache entry, the cache MUST update the entry to reflect any new field values given in the response. </p>
<h3><a id=sec10.3.6>10.3.6</a> 305 Use Proxy</h3>
<p>The requested resource MUST be accessed through the proxy given by the Location field. The Location field gives the URI of the proxy. The recipient is expected to repeat this single request via the proxy. 305 responses MUST only be generated by origin servers. </p>
<pre>      Note: RFC 2068 was not clear that 305 was intended to redirect a
single request, and to be generated by origin servers only.  Not
observing these limitations has significant security consequences.
</pre>
<h3><a id=sec10.3.7>10.3.7</a> 306 (Unused)</h3>
<p>The 306 status code was used in a previous version of the specification, is no longer used, and the code is reserved. </p>
<h3><a id=sec10.3.8>10.3.8</a> 307 Temporary Redirect</h3>
<p>The requested resource resides temporarily under a different URI. Since the redirection MAY be altered on occasion, the client SHOULD continue to use the Request-URI for future requests. This response is only cacheable if indicated by a Cache-Control or Expires header field. </p>
<p>The temporary URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s) , since many pre-HTTP/1.1 user agents do not understand the 307 status. Therefore, the note SHOULD contain the information necessary for a user to repeat the original request on the new URI. </p>
<p>If the 307 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued. </p>
<h3><a id=sec10.4>10.4</a> Client Error 4xx</h3>
<p>The 4xx class of status code is intended for cases in which the client seems to have erred. Except when responding to a HEAD request, the server SHOULD include an entity containing an explanation of the error situation, and whether it is a temporary or permanent condition. These status codes are applicable to any request method. User agents SHOULD display any included entity to the user. </p>
<p>If the client is sending data, a server implementation using TCP SHOULD be careful to ensure that the client acknowledges receipt of the packet(s) containing the response, before the server closes the input connection. If the client continues sending data to the server after the close, the server's TCP stack will send a reset packet to the client, which may erase the client's unacknowledged input buffers before they can be read and interpreted by the HTTP application. </p>
<h3><a id=sec10.4.1>10.4.1</a> 400 Bad Request</h3>
<p>The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications. </p>
<h3><a id=sec10.4.2>10.4.2</a> 401 Unauthorized</h3>
<p>The request requires user authentication. The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field (section <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.8" rel=xref><u><font color=#0000ff>14.8</font></u></a>). If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials. If the 401 response contains the same challenge as the prior response, and the user agent has already attempted authentication at least once, then the user SHOULD be presented the entity that was given in the response, since that entity might include relevant diagnostic information. HTTP access authentication is explained in "HTTP Authentication: Basic and Digest Access Authentication" <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec17.html#bib43" rel=bibref><u><font color=#0000ff>[43]</font></u></a>. </p>
<h3><a id=sec10.4.3>10.4.3</a> 402 Payment Required</h3>
<p>This code is reserved for future use. </p>
<h3><a id=sec10.4.4>10.4.4</a> 403 Forbidden</h3>
<p>The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead. </p>
<h3><a id=sec10.4.5>10.4.5</a> 404 Not Found</h3>
<p>The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent. The 410 (Gone) status code SHOULD be used if the server knows, through some internally configurable mechanism, that an old resource is permanently unavailable and has no forwarding address. This status code is commonly used when the server does not wish to reveal exactly why the request has been refused, or when no other response is applicable. </p>
<h3><a id=sec10.4.6>10.4.6</a> 405 Method Not Allowed</h3>
<p>The method specified in the Request-Line is not allowed for the resource identified by the Request-URI. The response MUST include an Allow header containing a list of valid methods for the requested resource. </p>
<h3><a id=sec10.4.7>10.4.7</a> 406 Not Acceptable</h3>
<p>The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request. </p>
<p>Unless it was a HEAD request, the response SHOULD include an entity containing a list of available entity characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content-Type header field. Depending upon the format and the capabilities of the user agent, selection of the most appropriate choice MAY be performed automatically. However, this specification does not define any standard for such automatic selection. </p>
<pre>      Note: HTTP/1.1 servers are allowed to return responses which are
not acceptable according to the accept headers sent in the
request. In some cases, this may even be preferable to sending a
406 response. User agents are encouraged to inspect the headers of
an incoming response to determine if it is acceptable.
</pre>
<p>If the response could be unacceptable, a user agent SHOULD temporarily stop receipt of more data and query the user for a decision on further actions. </p>
<h3><a id=sec10.4.8>10.4.8</a> 407 Proxy Authentication Required</h3>
<p>This code is similar to 401 (Unauthorized), but indicates that the client must first authenticate itself with the proxy. The proxy MUST return a Proxy-Authenticate header field (section <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.33" rel=xref><u><font color=#0000ff>14.33</font></u></a>) containing a challenge applicable to the proxy for the requested resource. The client MAY repeat the request with a suitable Proxy-Authorization header field (section <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.34" rel=xref><u><font color=#0000ff>14.34</font></u></a>). HTTP access authentication is explained in "HTTP Authentication: Basic and Digest Access Authentication" <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec17.html#bib43" rel=bibref><u><font color=#0000ff>[43]</font></u></a>. </p>
<h3><a id=sec10.4.9>10.4.9</a> 408 Request Timeout</h3>
<p>The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time. </p>
<h3><a id=sec10.4.10>10.4.10</a> 409 Conflict</h3>
<p>The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request. The response body SHOULD include enough </p>
<p>information for the user to recognize the source of the conflict. Ideally, the response entity would include enough information for the user or user agent to fix the problem; however, that might not be possible and is not required. </p>
<p>Conflicts are most likely to occur in response to a PUT request. For example, if versioning were being used and the entity being PUT included changes to a resource which conflict with those made by an earlier (third-party) request, the server might use the 409 response to indicate that it can't complete the request. In this case, the response entity would likely contain a list of the differences between the two versions in a format defined by the response Content-Type. </p>
<h3><a id=sec10.4.11>10.4.11</a> 410 Gone</h3>
<p>The requested resource is no longer available at the server and no forwarding address is known. This condition is expected to be considered permanent. Clients with link editing capabilities SHOULD delete references to the Request-URI after user approval. If the server does not know, or has no facility to determine, whether or not the condition is permanent, the status code 404 (Not Found) SHOULD be used instead. This response is cacheable unless indicated otherwise. </p>
<p>The 410 response is primarily intended to assist the task of web maintenance by notifying the recipient that the resource is intentionally unavailable and that the server owners desire that remote links to that resource be removed. Such an event is common for limited-time, promotional services and for resources belonging to individuals no longer working at the server's site. It is not necessary to mark all permanently unavailable resources as "gone" or to keep the mark for any length of time -- that is left to the discretion of the server owner. </p>
<h3><a id=sec10.4.12>10.4.12</a> 411 Length Required</h3>
<p>The server refuses to accept the request without a defined Content- Length. The client MAY repeat the request if it adds a valid Content-Length header field containing the length of the message-body in the request message. </p>
<h3><a id=sec10.4.13>10.4.13</a> 412 Precondition Failed</h3>
<p>The precondition given in one or more of the request-header fields evaluated to false when it was tested on the server. This response code allows the client to place preconditions on the current resource metainformation (header field data) and thus prevent the requested method from being applied to a resource other than the one intended. </p>
<h3><a id=sec10.4.14>10.4.14</a> 413 Request Entity Too Large</h3>
<p>The server is refusing to process a request because the request entity is larger than the server is willing or able to process. The server MAY close the connection to prevent the client from continuing the request. </p>
<p>If the condition is temporary, the server SHOULD include a Retry- After header field to indicate that it is temporary and after what time the client MAY try again. </p>
<h3><a id=sec10.4.15>10.4.15</a> 414 Request-URI Too Long</h3>
<p>The server is refusing to service the request because the Request-URI is longer than the server is willing to interpret. This rare condition is only likely to occur when a client has improperly converted a POST request to a GET request with long query information, when the client has descended into a URI "black hole" of redirection (e.g., a redirected URI prefix that points to a suffix of itself), or when the server is under attack by a client attempting to exploit security holes present in some servers using fixed-length buffers for reading or manipulating the Request-URI. </p>
<h3><a id=sec10.4.16>10.4.16</a> 415 Unsupported Media Type</h3>
<p>The server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method. </p>
<h3><a id=sec10.4.17>10.4.17</a> 416 Requested Range Not Satisfiable</h3>
<p>A server SHOULD return a response with this status code if a request included a Range request-header field (section 14.35), and none of the range-specifier values in this field overlap the current extent of the selected resource, and the request did not include an If-Range request-header field. (For byte-ranges, this means that the first- byte-pos of all of the byte-range-spec values were greater than the current length of the selected resource.) </p>
<p>When this status code is returned for a byte-range request, the response SHOULD include a Content-Range entity-header field specifying the current length of the selected resource (see section <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16" rel=xref><u><font color=#0000ff>14.16</font></u></a>). This response MUST NOT use the multipart/byteranges content- type. </p>
<h3><a id=sec10.4.18>10.4.18</a> 417 Expectation Failed</h3>
<p>The expectation given in an Expect request-header field (see section 14.20) could not be met by this server, or, if the server is a proxy, the server has unambiguous evidence that the request could not be met by the next-hop server. </p>
<h3><a id=sec10.5>10.5</a> Server Error 5xx</h3>
<p>Response status codes beginning with the digit "5" indicate cases in which the server is aware that it has erred or is incapable of performing the request. Except when responding to a HEAD request, the server SHOULD include an entity containing an explanation of the error situation, and whether it is a temporary or permanent condition. User agents SHOULD display any included entity to the user. These response codes are applicable to any request method. </p>
<h3><a id=sec10.5.1>10.5.1</a> 500 Internal Server Error</h3>
<p>The server encountered an unexpected condition which prevented it from fulfilling the request. </p>
<h3><a id=sec10.5.2>10.5.2</a> 501 Not Implemented</h3>
<p>The server does not support the functionality required to fulfill the request. This is the appropriate response when the server does not recognize the request method and is not capable of supporting it for any resource. </p>
<h3><a id=sec10.5.3>10.5.3</a> 502 Bad Gateway</h3>
<p>The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request. </p>
<h3><a id=sec10.5.4>10.5.4</a> 503 Service Unavailable</h3>
<p>The server is currently unable to handle the request due to a temporary overloading or maintenance of the server. The implication is that this is a temporary condition which will be alleviated after some delay. If known, the length of the delay MAY be indicated in a Retry-After header. If no Retry-After is given, the client SHOULD handle the response as it would for a 500 response. </p>
<pre>      Note: The existence of the 503 status code does not imply that a
server must use it when becoming overloaded. Some servers may wish
to simply refuse the connection.
</pre>
<h3><a id=sec10.5.5>10.5.5</a> 504 Gateway Timeout</h3>
<p>The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI (e.g. HTTP, FTP, LDAP) or some other auxiliary server (e.g. DNS) it needed to access in attempting to complete the request. </p>
<pre>      Note: Note to implementors: some deployed proxies are known to
return 400 or 500 when DNS lookups time out.
</pre>
<h3><a id=sec10.5.6>10.5.6</a> 505 HTTP Version Not Supported</h3>
<p>The server does not support, or refuses to support, the HTTP protocol version that was used in the request message. The server is indicating that it is unable or unwilling to complete the request using the same major version as the client, as described in section <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.1" rel=xref><u><font color=#0000ff>3.1</font></u></a>, other than with this error message. The response SHOULD contain an entity describing why that version is not supported and what other protocols are supported by that server. </p>
<img src ="http://www.blogjava.net/echo/aggbug/134832.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-08-07 00:59 <a href="http://www.blogjava.net/echo/archive/2007/08/07/134832.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何做需求分析</title><link>http://www.blogjava.net/echo/archive/2007/07/07/128831.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Sat, 07 Jul 2007 15:44:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/07/07/128831.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/128831.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/07/07/128831.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/128831.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/128831.html</trackback:ping><description><![CDATA[come from <a href="http://blog.sina.com.cn/u/4a698c270100067q" target=_blank><u><font color=#810081>here</font></u></a><br><br><font size=2>如果将需求分析阶段的工作归结为编写需求规格说明书，这种简化的做法往往是导致项目后期层出不穷问题的罪魁祸首。建议采用以下步骤形成软件需求：获取用户需求&#8594;分析用户需求&#8594;编写需求文档&#8594;评审需求文档&#8594;管理需求。下面我们先来讨论前两个步骤（获取用户需求、分析用户需求）的做法。</font>
<p><strong><font size=2>获取用户需求</font></strong></p>
<p><font size=2>　　这是该阶段的一个最重要的任务。以下为获取用户需求需要执行的活动（如图1所示）。</font></p>
<p><font size=2>　　● 了解客户方的所有用户类型以及潜在的类型。然后，根据他们的要求来确定系统的整体目标和系统的工作范围。</font></p>
<p><font size=2>　　● 对用户进行访谈和调研。交流的方式可以是会议、电话、电子邮件、小组讨论、模拟演示等不同形式。需要注意的是，每一次交流一定要有记录，对于交流的结果还可以进行分类，便于后续的分析活动。例如，可以将需求细分为功能需求、非功能需求（如响应时间、平均无故障工作时间、自动恢复时间等）、环境限制、设计约束等类型。</font></p>
<p><font size=2>　　● 需求分析人员对收集到的用户需求做进一步的分析和整理。下面是几条常见的准则：</font></p>
<p><font size=2>　　⑴对于用户提出的每个需求都要知道&#8220;为什么&#8221;，并判断用户提出的需求是否有充足的理由；</font></p>
<p><font size=2><img height=249 alt="" src="http://www.sawin.cn/doc/SA/REQ/howtoreq2-1.jpg" width=150>　　</font></p>
<p><font size=2>　　图1 获取用户需求的活动</font></p>
<p><font size=2>　　⑵将那种以&#8220;如何实现&#8221;的表述方式转换为&#8220;实现什么&#8221;的方式，因为需求分析阶段关注的目标是&#8220;做什么&#8221;，而不是&#8220;怎么做&#8221;；</font></p>
<p><font size=2>　　⑶分析由用户需求衍生出的隐含需求，并识别用户没有明确提出来的隐含需求（有可能是实现用户需求的前提条件），这一点往往容易忽略掉，经常因为对隐含需求考虑得不够充分而引起需求变更。</font></p>
<p><font size=2>　　● 需求分析人员将调研的用户需求以适当的方式呈交给用户方和开发方的相关人员。大家共同确认需求分析人员所提交的结果是否真实地反映了用户的意图。需求分析人员在这个任务中需要执行下述活动：</font></p>
<p><font size=2>　　⑴明确标识出那些未确定的需求项（在需求分析初期往往有很多这样的待定项）；</font></p>
<p><font size=2>　　⑵使需求符合系统的整体目标；</font></p>
<p><font size=2>　　⑶保证需求项之间的一致性，解决需求项之间可能存在的冲突。</font></p>
<p><font size=2><strong>分析用户需求</strong></font></p>
<p><font size=2>　　在很多情形下，分析用户需求是与获取用户需求并行的，主要通过建立模型的方式来描述用户的需求，为客户、用户、开发方等不同参与方提供一个交流的渠道。这些模型是对需求的抽象，以可视化的方式提供一个易于沟通的桥梁。用户需求的分析与获取用户需求有着相似的步骤，区别在于分析用户需求时使用模型来描述，以获取用户更明确的需求。分析用户需求需要执行下列活动：</font></p>
<p><font size=2>　　● 以图形表示的方式描述系统的整体结构，包括系统的边界与接口；</font></p>
<p><font size=2>　　● 通过原型、页面流或其它方式向用户提供可视化的界面，用户可以对需求做出自己的评价；</font></p>
<p><font size=2>　　● 系统可行性分析，需求实现的技术可行性、环境分析、费用分析、时间分析等；</font></p>
<p><font size=2>　　● 以模型描述系统的功能项、数据实体、外部实体、实体之间的关系、实体之间的状态转换等方面的内容。</font></p>
<p><font size=2><img height=252 alt="" src="http://www.sawin.cn/doc/SA/REQ/howtoreq2-2.jpg" width=351>　　</font></p>
<p><font size=2>　　图2 DFD示意图</font></p>
<p><font size=2>　　用于需求建模的方法有很多种，最常用的包括数据流图（DFD）、实体关系图（ERD）和用例图（Use Case）三种方式。DFD作为结构化系统分析与设计的主要方法，已经得到了广泛的应用，DFD尤其适用于MIS系统的表述。DFD使用四种基本元素来描述系统的行为，过程、实体、数据流和数据存储。DFD方法直观易懂，使用者可以方便地得到系统的逻辑模型和物理模型，但是从DFD图中无法判断活动的时序关系。图2描述的是某个项目的DFD示意图。</font></p>
<p><font size=2>　　ERD方法用于描述系统实体间的对应关系，需求分析阶段使用ERD描述系统中实体的逻辑关系，在设计阶段则使用ERD描述物理表之间的关系。需求分析阶段使用ERD来描述现实世界中的对象。ERD只关注系统中数据间的关系，而缺乏对系统功能的描述。如果将ERD与DFD两种方法相结合，则可以更准确地描述系统的需求。</font></p>
<p><font size=2>　　在面向对象分析的方法中通常使用Use Case来获取软件的需求。Use Case通过描述&#8220;系统&#8221;和&#8220;活动者&#8221;之间的交互来描述系统的行为。通过分解系统目标，Use Case描述活动者为了实现这些目标而执行的所有步骤。Use Case方法最主要的优点，在于它是用户导向的，用户可以根据自己所对应的Use Case来不断细化自己的需求。此外，使用Use Case还可以方便地得到系统功能的测试用例。</font></p>
<p><font size=2><strong>编写需求文档</strong></font></p>
<p><font size=2>　　需求文档可以使用自然语言或形式化语言来描述，还可以添加图形的表述方式和模型表征的方式。需求文档应该包括用户的所有需求（功能性需求和非功能性需求）。</font></p>
<p><font size=2><strong>评审需求文档</strong></font></p>
<p><font size=2>　　需求文档完成后，需要经过正式评审，以便作为下一阶段工作的基础。一般的评审分为用户评审和同行评审两类。用户和开发方对于软件项目内容的描述，是以需求规格说明书作为基础的；用户验收的标准则是依据需求规格说明书中的内容来制订，所以评审需求文档时用户的意见是第一位的。而同行评审的目的，是在软件项目初期发现那些潜在的缺陷或错误，避免这些错误和缺陷遗漏到项目的后续阶段。</font></p>
<p><font size=2><strong>管理需求</strong></font></p>
<p><font size=2><img height=403 alt="" src="http://www.sawin.cn/doc/SA/REQ/howtoreq2-3.jpg" width=294>　　</font></p>
<p><font size=2>　　图1 需求变更流程</font></p>
<p><font size=2>　　需求的变更是不可避免的，如何以可控的方式管理软件的需求，对于项目的顺利进行有着重要的意义。如果匆匆忙忙地完成用户调研与分析，则往往意味着不稳定的需求。所以需求管理要保证需求分析各个活动都得到了充分的执行。对于需求变更的管理，则主要使用需求变更流程和需求跟踪矩阵的管理方式。需求变更流程和需求跟踪矩阵分别如图1和图2所示。</font></p>
<p><font size=2><img height=152 alt="" src="http://www.sawin.cn/doc/SA/REQ/howtoreq2-4.jpg" width=374>　　</font></p>
<p><font size=2>　　图2 需求跟踪矩阵</font></p>
<p><font size=2>　　常见问题及建议</font></p>
<p><font size=2>　　Q、客户与最终用户的区别是什么？</font></p>
<p><font size=2>　　A、可以借助图3来说明它们之间的区别。</font></p>
<p><font size=2><img height=195 alt="" src="http://www.sawin.cn/doc/SA/REQ/howtoreq2-5.jpg" width=300>　　</font></p>
<p><font size=2>　　图3 需求获取渠道示意图</font></p>
<p><font size=2>　　软件需求来自系统工程与客户两个方面，其中客户是主要的需求提供者（系统工程需求也来自于客户）。客户需要搜集其最终用户的需求并考虑自身的需求，然后再提供给开发方。假如客户并未去认真搜集最终用户的需求，开发方便需要做到这一点，因为系统最终要满足最终用户的需求。</font></p>
<p><font size=2>　　Q、如何进行用户访谈？</font></p>
<p><font size=2>　　A、首先，一定要事先确定访谈的目的和提纲。其次，因为用户往往并不知道应该提供哪些方面的需求，所以需要开发人员引导。</font></p>
<p><font size=2>　　Q、用户访谈内容是什么？</font></p>
<p><font size=2>　　A、首先，请用户描述他们如何完成自己当前的工作，并与用户一起抽象出一个工作流程或工作模型。然后，在得到用户的认可后，向用户解释自己是怎样来实现这些功能的，并说明哪些环节可以用自动化方式实现等。</font></p>
<p><font size=2>　　Q、采用哪一种方式做需求分析最好？</font></p>
<p><font size=2>　　A、不同的需求分析有不同的特点。还没有哪一种方法可以完全替代别的方法，否则，现在就不会存在不同的需求建模方式了。一般来说，可以使用DFD＋ERD来描述那些功能层次比较清晰的需求；而USE CASE则适于描述功能结构复杂的需求。做需求分析的目的是为了建立需求的模型，不同的子系统有可能使用不同的建模方法。</font></p>
<p><font size=2>　　Q、怎样做原型，原型的目的是什么？</font></p>
<p><font size=2>　　A、通常使用原型分析方法来帮助开发方进一步获取用户需求或让用户确认需求。开发方往往先向用户提供一个可视界面作为原型，并在界面上布置必要的元素以演示用户所需要的功能。可以使用第四代语言（例如Visual Basic、Delphi等）来快速生成用户界面，也可以使用FrontPage等网页制作工具来生成用户可视的页面流。</font></p>
<p><font size=2>　　原型的目的往往是获取需求。但有时也使用原型的方式来验证关键技术或技术难点。对于技术原型，界面则往往被忽略掉。</font></p>
<img src ="http://www.blogjava.net/echo/aggbug/128831.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-07-07 23:44 <a href="http://www.blogjava.net/echo/archive/2007/07/07/128831.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入EJB的调用原理</title><link>http://www.blogjava.net/echo/archive/2007/06/16/124620.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Sat, 16 Jun 2007 03:10:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/06/16/124620.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/124620.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/06/16/124620.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/124620.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/124620.html</trackback:ping><description><![CDATA[<span style="COLOR: red">深入EJB的调用原理</span><br><br>一个远程对象至少要包括4个class文件：远程对象；远程对象的接口；实现远程接口的对象的stub；对象的skeleton这4个class文件。<br><br>在EJB中则至少要包括10个class：<br><br>Bean类，特定App Server的Bean实现类，Bean的remote接口，特定App Server的remote接口实现类，特定App Server的remote接口的实现类的stub类和skeleton类。<br><br>Bean的home接口，特定App Server的home接口实现类，特定App Server的home接口的实现类的stub类和skeleton类和RMI不同的是，EJB中这10个class真正需要用户编写的只有3个，分别是Bean类和它的remote接口，home接口，至于其它的7个class到底是怎么生成，被打包在什么地方，或者是否需要更多的类文件，会根据不同的App Server表现出比较大的差异，不能一概而论。<br><br>拿我最熟悉的Weblogic的来说吧，Weblogic的Bean实现类，以及两个接口的Weblogic的实现类是在ejbc的时候被打包到EJB的jar包里面的，这3个class文件可以看到。而home接口和remote接口的Weblogic的实现类的stub类和skeleton类是在EJB被部署到Weblogic的时候，由Weblogic动态生成stub类和Skeleton类的字节码，因此看不到这4个类文件。<br><br>对于一次客户端远程调用EJB，要经过两个远程对象的多次RMI循环。首先是通过JNDI查找Home接口，获得Home接口的实现类，这个过程其实相当复杂。<br><br>首先是找到Home接口的Weblogic实现类，然后创建一个Home接口的Weblogic实现类的stub类的对象实例，将它序列化传送给客户端（注意stub类的实例是在第1次RMI循环中，由服务器动态发送给客户端的，因此不需要客户端保存Home接口的Weblogic实现类的stub类），最后客户端获得该stub类的对象实例（普通的RMI需要在客户端保存stub类，而EJB不需要，因为服务器会把stub类的对象实例发送给客户端）。<br><br>客户端拿到服务器给它的Home接口的Weblogic实现类的stub类对象实例以后，调用stub类的create方法，(在代码上就是home.create()，但是后台要做很多事情),于是经过第2次RMI循环，在服务器端，Home接口的Weblogic实现类的skeleton类收到stub类的调用信息后，由它再去调用Home接口的Weblogic实现类的create方法。<br><br>在服务端，Home接口的Weblogic实现类的create方法再去调用Bean类的Weblogic实现类的ejbCreate方法，在服务端创建或者分配一个EJB实例，然后将这个EJB实例的远程接口的Weblogic实现类的stub类对象实例序列化发送给客户端。<br>客户端收到remote接口的Weblogic实现类的stub类的对象实例，对该对象实例的方法调用（在客户端代码中实际上就是对remote接口的调用），将传送给服务器端remote接口的Weblogic实现类的skeleton类对象，而skeleton类对象再调用相应的remote接口的Weblogic实现类，然后remote接口的Weblogic实现类再去调用Bean类的Weblogic实现类，如此就完成一次EJB对象的远程调用。<br><br>看了一遍帖子，感觉还是没有说太清楚，既然写了帖子，就想彻底把它说清楚。<br><br>先拿普通RMI来说，有4个class，分别是远程对象，对象的接口，对象的stub类和skeleton类。而对象本身和对象的stub类同时都实现了接口类。而我们在客户端代码调用远程对象的时候，虽然在代码中操纵接口，实质上是在操纵stub类，例如：<br><br>接口类：Hello<br><br>远程对象：Hello_Server<br><br>stub类：Hello_Stub<br><br>skeleton类：Hello_Skeleton<br><br>客户端代码要这样写：<br><br>
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code><span class=content>
            Hello h = new Hello_Stub();
            h.getString();</span></ccid_code>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p><br><br>我们不会这样写：<br><br>
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code><span class=content>
            Hello_Stub h = new Hello_Stub();
            h.getString();</span></ccid_code>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p><br><br>因为使用接口适用性更广，就算更换了接口实现类，也不需要更改代码。因此客户端需要Hello.class和Hello_Stub.class这两个文件。<br><br>但是对于EJB来说，就不需要Hello_Stub.class，因为服务器会发送给它，但是Hello.class文件客户端是省不了的，必须有。表面上我们的客户端代码在操纵Hello，但别忘记了Hello只是一个接口，抽象的，实质上是在操纵Hello_Stub。</p>
拿Weblogic上的EJB举例子，10个class分别是：<br><br>Bean类：HelloBean （用户编写）<br><br>Bean类的Weblogic实现类：HelloBean_Impl （EJBC生成）<br><br>Home接口：HelloHome （用户编写）<br><br>Home接口的Weblogic实现类 ((Hello Bean))_HomeImpl（EJBC生成）<br><br>Home接口的Weblogic实现类的stub类 ((Hello Bean))_HomeImpl_WLStub（部署的时候动态生成字节码）<br><br>Home接口的Weblogic实现类的skeleton类 ((Hello Bean))_HomeImpl_WLSkeleton（部署的时候动态生成字节码）<br><br>Remote接口：Hello （用户编写）<br><br>Remote接口的Weblogic实现类 ((Hello Bean))_EOImpl（EJBC生成）<br><br>Remote接口的Weblogic实现类的stub类 ((Hello Bean))_EOImpl_WLStub（部署的时候动态生成字节码）<br><br>Remote接口的Weblogic实现类的skeleton类 ((Hello Bean))_EOImpl_WLSkeleton（部署的时候动态生成字节码）<br><br>客户端只需要Hello.class和HelloHome.class这两个文件。<br><br>
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code>
            <span class=content>((Hello Home)) home = (Home)
            ((Portable Remote Object)).narrow(ctx.lookup("Hello"),
            ((Hello Home)).class);</span></ccid_code>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p><br><br>这一行代码是从JNDI获得Home接口，但是请记住！接口是抽象的，那么home这个对象到底是什么类的对象实例呢？很简单，用toString()输出看一下就明白了，下面一行是输出结果：<br><br>
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code class=content>
            ((Hello Bean))_HomeImpl_WLStub@18c458</ccid_code>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p><br><br>这表明home这个通过从服务器的JNDI树上查找获得的对象实际上是HelloBean_HomeImpl_WLStub类的一个实例。<br><br>接下来客户端代码：<br><br>
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code class=content>
            Hello h = home.create()</ccid_code>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center>
<p><br><br>同样Hello只是一个抽象的接口，那么h对象是什么东西呢？打印一下：<br><br>
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code class=content>
            ((Hello Bean))_EOImpl_WLStub@8fa0d1</ccid_code>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center><br>原来是HelloBean_EOImpl_WLStub的一个对象实例。<br><br>用这个例子来简述一遍EJB调用过程：<br><br>首先客户端JNDI查询，服务端JNDI树上Hello这个名字实际上绑定的对象是HelloBean_HomeImpl_WLStub，所以服务端将创建HelloBean_HomeImpl_WLStub的一个对象实例，序列化返回给客户端。<br><br>于是客户端得到home对象，表面上是得到HelloHome接口的实例，实际上是进行了一次远程调用得到了HelloBean_HomeImpl_WLStub类的对象实例，别忘记了HelloBean_HomeImpl_WLStub也实现了HelloHome接口。<br><br>然后home.create()实质上就是HelloBean_HomeImpl_WLStub.create()，该方法将发送信息给HelloBean_HomeImpl_WLSkeleton，而HelloBean_HomeImpl_WLSkeleton接受到信息后，再去调用HelloBean_HomeImpl的create方法，至此完成第1次完整的RMI循环。<br><br>注意在这次RMI循环过程中，远程对象是HelloBean_HomeImpl，远程对象的接口是HelloHome，对象的stub是HelloBean_HomeImpl_WLStub，对象的skeleton是HelloBean_HomeImpl_WLSkeleton。<br><br>然后HelloBean_HomeImpl再去调用HelloBean_Impl的ejbCreate方法，而HelloBean_Impl的ejbCreate方法将负责创建或者分配一个Bean实例，并且创建一个HelloBean_EOImpl_WLStub的对象实例。<br><br>这一步比较有趣的是，在前一步RMI循环中，远程对象HelloBean_HomeImpl在客户端有一个代理类HelloBean_HomeImpl_WLStub，但在这一步，HelloBean_HomeImpl自己却充当了HelloBean_Impl的代理类，只不过HelloBean_HomeImpl不在客户端，而是在服务端，因此不进行RMI。<br><br>然后HelloBean_EOImpl_WLStub的对象实例序列化返回给客户端，这一步也很有趣，上次RMI过程，主角是HelloBean_HomeImpl和它的代理类HelloBean_HomeImpl_WLStub，但这这一次换成了HelloBean_EOImpl和它的代理类HelloBean_EOImpl_WLStub来玩了。<br><br>
<center><ccid_nobr>
<table cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1>
    <tbody>
        <tr>
            <td class=code style="FONT-SIZE: 9pt" bgColor=#e6e6e6>
            <pre><ccid_code class=content>
            Hello h = home.create();h.helloWorld();</ccid_code>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</ccid_nobr></center><br>假设Hello接口有一个helloWorld远程方法，那么表面上是在调用Hello接口的helloWorld方法，实际上是在调用HelloBean_EOImpl_WLStub的helloWorld方法。<br><br>然后HelloBean_EOImpl_WLStub的helloWorld方法将发送信息给服务器上的HelloBean_EOImpl_WLSkeleton，而HelloBean_EOImpl_WLSkeleton收到信息以后，再去调用HelloBean_EOImpl的helloWorld方法。至此，完成第2次完整的RMI循环过程。<br><br>在刚才HelloBean_EOImpl是作为远程对象被调用的，它的代理类是HelloBean_EOImpl_WLStub，但现在HelloBean_EOImpl要作为HelloBean_Impl的代理类了。现在HelloBean_EOImpl去调用HelloBean_Impl的helloWorld方法。注意！HelloBean_Impl继承了HelloBean，而HelloBean中的helloWorld方法是我们亲自编写的代码，现在终于调用到了我们编写的代码了！<br><br>至此，一次EJB调用过程终于完成。在整个过程中，服务端主要要调用的类是HelloBean_Impl， Hello Bean?_HomeImpl，HelloBean_HomeImpl_WLSkeleton，HelloBean_EOImpl，HelloBean_EOImpl_WLSkeleton。<br><br>客户端主要调用的类是HelloBean_HomeImpl_WLStub，HelloBean_EOImpl_WLStub，这两个类在客户端代码中并不会直接出现，出现在代码中的类是他们的接口HelloHome和Hello，因此客户端需要这两个接口文件，而Stub是服务器传送给他们的。 
<img src ="http://www.blogjava.net/echo/aggbug/124620.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-06-16 11:10 <a href="http://www.blogjava.net/echo/archive/2007/06/16/124620.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>架构师成长路线</title><link>http://www.blogjava.net/echo/archive/2007/06/16/124602.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Fri, 15 Jun 2007 18:01:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/06/16/124602.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/124602.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/06/16/124602.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/124602.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/124602.html</trackback:ping><description><![CDATA[<img style="WIDTH: 716px; HEIGHT: 768px" height=768 src="http://www.blogjava.net/images/blogjava_net/echo/Snap1.gif" width=716 border=0>
<img src ="http://www.blogjava.net/echo/aggbug/124602.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-06-16 02:01 <a href="http://www.blogjava.net/echo/archive/2007/06/16/124602.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数据库中的索引</title><link>http://www.blogjava.net/echo/archive/2007/06/09/122962.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Fri, 08 Jun 2007 17:57:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/06/09/122962.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/122962.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/06/09/122962.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/122962.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/122962.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 数据库中的索引&nbsp;&nbsp;<a href='http://www.blogjava.net/echo/archive/2007/06/09/122962.html'>阅读全文</a><img src ="http://www.blogjava.net/echo/aggbug/122962.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-06-09 01:57 <a href="http://www.blogjava.net/echo/archive/2007/06/09/122962.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB 2 工作流程图 </title><link>http://www.blogjava.net/echo/archive/2007/06/09/122961.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Fri, 08 Jun 2007 17:16:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/06/09/122961.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/122961.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/06/09/122961.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/122961.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/122961.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: EJB 2 工作流程图&nbsp;&nbsp;<a href='http://www.blogjava.net/echo/archive/2007/06/09/122961.html'>阅读全文</a><img src ="http://www.blogjava.net/echo/aggbug/122961.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-06-09 01:16 <a href="http://www.blogjava.net/echo/archive/2007/06/09/122961.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>A private conversation</title><link>http://www.blogjava.net/echo/archive/2007/05/31/121236.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Thu, 31 May 2007 11:46:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/05/31/121236.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/121236.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/05/31/121236.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/121236.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/121236.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: A Private Conversation<br><br>      Last week I went to the theatre, I had a good seat, the play was very interesting, but I did not enjoy it. A young man and a young woman were sitting behind me, they were talking loudly. I got very angry, I could not hear the actors. I truned round.<br>I looked at the man and the woman angrily. The did not pay any attention. In the end, I conld not bear it. I turned round again. <br>'I can't hear a word!' I said angrily.<br>      'It's none of your busine&nbsp;&nbsp;<a href='http://www.blogjava.net/echo/archive/2007/05/31/121236.html'>阅读全文</a><img src ="http://www.blogjava.net/echo/aggbug/121236.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-05-31 19:46 <a href="http://www.blogjava.net/echo/archive/2007/05/31/121236.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>了其然，知其用，研其究，发其思</title><link>http://www.blogjava.net/echo/archive/2007/05/24/119834.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Thu, 24 May 2007 14:42:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/05/24/119834.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/119834.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/05/24/119834.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/119834.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/119834.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 了其然，知其用，研其究，发其思<br><br>了其然：对最近新出现的理念技术能够有所了解，简单知道其可以解决什么问题，分析一下是否最近自己所需要应用，或可被更好的利用。 <br>       知其用：知道如何应用这门新技术。简单的应用一般花费不少时间，但是想复杂的应用，需要耗费的时间和精力可就多了。如果把握不好，盲目的应用和学习，会浪费不少时间。<br><br>       研其究：对新技术新理念研究其深层次的原理，框架，结构。<br><br>       发其思：这是最难的一层，首先需要有研其究的基础，这本身就是一个高难度的事情。而研究之后，能够发散思维，扩充或本土化改造，则更是艰巨的事情。<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/echo/archive/2007/05/24/119834.html'>阅读全文</a><img src ="http://www.blogjava.net/echo/aggbug/119834.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-05-24 22:42 <a href="http://www.blogjava.net/echo/archive/2007/05/24/119834.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>My Eclipse 5.5 New and Noteworthy Features</title><link>http://www.blogjava.net/echo/archive/2007/05/21/119010.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Mon, 21 May 2007 15:39:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/05/21/119010.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/119010.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/05/21/119010.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/119010.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/119010.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: My Eclipse 5.5 New and Noteworthy Features&nbsp;&nbsp;<a href='http://www.blogjava.net/echo/archive/2007/05/21/119010.html'>阅读全文</a><img src ="http://www.blogjava.net/echo/aggbug/119010.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-05-21 23:39 <a href="http://www.blogjava.net/echo/archive/2007/05/21/119010.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL语句性能调整</title><link>http://www.blogjava.net/echo/archive/2007/05/21/119001.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Mon, 21 May 2007 14:49:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/05/21/119001.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/119001.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/05/21/119001.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/119001.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/119001.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: SQL语句性能调整的目标是： <br>　　去掉不必要的大表全表扫描---不必要的大表全表扫描会造成不必要的输入输出，而且还会拖垮整个数据库； <br>　　检查优化索引的使用---这对于提高查询速度来说非常重要 <br>　　检查子查询---考虑SQL子查询是否可以用简单连接的方式进行重新书写； <br>　　调整PCTFREE和PCTUSED等存储参数优化插入、更新或者删除等操作； <br>　　考虑数据库的优化器; <br>　　考虑数据表的全表扫描和在多个CPU的情况下考虑并行查询; &nbsp;&nbsp;<a href='http://www.blogjava.net/echo/archive/2007/05/21/119001.html'>阅读全文</a><img src ="http://www.blogjava.net/echo/aggbug/119001.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-05-21 22:49 <a href="http://www.blogjava.net/echo/archive/2007/05/21/119001.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>NetBeans News</title><link>http://www.blogjava.net/echo/archive/2007/05/21/118771.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Sun, 20 May 2007 17:17:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/05/21/118771.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/118771.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/05/21/118771.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/118771.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/118771.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: NetBeans.org is proud to announce the availability of NetBeans IDE 6.0 Preview (Milestone 9). Here are some of the highlights: <br><br>Ruby/JRuby/Ruby on Rails Support <br>A Smarter and Faster Editor <br>Improved Swing development (Swing Data Binding) <br>Integrated Profiling <br>Integrated Visual Design for Web Applications <br>New, Integrated UI for CLDC/MIDP and CDC development <br>The final NetBeans IDE 6.0 release is planned for November, 2007. As always, we welcome and encourage yo&nbsp;&nbsp;<a href='http://www.blogjava.net/echo/archive/2007/05/21/118771.html'>阅读全文</a><img src ="http://www.blogjava.net/echo/aggbug/118771.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-05-21 01:17 <a href="http://www.blogjava.net/echo/archive/2007/05/21/118771.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>十年编程经验凝结(廖俊才，CSDN编辑)</title><link>http://www.blogjava.net/echo/archive/2007/05/21/118769.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Sun, 20 May 2007 16:56:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/05/21/118769.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/118769.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/05/21/118769.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/118769.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/118769.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 十年编程经验凝结(廖俊才，CSDN编辑)&nbsp;&nbsp;<a href='http://www.blogjava.net/echo/archive/2007/05/21/118769.html'>阅读全文</a><img src ="http://www.blogjava.net/echo/aggbug/118769.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-05-21 00:56 <a href="http://www.blogjava.net/echo/archive/2007/05/21/118769.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数据库理论基础(外联接)</title><link>http://www.blogjava.net/echo/archive/2007/05/18/118204.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Thu, 17 May 2007 16:30:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/05/18/118204.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/118204.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/05/18/118204.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/118204.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/118204.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 数据库理论基础(外联接)<br><br>        假设有两个关系R和S<br><br>        在关系R和S做自然联接时, 我们选择两个关系在公共属性上值相等的元组构成新关系的元组.此时, 关系R中某些元组有可能在S中不存在公共属性上值相等的元组, 造成R中这些元组的值在操作时被舍弃. 由于同样的原因, S中某些元组也有可能被舍弃. 为了在操作时能保存这些被舍弃的元组,  可以采用外联接操作. <br>        <br>         如果R和S做自然联接时, 把原来该舍弃的元组也保留在新关系中， 同时在这些元组新增加的属性上填上空值(null), 这种操作称为"外联接"操作.<br>        <br>         如果R和S做自然联接时, 只把R中原来该舍弃的元组放在新关系中, 那么这种操作被称为"左外联接"操作.<br>         select * from t_R left outer join t_S on t_R.B = t_S.B and t_R.C = t_S.C<br>        <br>         如&nbsp;&nbsp;<a href='http://www.blogjava.net/echo/archive/2007/05/18/118204.html'>阅读全文</a><img src ="http://www.blogjava.net/echo/aggbug/118204.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-05-18 00:30 <a href="http://www.blogjava.net/echo/archive/2007/05/18/118204.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring AOP 学习笔记</title><link>http://www.blogjava.net/echo/archive/2007/05/07/115767.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Mon, 07 May 2007 14:27:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/05/07/115767.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/115767.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/05/07/115767.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/115767.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/115767.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 通知（Advice）：横切操作时具体的操作。 <br>切入点（Pointcut）：描述什么时候需要进行横切操作，即在哪些地方需要加入通知，但是切入点不关心具体的通知是什么。 <br>通知者（Advisor）：由于通知者是通过切入点来创建的（切入点作为创建一个通知者实例时的参数），切入点可以对目标类和目标方法进行详细的描述，所以通知者告诉代理哪些类的哪些方法需要进行横切操作，从而对需要实现横切的方法进行灵活的定制。我把通知者理解为切入点和通知的绑定（通知作为创建通知者实例时的另一个参数），它描述了哪些类的哪些方法需要进行哪些横切操作（即哪个通知）。 <br>&nbsp;&nbsp;<a href='http://www.blogjava.net/echo/archive/2007/05/07/115767.html'>阅读全文</a><img src ="http://www.blogjava.net/echo/aggbug/115767.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-05-07 22:27 <a href="http://www.blogjava.net/echo/archive/2007/05/07/115767.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>static的用法</title><link>http://www.blogjava.net/echo/archive/2007/04/27/113954.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Thu, 26 Apr 2007 16:25:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/04/27/113954.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/113954.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/04/27/113954.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/113954.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/113954.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: static的用法&nbsp;&nbsp;<a href='http://www.blogjava.net/echo/archive/2007/04/27/113954.html'>阅读全文</a><img src ="http://www.blogjava.net/echo/aggbug/113954.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-04-27 00:25 <a href="http://www.blogjava.net/echo/archive/2007/04/27/113954.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一些Java异常处理程序的陋习</title><link>http://www.blogjava.net/echo/archive/2007/04/26/113947.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Thu, 26 Apr 2007 15:56:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/04/26/113947.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/113947.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/04/26/113947.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/113947.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/113947.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一些Java异常处理程序的陋习&nbsp;&nbsp;<a href='http://www.blogjava.net/echo/archive/2007/04/26/113947.html'>阅读全文</a><img src ="http://www.blogjava.net/echo/aggbug/113947.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-04-26 23:56 <a href="http://www.blogjava.net/echo/archive/2007/04/26/113947.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>职业规划与高薪之路</title><link>http://www.blogjava.net/echo/archive/2007/04/14/110583.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Sat, 14 Apr 2007 01:23:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/04/14/110583.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/110583.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/04/14/110583.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/110583.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/110583.html</trackback:ping><description><![CDATA[<br><img height=580 alt=职业规划与高薪之路.png src="http://www.blogjava.net/images/blogjava_net/alex/images/职业规划与高薪之路.png" width=1149 border=0>
<div class=postfoot>posted on 2006-12-17 13:25 <a href="http://www.blogjava.net/alex/"><font color=#000080>Alex</font></a> 阅读(2222) <a href="http://www.blogjava.net/alex/archive/2006/12/17/88331.aspx#Post"><font color=#000080>评论(6)</font></a> &nbsp;<a href="http://www.blogjava.net/alex/admin/EditPosts.aspx?postid=88331"><font color=#000080>编辑</font></a>&nbsp;<a href="http://www.blogjava.net/alex/AddToFavorite.aspx?id=88331"><font color=#000080>收藏</font></a> <a href="http://www.blogjava.net/alex/services/trackbacks/88331.aspx"><font color=#000080>引用</font></a> 所属分类: <a href="http://www.blogjava.net/alex/category/5492.html"><font color=#000080>life &amp; reading</font></a> </div>
<img src ="http://www.blogjava.net/echo/aggbug/110583.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-04-14 09:23 <a href="http://www.blogjava.net/echo/archive/2007/04/14/110583.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[ZT]Hibernate + Spring 对DAO的处理实例</title><link>http://www.blogjava.net/echo/archive/2007/04/14/110581.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Sat, 14 Apr 2007 01:18:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/04/14/110581.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/110581.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/04/14/110581.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/110581.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/110581.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: key words : hibernate spring daocome from : http://lpacec.javaeye.com/blog/46220&nbsp;&nbsp;&nbsp;1.&nbsp;&nbsp;package&nbsp;infoweb.dao;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.&nbsp...&nbsp;&nbsp;<a href='http://www.blogjava.net/echo/archive/2007/04/14/110581.html'>阅读全文</a><img src ="http://www.blogjava.net/echo/aggbug/110581.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-04-14 09:18 <a href="http://www.blogjava.net/echo/archive/2007/04/14/110581.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[ZT]Spring数据访问对象(DAO)框架</title><link>http://www.blogjava.net/echo/archive/2007/04/14/110578.html</link><dc:creator>Ecko</dc:creator><author>Ecko</author><pubDate>Sat, 14 Apr 2007 01:11:00 GMT</pubDate><guid>http://www.blogjava.net/echo/archive/2007/04/14/110578.html</guid><wfw:comment>http://www.blogjava.net/echo/comments/110578.html</wfw:comment><comments>http://www.blogjava.net/echo/archive/2007/04/14/110578.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/echo/comments/commentRss/110578.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/echo/services/trackbacks/110578.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: J2EE应用程序中的业务组件通常使用JDBC API访问和更改关系数据库中的持久数据。这经常导致持久性代码与业务逻辑发生混合，这是一种不好的习惯。数据访问对象(DAO)设计模式通过把持久性逻辑分成若干数据访问类来解决这一问题。<br><br>　　本文是一篇关于DAO设计模式的入门文章，突出讲述了它的优点和不足之处。另外，本文还介绍了Spring 2.0 JDBC/DAO框架并示范了它如何妥善地解决传统DAO设计中的缺陷。<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/echo/archive/2007/04/14/110578.html'>阅读全文</a><img src ="http://www.blogjava.net/echo/aggbug/110578.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/echo/" target="_blank">Ecko</a> 2007-04-14 09:11 <a href="http://www.blogjava.net/echo/archive/2007/04/14/110578.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>