??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲情侣偷拍精品,人人狠狠综合久久亚洲婷婷 ,狠狠色婷婷狠狠狠亚洲综合http://www.tkk7.com/ghawk/category/5526.htmlzh-cnTue, 27 Feb 2007 19:10:27 GMTTue, 27 Feb 2007 19:10:27 GMT60Scripting in Mustang 的一点启?/title><link>http://www.tkk7.com/ghawk/archive/2006/09/26/71905.html</link><dc:creator>GHawk</dc:creator><author>GHawk</author><pubDate>Tue, 26 Sep 2006 02:04:00 GMT</pubDate><guid>http://www.tkk7.com/ghawk/archive/2006/09/26/71905.html</guid><wfw:comment>http://www.tkk7.com/ghawk/comments/71905.html</wfw:comment><comments>http://www.tkk7.com/ghawk/archive/2006/09/26/71905.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.tkk7.com/ghawk/comments/commentRss/71905.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/ghawk/services/trackbacks/71905.html</trackback:ping><description><![CDATA[2006 Sun Techdays Shanghai 的第2天下午有一个名为?b>Java Scripting: One VM, Many Languages</b>》的Session?br /><br />Rags为大家展CZMustang的一个新Ҏ(gu),Scripting in Java——脚本语a支持?br /><br />通过加入脚本引擎的支持,p够在Java中解释JavascriptQpythonQruby{诸多脚本语a?br /><br />对于q个Ҏ(gu),惛_的一个可能的应用是在annotation中写脚本语言Q然后在代码中用相应的脚本语a引擎解释执行?br />保留到运行时的annotation可以用实现aop的功能,使用非inline的脚本就可以更灵zd控制aspect的行为?br /><br />比如Q?br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">//inline scripting<br />@ScriptBefore(script</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><img src="http://www.tkk7.com/images/dot.gif" /><img src="http://www.tkk7.com/images/dot.gif" /></span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,language</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">javascript</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> )<br /></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> foo() {<br />   <br />}<br /><br />//non-inline scripting<br />@ScriptBefore(file</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"scripts/logging.js</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,language</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">javascript</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> bar() {<br /><br />}</span></div><br /><img src ="http://www.tkk7.com/ghawk/aggbug/71905.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/ghawk/" target="_blank">GHawk</a> 2006-09-26 10:04 <a href="http://www.tkk7.com/ghawk/archive/2006/09/26/71905.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB 异常处理的最?jng)_?/title><link>http://www.tkk7.com/ghawk/archive/2005/12/10/23249.html</link><dc:creator>GHawk</dc:creator><author>GHawk</author><pubDate>Sat, 10 Dec 2005 03:25:00 GMT</pubDate><guid>http://www.tkk7.com/ghawk/archive/2005/12/10/23249.html</guid><wfw:comment>http://www.tkk7.com/ghawk/comments/23249.html</wfw:comment><comments>http://www.tkk7.com/ghawk/archive/2005/12/10/23249.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/ghawk/comments/commentRss/23249.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/ghawk/services/trackbacks/23249.html</trackback:ping><description><![CDATA[<P> <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0> <TBODY> <TR vAlign=top> <TD width="100%"> <H1><A ><FONT size=2>http://www-128.ibm.com/developerworks/cn/java/j-ejbexcept/</FONT></A> </H1> <H1>EJB 异常处理的最?jng)_?/H1> <P id=subtitle>学习(fn)在基?EJB 的系l上~写可以更快解决问题的代?/P><IMG class=display-img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=1></TD> <TD class=no-print width=192><IMG height=18 alt=developerWorks src="http://www-128.ibm.com/developerworks/i/dw.gif" width=192></TD></TR></TBODY></TABLE> <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0> <TBODY> <TR vAlign=top> <TD width=10><IMG height=1 alt="" src="http://www.ibm.com/i/c.gif" width=10></TD> <TD width="100%"> <TABLE class=no-print cellSpacing=0 cellPadding=0 width=160 align=right border=0> <TBODY> <TR> <TD width=10><IMG height=1 alt="" src="http://www.ibm.com/i/c.gif" width=10></TD> <TD> <TABLE cellSpacing=0 cellPadding=0 width=150 border=0> <TBODY> <TR> <TD class=v14-header-1-small>文档选项</TD></TR></TBODY></TABLE> <TABLE class=v14-gray-table-border cellSpacing=0 cellPadding=0 border=0> <TBODY> <TR> <TD class=no-padding width=150> <TABLE cellSpacing=0 cellPadding=0 width=143 border=0><IMG height=1 alt="" src="http://www.ibm.com/i/c.gif" width=8> <FORM name=email action=https://www-130.ibm.com/developerworks/secure/email-it.jsp><INPUT type=hidden value="随着 J2EE 成ؓ(f)企业开发^C选,来多Z J2EE 的应用程序将投入生。J2EE q_的重要组件之一?Enterprise JavaBeanQEJBQAPI。J2EE ?EJB 技术一h供了许多优点Q但随之而来的还有一些新的挑战。特别是企业pȝQ其中的M问题都必d速得到解冟뀂在本文中,企业 Java ~程老手 Srikanth Shenoy 展现了他?EJB 异常处理斚w的最?jng)_法,q些做法可以更快解决问题? name=body><INPUT type=hidden value="EJB 异常处理的最?jng)_? name=subject><INPUT type=hidden value=cn name=lang> <SCRIPT language=JavaScript type=text/javascript> <!-- document.write('<tr valign="top"><td width="8"><img src="http://www.ibm.com/i/c.gif" width="8" height="1" alt=""/></td><td width="16"><img src="http://www.ibm.com/i/v14/icons/em.gif" height="16" width="16" vspace="3" alt="此作为电(sh)子邮件发? /></td><td width="122"><p><a class="smallplainlink" href="javascript:document.email.submit();"><b>此作为电(sh)子邮件发?/b></a></p></td></tr>'); //--> </SCRIPT> <TBODY> <TR vAlign=top> <TD width=8><IMG height=1 alt="" src="http://www.ibm.com/i/c.gif" width=8></TD> <TD width=16><IMG height=16 alt=此作为电(sh)子邮件发?src="http://www.ibm.com/i/v14/icons/em.gif" width=16 vspace=3></TD> <TD width=122> <P><A class=smallplainlink href="javascript:document.email.submit();"><B><FONT color=#996699 size=2>此作为电(sh)子邮件发?/FONT></B></A></P></TD></TR><NOSCRIPT><tr valign="top"><td width="8"><img alt="" height="1" width="8" src="http://www.ibm.com/i/c.gif"/></td><td width="16"><img alt="" width="16" height="16" src="http://www.ibm.com/i/c.gif"/></td><td class="small" width="122"><p><span id="nozsmuw" class="ast">未显C需?JavaScript 的文档选项</span></p></td></tr></NOSCRIPT></FORM></TBODY></TABLE></TD></TR></TBODY></TABLE><BR> <TABLE cellSpacing=0 cellPadding=0 width=150 border=0> <TBODY> <TR> <TD class=v14-header-1-small>Ҏ(gu)늚评h(hun)</TD></TR></TBODY></TABLE> <TABLE class=v14-gray-table-border cellSpacing=0 cellPadding=0 border=0> <TBODY> <TR> <TD class=no-padding width=150> <TABLE cellSpacing=0 cellPadding=0 width=143 border=0> <TBODY> <TR vAlign=top> <TD width=8><IMG height=1 alt="" src="http://www.ibm.com/i/c.gif" width=8></TD> <TD><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/d_bold.gif" width=16 vspace=3 border=0></TD> <TD width=125> <P><A class=smallplainlink ><B><FONT color=#996699 size=2>帮助我们改进q些内容</FONT></B></A></P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR></TD></TR></TBODY></TABLE> <P>U别: 初</P> <P><A ><FONT color=#996699>Srikanth Shenoy</FONT></A>, J2EE N<BR></P> <P>2002 q?5 ?05 ?/P> <BLOCKQUOTE>随着 J2EE 成ؓ(f)企业开发^C选,来多Z J2EE 的应用程序将投入生。J2EE q_的重要组件之一?Enterprise JavaBeanQEJBQAPI。J2EE ?EJB 技术一h供了许多优点Q但随之而来的还有一些新的挑战。特别是企业pȝQ其中的M问题都必d速得到解冟뀂在本文中,企业 Java ~程老手 Srikanth Shenoy 展现了他?EJB 异常处理斚w的最?jng)_法,q些做法可以更快解决问题?/BLOCKQUOTE> <P>?hello-world 情Ş中,异常处理非常单。每当碰到某个方法的异常Ӟ捕莯异常q打印堆栈跟t或者声明这个方法抛出异常。不q的是,q种办法不以处理现实中出现的各U类型的异常。在生pȝ中,当有异常抛出Ӟ很可能是最l用h法处理他或她的请求。当发生q样的异常时Q最l用户通常希望能这P(x)</P> <UL> <LI>有一条清楚的消息表明已经发生了一个错? <LI>有一个唯一的错误号Q他可以据此讉K可方便获得的客户支持pȝ <LI>问题快速得到解冻Iq且可以信他的h已经得到处理Q或者将在设定的旉D内得到处理 </LI></UL> <P>理想情况下,企业U系l将不仅为客h供这些基本的服务Q还准备好一些必要的后端机制。D例来_(d)客户服务组应该收到x的错误通知Q以便在客户打电(sh)话求助之前服务代表就能意识到问题。此外,服务代表应该能够交叉引用用户的唯一错误号和产品日志Q从而快速识别问??最好是能把问题定位到确切的行号或确切的Ҏ(gu)。ؓ(f)了给最l用户和支持组提供他们需要的工具和服务,在构Z个系l时Q?zhn)必dpȝ被部|后可能出问题的所有地方心中有数?/P> <P>在本文中Q我们将谈谈Z EJB 的系l中的异常处理。我们将从回ּ常处理的基础知识开始,包括日志实用E序的用,然后Q很快就转入?EJB 技术如何定义和理不同cd的异常进行更详细的讨论。此后,我们通过一些代码示例来研究一些常见的异常处理解决Ҏ(gu)的优~点Q我q将展示我自己在充分利用 EJB 异常处理斚w的最?jng)_法?/P> <P>h意,本文假设(zhn)熟(zhn)?J2EE ?EJB 技术。?zhn)应理解实?bean 和会(x)?bean 的差异。如果?zhn)?bean 理的持久性(bean-managed persistenceQBMPQ)(j)和容器管理的持久性(container-managed persistenceQCMPQ)(j)在实?bean 上下文中是什么意思稍有了解,也是有帮助的。请参阅 <A ><FONT color=#996699>参考资?/FONT></A>部分了解关于 J2EE ?EJB 技术的更多信息?</P> <P><A name=1><span id="zlrczxj" class=atitle><FONT face=Arial size=4>异常处理基础知识</FONT></SPAN></A></P> <P>解决pȝ错误的第一步是建立一个与生pȝh相同构造的试pȝQ然后跟t导致抛出异常的所有代码,以及(qing)代码中的所有不同分支。在分布式应用程序中Q很可能是调试器不工作了Q所以,(zhn)可能将?<CODE>System.out.println()</CODE> Ҏ(gu)跟踪异常?<CODE>System.out.println</CODE> 管很方便,但开销巨大。在盘 I/O 期间Q?<CODE>System.out.println</CODE> ?I/O 处理q行同步Q这极大降低了吞吐量。在~省情况下,堆栈跟踪被记录到控制台。但是,在生产系l中Q浏览控制台以查看异常跟t是行不通的。而且Q不能保证堆栈跟t会(x)昄在生产系l中Q因为,?NT 上,pȝ理员可以把 <CODE>System.out</CODE> ?<CODE>System.err</CODE> 映射?<CODE>' '</CODE> Q在 UNIX 上,可以映射?<CODE>dev/null</CODE> 。此外,如果(zhn)把 J2EE 应用E序服务器作?NT 服务q行Q甚至不?x)有控制台。即使?zhn)把控制台日志重定向到一个输出文Ӟ当?J2EE 应用E序服务器重新启动时Q这个文件很可能也将被重写?</P> <TABLE cellSpacing=0 cellPadding=0 width="40%" align=right border=0> <TBODY> <TR> <TD width=10><IMG height=1 alt="" src="http://www.ibm.com/i/c.gif" width=10></TD> <TD> <TABLE cellSpacing=0 cellPadding=5 width="100%" border=1> <TBODY> <TR> <TD bgColor=#eeeeee><A name=sidebar1><B>异常处理的原?/B></A><BR> <P>以下是一些普遍接受的异常处理原则Q? <OL> <LI>如果无法处理某个异常Q那׃要捕获它? <LI>如果捕获了一个异常,请不要胡乱处理它? <LI>量在靠q异常被抛出的地Ҏ(gu)获异常? <LI>在捕获异常的地方它记录到日志中Q除非?zhn)打算它重新抛出? <LI>按照(zhn)的异常处理必须多精l来构造?zhn)的方法? <LI>需要用几种cd的异常就用几U,其是对于应用程序异常?</LI></OL><BR>W?1 Ҏ(gu)然与W?3 点相抵触。实际的解决Ҏ(gu)是以下两者的折衷Q?zhn)在距异常被抛出多q的地方它捕获Q在完全丢失原始异常的意图或内容之前Q?zhn)可以让异常落在多q的地方? <P></P> <P><B>?/B>Q尽这些原则的应用遍及(qing)所?EJB 异常处理机制Q但它们q不是特别针?EJB 异常处理的?</P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE> <P>׃以上q些原因Q把代码l装成品ƈ同时包含 <CODE>System.out.println</CODE> q不是一U选择。在试期间使用 <CODE>System.out.println</CODE> Q然后在形成产品之前除去 <CODE>System.out.println</CODE> 也不是上{,因ؓ(f)q样做意味着(zhn)的产品代码与测试代码运行得不尽相同。?zhn)需要的是一U声明控制日志机Ӟ以(zhn)的试代码和品代码相同,q且当记录日志以声明方式关闭Ӟl品带来的性能开销最?</P> <P>q里的解x案显然是使用一个日志实用程序。采用恰当的~码U定Q日志实用程序将负责_地记录下Mcd的消息,不论是系l错误还是一些警告。所以,我们在q一步讲qC前谈谈日志实用程序?/P> <P><A name=N100BE><span id="xtlfwky" class=smalltitle><STRONG><FONT face=Arial>日志领域Q鸟?/FONT></STRONG></SPAN></A></P> <P>每个大型应用E序在开发、测试及(qing)产品周期中都使用日志实用E序。在今天的日志领域中Q有几个角逐者,其中有两个广Zh知。一个是 Log4JQ它是来?Apache ?Jakarta 的一个开放源代码的项目。另一个是 J2SE 1.4 捆绑提供的,它是最q刚加入到这个行列的。我们将使用 Log4J 说明本文所讨论的最?jng)_法;但是Q这些最?jng)_法ƈ不特别依赖于 Log4J?/P> <P>Log4J 有三个主要组Ӟ(x)layout、appender ?category?<I>Layou</I>代表消息被记录到日志中的格式?<I>appender</I>是消息将被记录到的物理位|的别名。?<I>category</I>则是有名U的实体Q?zhn)可以把它当作是日志的句柄。layout ?appender ?XML 配置文g中声明。每?category 带有它自q layout ?appender 定义。当(zhn)获取了一?category q把消息记录到它那里Ӟ消息在与?category 相关联的各个 appender 处结束,q且所有这些消息都以 XML 配置文g中指定的 layout 格式表示?</P> <P>Log4J l消息指定四U优先Q它们是 ERROR、WARN、INFO ?DEBUG。ؓ(f)便于本文的讨论,所有异帔R以具?ERROR 优先U记录。当记录本文中的一个异常时Q我们将能够扑ֈ获取 categoryQ?<CODE>Category.getInstance(String name)</CODE> Ҏ(gu)Q的代码Q然后调用方?<CODE>category.error()</CODE> Q它与具?ERROR 优先U的消息相对应)(j)?</P> <P>管日志实用E序能帮助我们把消息记录到适当的持久位|,但它们ƈ不能栚w问题。它们不能从产品日志中精找出某个客L(fng)问题报告Q这一便利技术留l?zhn)把它构徏到(zhn)正在开发的pȝ中?/P> <P>要了解关?Log4J 日志实用E序?J2SE 所带的日志实用E序的更多信息,请参?<A ><FONT color=#996699>参考资?/FONT></A>部分?</P> <P><A name=N100E8><span id="rwtkqiw" class=smalltitle><STRONG><FONT face=Arial>异常的类?/FONT></STRONG></SPAN></A></P> <P>异常的分cL不同方式。这里,我们讨Z EJB 的角度如何对异常q行分类。EJB 规范?yu)异常大致分成三c:(x)</P> <UL> <LI><B>JVM 异常</B>Q这U类型的异常?JVM 抛出?<CODE>OutOfMemoryError</CODE> 是 JVM 异常的一个常见示例。对 JVM 异常(zhn)无能ؓ(f)力。它们表明一U致命的情况。唯一得体的退出办法是停止应用E序服务器(可能要增加硬件资源)(j)Q然后重新启动系l?<BR> <LI><B>应用E序异常</B>Q应用程序异常是一U定制异常,由应用程序或W三方的库抛出。这些本质上是受查异常(checked exceptionQ;它们预示了业务逻辑中的某个条g未满。在q样的情况下QEJB Ҏ(gu)的调用者可以得体地处理q种局面ƈ采用另一条备用途径?<BR> <LI><B>pȝ异常</B>Q在大多数情况下Q系l异常由 JVM 作ؓ(f) <CODE>RuntimeException</CODE> 的子cL出。例如, <CODE>NullPointerException</CODE> ?<CODE>ArrayOutOfBoundsException</CODE> 因代码中的错误而被抛出。另一U类型的pȝ异常在系l碰到配|不当的资源Q例如,拼写错误?JNDI 查找QJNDI lookupQ)(j)时发生。在q种情况下,pȝ将抛出一个受查异常。捕莯些受查系l异常ƈ它们作为非受查异常Qunchecked exceptionQ抛出颇有意义。最重要的规则是Q如果?zhn)?gu)个异常无能ؓ(f)力,那么它就是一个系l异常ƈ且应当作为非受查异常抛出?</LI></UL> <P><B>?/B>Q?<I>受查异常</I>是一个作?<CODE>java.lang.Exception</CODE> 的子cȝ Java cR通过?<CODE>java.lang.Exception</CODE> z子类Q就强制(zhn)在~译时捕莯个异常。相反地Q?<I>非受查异?/I>则是一个作?<CODE>java.lang.RuntimeException</CODE> 的子cȝ Java cR从 <CODE>java.lang.RuntimeException</CODE> z子类保了编译器不会(x)强制(zhn)捕莯个异常?</P><BR> <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0> <TBODY> <TR> <TD><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"></TD></TR></TBODY></TABLE> <TABLE class=no-print cellSpacing=0 cellPadding=0 align=right> <TBODY> <TR align=right> <TD> <TABLE cellSpacing=0 cellPadding=0 border=0> <TBODY> <TR> <TD vAlign=center><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></TD> <TD vAlign=top align=right><A class=fbox ><B><FONT color=#996699>回页?/FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR> <P><A name=2><span id="yfhniav" class=atitle><FONT face=Arial size=4>EJB 容器怎样处理异常</FONT></SPAN></A></P> <P>EJB 容器拦截 EJB lg上的每一个方法调用。结果,Ҏ(gu)调用中发生的每一个异怹?EJB 容器拦截到。EJB 规范只处理两U类型的异常Q应用程序异常和pȝ异常?/P> <P>EJB 规范?<I>应用E序异常</I>定义为在q程接口中的Ҏ(gu)说明上声明的M异常Q而不?<CODE>RemoteException</CODE> Q。应用程序异常是业务工作中的一U特D情形。当q种cd的异常被抛出Ӟ客户Z(x)得到一个恢复选项Q这个选项通常是要求以一U不同的方式处理h。不q,qƈ不意味着M在远E接口方法的 <CODE>throws</CODE> 子句中声明的非受查异帔R?x)被当作应用E序异常对待。EJB 规范明确指出Q应用程序异怸应?<CODE>RuntimeException</CODE> 或它的子cR?</P> <P>当发生应用程序异常时Q除非被昑ּ要求Q通过调用兌?<CODE>EJBContext</CODE> 对象?<CODE>setRollbackOnly()</CODE> Ҏ(gu)Q回滚事务,否则 EJB 容器׃?x)这样做。事实上Q应用程序异常被保证以它原本的状态传送给客户机:(x)EJB 容器l不?x)以M方式包装或修改异常?</P> <P><I>pȝ异常</I>被定义ؓ(f)受查异常或非受查异常QEJB Ҏ(gu)不能从这U异常恢复。当 EJB 容器拦截到非受查异常Ӟ它会(x)回滚事务q执行Q何必要的清理工作。接着Q它把该非受查异常包装到 <CODE>RemoteException</CODE> 中,然后抛给客户机。这PEJB 容器把所有非受查异常作ؓ(f) <CODE>RemoteException</CODE> Q或者作为其子类Q例?<CODE>TransactionRolledbackException</CODE> Q提供给客户机?</P> <P>对于受查异常的情况,容器q不?x)自动执行上面所描述的内务处理。要使用 EJB 容器的内部内务处理,(zhn)将必须把受查异怽为非受查异常抛出。每当发生受查系l异常(?<CODE>NamingException</CODE> Q时Q?zhn)都应该通过包装原始的异常抛?<CODE>javax.ejb.EJBException</CODE> 或其子类。因?<CODE>EJBException</CODE> 本n是非受查异常Q所以不需要在Ҏ(gu)?<CODE>throws</CODE> 子句中声明它。EJB 容器捕获 <CODE>EJBException</CODE> 或其子类Q把它包装到 <CODE>RemoteException</CODE> 中,然后?<CODE>RemoteException</CODE> 抛给客户机?</P> <P>虽然pȝ异常由应用程序服务器记录Q这?EJB 规范规定的)(j)Q但记录格式因应用E序服务器的不同而异。ؓ(f)了访问所需的统计信息,企业常常需要对所生成的日志运?shell/Perl 脚本。ؓ(f)了确保记录格式的l一Q在(zhn)的代码中记录异怼(x)更好些?/P> <P><B>?/B>QEJB 1.0 规范要求把受查系l异怽?<CODE>RemoteException</CODE> 抛出。从 EJB 1.1 规范赯?EJB 实现cȝ不应抛出 <CODE>RemoteException</CODE> ?</P><BR> <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0> <TBODY> <TR> <TD><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"></TD></TR></TBODY></TABLE> <TABLE class=no-print cellSpacing=0 cellPadding=0 align=right> <TBODY> <TR align=right> <TD> <TABLE cellSpacing=0 cellPadding=0 border=0> <TBODY> <TR> <TD vAlign=center><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></TD> <TD vAlign=top align=right><A class=fbox ><B><FONT color=#996699>回页?/FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR> <P><A name=3><span id="gnevmas" class=atitle><FONT face=Arial size=4>常见的异常处理策?/FONT></SPAN></A></P> <P>如果没有异常处理{略Q项目小l的不同开发者很可能?x)编写以不同方式处理异常的代码。由于同一个异常在pȝ的不同地方可能以不同的方式被描述和处理,所以,q至会(x)使品支持小l感到迷惑。缺乏策略还?x)导致在整个pȝ的多个地斚w有记录。日志应该集中v来或者分成几个可理的单元。理想的情况是,应在可能少的地方记录异常日志,同时不损失内宏V在q一部分?qing)其后的几个部分Q我展C可以在整个企业pȝ中以l一的方式实现的~码{略。?zhn)可以?<A ><FONT color=#996699>参考资?/FONT></A>部分下蝲本文开发的实用E序cR?</P> <P>清单 1 昄了来自会(x)?EJB lg的一个方法。这个方法删除某个客户在特定日期前所下的全部订单。首先,它获?<CODE>OrderEJB</CODE> ?Home 接口。接着Q它取回某个特定客户的所有订单。当它碰到在某个特定日期之前所下的订单Ӟ删除所订购的商品,然后删除订单本n。请注意Q抛Z三个异常Q显CZ三种常见的异常处理做法。(为简单v见,假设~译器优化未被用。)(j) </P><BR><A name=code1><B>清单 1. 三种常见的异常处理做?/B></A><BR> <TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <TBODY> <TR> <TD><PRE><CODE class=section> <FONT face="Lucida Console">100 try { 101 OrderHome homeObj = EJBHomeFactory.getInstance().getOrderHome(); 102 Collection orderCollection = homeObj.findByCustomerId(id); 103 iterator orderItter = orderCollection.iterator(); 104 while (orderIter.hasNext()) { 105 Order orderRemote = (OrderRemote) orderIter.getNext(); 106 OrderValue orderVal = orderRemote.getValue(); 107 if (orderVal.getDate() < "mm/dd/yyyy") { 108 OrderItemHome itemHome = EJBHomeFactory.getInstance().getItemHome(); 109 Collection itemCol = itemHome.findByOrderId(orderId) 110 Iterator itemIter = itemCol.iterator(); 111 while (itemIter.hasNext()) { 112 OrderItem item = (OrderItem) itemIter.getNext(); 113 item.remove(); 114 } 115 orderRemote.remove(); 116 } 117 } 118 } catch (NamingException ne) { 119 throw new EJBException("Naming Exception occurred"); 120 } catch (FinderException fe) { 121 fe.printStackTrace(); 122 throw new EJBException("Finder Exception occurred"); 123 } catch (RemoteException re) { 124 re.printStackTrace(); 125 //Some code to log the message 126 throw new EJBException(re); 127 } </FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR> <P>现在Q让我们用上面所C的代码来研I一下所展示的三U异常处理做法的~点?/P> <P><B>抛出Q重抛出带有出错消息的异?/B> <BR><CODE>NamingException</CODE> 可能发生在行 101 或行 108。当发生 <CODE>NamingException</CODE> Ӟq个Ҏ(gu)的调用者就得到 <CODE>RemoteException</CODE> q向后跟t该异常到行 119。调用者ƈ不能告知 <CODE>NamingException</CODE> 实际是发生在?101 q是?108。由于异常内容要直到被记录了才能得到保护Q所以,q个问题的根源很难查出。在q种情Ş下,我们p异常的内容被“吞掉”了。正如这个示例所C,抛出或重抛出一个带有消息的异常q不是一U好的异常处理解军_法?</P> <P><B>记录到控制台q抛Z个异?/B> <BR><CODE>FinderException</CODE> 可能发生在行 102 ?109。不q,׃异常被记录到控制収ͼ所以仅当控制台可用时调用者才能向后跟t到?102 ?109。这昄不可行,所以异常只能被向后跟踪到行 122。这里的推理同上?</P> <P><B>包装原始的异总保护其内?/B> <BR><CODE>RemoteException</CODE> 可能发生在行 102?06?09?13 ?115。它在行 123 ?<CODE>catch</CODE> 块被捕获。接着Q这个异常被包装?<CODE>EJBException</CODE> 中,所以,不论调用者在哪里记录它,它都能保持完整。这U办法比前面两种办法更好Q同时演CZ没有日志{略的情c(din)如?<CODE>deleteOldOrders()</CODE> Ҏ(gu)的调用者记录该异常Q那么将D重复记录。而且Q尽有了日志记录,但当客户报告某个问题Ӟ产品日志或控制台q不能被交叉引用?</P><BR> <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0> <TBODY> <TR> <TD><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"></TD></TR></TBODY></TABLE> <TABLE class=no-print cellSpacing=0 cellPadding=0 align=right> <TBODY> <TR align=right> <TD> <TABLE cellSpacing=0 cellPadding=0 border=0> <TBODY> <TR> <TD vAlign=center><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></TD> <TD vAlign=top align=right><A class=fbox ><B><FONT color=#996699>回页?/FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR> <P><A name=4><span id="iacxzcf" class=atitle><FONT face=Arial size=4>EJB 异常处理探试?/FONT></SPAN></A></P> <P>EJB lg应抛出哪些异常?(zhn)应它们记录到pȝ中的什么地方?q两个问题盘栚wl、相互联p,应该一赯冟뀂解军_法取决于以下因素Q?/P> <UL> <LI><B>(zhn)的 EJB pȝ设计</B>Q在良好?EJB 设计中,客户机绝不调用实?EJB lg上的Ҏ(gu)。多数实?EJB Ҏ(gu)调用发生在会(x)?EJB lg中。如果?zhn)的设计遵循这些准则,则(zhn)应该用?x)?EJB lg来记录异常。如果客h直接调用了实?EJB Ҏ(gu)Q则(zhn)还应该把消息记录到实体 EJB lg中。然而,存在一个难题:(x)相同的实?EJB Ҏ(gu)可能也会(x)被会(x)?EJB lg调用。在q种情Ş下,如何避免重复记录呢?cM圎ͼ当一个会(x)?EJB lg调用其它实体 EJB Ҏ(gu)Ӟ(zhn)如何避免重复记录呢Q很快我们就探讨一U处理这两种情况的通用解决Ҏ(gu)。(h意,EJB 1.1 q未从体pȝ构上L客户用实?EJB lg上的Ҏ(gu)。在 EJB 2.0 中,(zhn)可以通过为实?EJB lg定义本地接口规定q种限制。)(j) <BR><BR> <LI><B>计划的代码重用范?/B>Q这里的问题是?zhn)是打把日志代码d到多个地方,q是打算重新设计、重新构造代码来减少日志代码?<BR><BR> <LI><B>(zhn)要Z服务的客h的类?/B>Q考虑(zhn)是ؓ(f) J2EE Web 层、单?Java 应用E序、PDA q是ؓ(f)其它客户机服务是很重要的。Web 层设计有各种形状和大。如果?zhn)在用命令(CommandQ模式,在这个模式中QW(xu)eb 层通过每次传入一个不同的命o(h)调用 EJB 层中的相同方法,那么Q把异常记录到命令在其中执行?EJB lg中是很有用的。在多数其它?Web 层设计中Q把异常记录?Web 层本w要更容易,也更好,因ؓ(f)(zhn)需要把异常日志代码d到更的地方。如果?zhn)?Web 层和 EJB 层在同一地方q且不需要支持Q何其它类型的客户机,那么应该考虑后一U选择?<BR><BR> <LI><B>(zhn)将处理的异常的cdQ应用程序或pȝQ?/B>Q处理应用程序异怸处理pȝ异常有很大不同。系l异常的发生不受 EJB 开发者意囄控制。因为系l异常的含义不清楚,所以内容应指明异常的上下文。?zhn)已经看到了,通过对原始异常进行包装ɘq个问题得到了最好的处理。另一斚wQ应用程序异常是?EJB 开发者显式抛出的Q通常包装有一条消息。因为应用程序异常的含义清楚Q所以没有理p保护它的上下文。这U类型的异常不必记录?EJB 层或客户机层Q它应该以一U有意义的方式提供给最l用P带上指向所提供的解x案的另一条备用途径。系l异常消息没必要Ҏ(gu)l用户很有意义?</LI></UL><BR> <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0> <TBODY> <TR> <TD><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"></TD></TR></TBODY></TABLE> <TABLE class=no-print cellSpacing=0 cellPadding=0 align=right> <TBODY> <TR align=right> <TD> <TABLE cellSpacing=0 cellPadding=0 border=0> <TBODY> <TR> <TD vAlign=center><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></TD> <TD vAlign=top align=right><A class=fbox ><B><FONT color=#996699>回页?/FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR> <P><A name=5><span id="adbkbpz" class=atitle><FONT face=Arial size=4>处理应用E序异常</FONT></SPAN></A></P> <P>在这一部分?qing)其后的几个部分中,我们更仔细地研I用 EJB 异常处理应用E序异常和系l异常,以及(qing) Web 层设计。作个讨论的一部分Q我们将探讨处理从会(x)话和实体 EJB lg抛出的异常的不同方式?/P> <P><B>实体 EJB lg中的应用E序异常</B> <BR>清单 2 昄了实?EJB 的一?<CODE>ejbCreate()</CODE> Ҏ(gu)。这个方法的调用者传入一?<CODE>OrderItemValue</CODE> q请求创Z?<CODE>OrderItem</CODE> 实体。因?<CODE>OrderItemValue</CODE> 没有名称Q所以抛Z <CODE>CreateException</CODE> ?</P><BR><A name=code2><B>清单 2. 实体 EJB lg中的h ejbCreate() Ҏ(gu)</B></A><BR> <TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <TBODY> <TR> <TD><PRE><CODE class=section> <FONT face="Lucida Console">public Integer ejbCreate(OrderItemValue value) throws CreateException { if (value.getItemName() == null) { throw new CreateException("Cannot create Order without a name"); } .. .. return null; } </FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR> <P>清单 2 昄?<CODE>CreateException</CODE> 的一个很典型的用法。类似地Q如果方法的输入参数的g正确Q则查找E序Ҏ(gu)抛?<CODE>FinderException</CODE> ?</P> <P>然而,如果(zhn)在使用容器理的持久性(CMPQ,则开发者无法控制查扄序方法,从?<CODE>FinderException</CODE> 永远不会(x)?CMP 实现抛出。尽如此,?Home 接口的查扄序方法的 <CODE>throws</CODE> 子句中声?<CODE>FinderException</CODE> q是要更好一些?<CODE>RemoveException</CODE> 是另一个应用程序异常,它在实体被删除时被抛出?</P> <P>从实?EJB lg抛出的应用程序异常基本上限定三种cdQ?<CODE>CreateException</CODE> ?<CODE>FinderException</CODE> ?<CODE>RemoveException</CODE> Q及(qing)它们的子cR多数应用程序异帔R来源于会(x)?EJB lgQ因为那里是作出决策的地斏V实?EJB lg一般是哑类Q它们的唯一职责是创徏和取回数据?</P> <P><B>?x)?EJB lg中的应用E序异常</B> <BR>清单 3 昄了来自会(x)?EJB lg的一个方法。这个方法的调用者设法订?<I>n</I> 件某特定cd的某商品?<CODE>SessionEJB()</CODE> Ҏ(gu)计算Z库中的数量不够,于是抛出 <CODE>NotEnoughStockException</CODE> ?<CODE>NotEnoughStockException</CODE> 适用于特定于业务的场合;当抛Zq个异常Ӟ调用者会(x)得到采用另一个备用途径的徏议,让他订购更少数量的商品?</P><BR><A name=code3><B>清单 3. ?x)?EJB lg中的h容器回调Ҏ(gu)</B></A><BR> <TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <TBODY> <TR> <TD><PRE><CODE class=section> <FONT face="Lucida Console">public ItemValueObject[] placeOrder(int n, ItemType itemType) throws NotEnoughStockException { //Check Inventory. Collection orders = ItemHome.findByItemType(itemType); if (orders.size() < n) { throw NotEnoughStockException("Insufficient stock for " + itemType); } } </FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR><BR> <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0> <TBODY> <TR> <TD><FONT face="Lucida Console"><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"></FONT></TD></TR></TBODY></TABLE> <TABLE class=no-print cellSpacing=0 cellPadding=0 align=right> <TBODY> <TR align=right> <TD> <TABLE cellSpacing=0 cellPadding=0 border=0> <TBODY> <TR> <TD vAlign=center><FONT face="Lucida Console"><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></FONT></TD> <TD vAlign=top align=right><A class=fbox ><B><FONT color=#996699>回页?/FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR> <P><A name=6><span id="ftdulsg" class=atitle><FONT face=Arial size=4>处理pȝ异常</FONT></SPAN></A></P> <P>pȝ异常处理是比应用E序异常处理更ؓ(f)复杂的论题。由于会(x)?EJB lg和实?EJB lg处理pȝ异常的方式相|所以,对于本部分的所有示例,我们都将着重于实体 EJB lgQ不q请CQ其中的大部分示例也适用于处理会(x)?EJB lg?/P> <P>当引用其?EJB q程接口Ӟ实体 EJB lg?x)碰?<CODE>RemoteException</CODE> Q而查扑օ?EJB lgӞ则会(x)到 <CODE>NamingException</CODE> Q如果?bean 理的持久性(BMPQ,则会(x)到 <CODE>SQLException</CODE> 。与q些cM的受查系l异常应该被捕获q作?<CODE>EJBException</CODE> 或它的一个子cL出。原始的异常应被包装h。清?4 昄了一U处理系l异常的办法Q这U办法与处理pȝ异常?EJB 容器的行Z致。通过包装原始的异常ƈ在实?EJB lg中将它重新抛出,(zhn)就保了能够在惌录它的时候访问该异常?</P><BR><A name=code4><B>清单 4. 处理pȝ异常的一U常见方?/B></A><BR> <TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <TBODY> <TR> <TD><PRE><CODE class=section> <FONT face="Lucida Console">try { OrderHome orderHome = EJBHomeFactory.getInstance().getOrderHome(); Order order = orderHome.findByPrimaryKey(Integer id); } catch (NamingException ne) { throw new EJBException(ne); } catch (SQLException se) { throw new EJBException(se); } catch (RemoteException re) { throw new EJBException(re); } </FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR> <P><A name=N102CE><span id="ahfhymh" class=smalltitle><STRONG><FONT face=Arial>避免重复记录</FONT></STRONG></SPAN></A></P> <P>通常Q异常记录发生在?x)?EJB lg中。但如果直接?EJB 层外部访问实?EJB lgQ又?x)怎么样呢Q要是这P(zhn)就不得不在实体 EJB lg中记录异常ƈ抛出它。这里的问题是,调用者没办法知道异常是否已经被记录,因而很可能再次记录它,从而导致重复记录。更重要的是Q调用者没办法讉K初始记录时所生成的唯一的标识。Q何没有交叉引用机制的记录都是毫无用处的?/P> <P>误(g)虑q种最p糕的情形:(x)单机 Java 应用E序讉K了实?EJB lg中的一个方?<CODE>foo()</CODE> 。在一个名?<CODE>bar()</CODE> 的会(x)?EJB Ҏ(gu)中也讉K了同一个方法。一?Web 层客h调用?x)?EJB lg的方?<CODE>bar()</CODE> q也记录了该异常。如果当?Web 层调用会(x)?EJB Ҏ(gu) <CODE>bar()</CODE> 时在实体 EJB Ҏ(gu) <CODE>foo()</CODE> 中发生了一个异常,则该异常被记录C个地方:(x)先是在实?EJB lgQ然后是在会(x)?EJB lgQ最后是?Web 层。而且Q没有一个堆栈跟t可以被交叉引用Q?</P> <P>q运的是Q解册些问题用常规办法可以很Ҏ(gu)地做到。?zhn)所需要的只是一U机Ӟ使调用者能够:(x)</P> <UL> <LI>讉K唯一的标? <LI>查明异常是否已经被记录了 </LI></UL> <P>(zhn)可以派?<CODE>EJBException</CODE> 的子cL存储q样的信息。清?5 昄?<CODE>LoggableEJBException</CODE> 子类Q?</P><BR><A name=code5><B>清单 5. LoggableEJBException ?EJBException 的一个子c?/B></A><BR> <TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <TBODY> <TR> <TD><PRE><CODE class=section> <FONT face="Lucida Console">public class LoggableEJBException extends EJBException { protected boolean isLogged; protected String uniqueID; public LoggableEJBException(Exception exc) { super(exc); isLogged = false; uniqueID = ExceptionIDGenerator.getExceptionID(); } .. .. } </FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR> <P>c?<CODE>LoggableEJBException</CODE> 有一个指C符标志Q?<CODE>isLogged</CODE> Q,用于(g)查异常是否已l被记录了。每当捕获一?<CODE>LoggableEJBException</CODE> Ӟ看一下该异常是否已经被记录了Q?<CODE>isLogged == false</CODE> Q。如?isLogged ?falseQ则记录该异常ƈ把标志设|ؓ(f) <CODE>true</CODE> ?</P> <P><CODE>ExceptionIDGenerator</CODE> cȝ当前旉和机器的L名ؓ(f)异常生成唯一的标识。如果?zhn)喜欢Q也可以用有惌力的法来生成这个唯一的标识。如果?zhn)在实?EJB lg中记录了异常Q则q个异常不?x)在别的地方被记录。如果?zhn)没有记录在实?EJB lg中抛Z <CODE>LoggableEJBException</CODE> Q则q个异常被记录C(x)?EJB lg中,但不记录?Web 层中?</P> <P>?6 昄了用这一技术重写后的清?4。?zhn)q可以?<CODE>LoggableException</CODE> 以适合于?zhn)的需要(通过l异常指定错误代码等Q?</P><BR><A name=code6><B>清单 6. 使用 LoggableEJBException 的异常处?/B></A><BR> <TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <TBODY> <TR> <TD><PRE><CODE class=section> <FONT face="Lucida Console">try { OrderHome orderHome = EJBHomeFactory.getInstance().getOrderHome(); Order order = orderHome.findByPrimaryKey(Integer id); } catch (NamingException ne) { throw new LoggableEJBException(ne); } catch (SQLException se) { throw new LoggableEJBException(se); } catch (RemoteException re) { Throwable t = re.detail; if (t != null && t instanceof Exception) { throw new LoggableEJBException((Exception) re.detail); } else { throw new LoggableEJBException(re); } } </FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR> <P><A name=N10342><span id="vjegxpd" class=smalltitle><STRONG><FONT face=Arial>记录 RemoteException</FONT></STRONG></SPAN></A></P> <P>从清?6 中,(zhn)可以看?naming ?SQL 异常在被抛出前被包装C <CODE>LoggableEJBException</CODE> 中。但 <CODE>RemoteException</CODE> 是以一U稍有不??而且要稍微花Ҏ(gu)??的方式处理的? <TABLE cellSpacing=0 cellPadding=0 width="40%" align=right border=0> <TBODY> <TR> <TD width=10><IMG height=1 alt="" src="http://www.ibm.com/i/c.gif" width=10></TD> <TD> <TABLE cellSpacing=0 cellPadding=5 width="100%" border=1> <TBODY> <TR> <TD bgColor=#eeeeee><A name=sidebar2><B>?x)?EJB lg中的pȝ异常</B></A><BR> <P>如果(zhn)决定记录会(x)?EJB 异常Q请使用 <A ><FONT color=#996699>清单 7</FONT></A>所C的记录代码Q否则,h出异常,?<A ><FONT color=#996699>清单 6</FONT></A>所C。?zhn)应该注意刎ͼ会(x)?EJB lg处理异常可有一U与实体 EJB lg不同的方式:(x)因ؓ(f)大多?EJB pȝ都只能从 Web 层访问,而且?x)?EJB 可以作ؓ(f) EJB 层的虚包Q所以,把会(x)?EJB 异常的记录推q到 Web 层实际上是有可能做到的?</P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>它之所以不同,是因为在 <CODE>RemoteException</CODE> 中,实际的异常将被存储到一个称?<CODE>detail</CODE> Q它?<CODE>Throwable</CODE> cd的)(j)的公共属性中。在大多数情况下Q这个公共属性保存有一个异常。如果?zhn)调?<CODE>RemoteException</CODE> ?<CODE>printStackTrace</CODE> Q则除打?detail 的堆栈跟t之外,它还?x)打印异常本w的堆栈跟踪。?zhn)不需要像q样?<CODE>RemoteException</CODE> 的堆栈跟t?</P> <P>Z把?zhn)的应用程序代码从错综复杂的代码(例?<CODE>RemoteException</CODE> 的代码)(j)中分d来,q些行被重新构造成一个称?<CODE>ExceptionLogUtil</CODE> 的类。有了这个类Q?zhn)所要做的只是每当需要创?<CODE>LoggableEJBException</CODE> 时调?<CODE>ExceptionLogUtil.createLoggableEJBException(e)</CODE> 。请注意Q在清单 6 中,实体 EJB lgq没有记录异常;不过Q即便?zhn)军_在实?EJB lg中记录异常,q个解决Ҏ(gu)仍然行得通。清?7 昄了实?EJB lg中的异常记录Q?</P><BR><A name=code7><B>清单 7. 实体 EJB lg中的异常记录</B></A><BR> <TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <TBODY> <TR> <TD><PRE><CODE class=section> <FONT face="Lucida Console">try { OrderHome orderHome = EJBHomeFactory.getInstance().getOrderHome(); Order order = orderHome.findByPrimaryKey(Integer id); } catch (RemoteException re) { LoggableEJBException le = ExceptionLogUtil.createLoggableEJBException(re); String traceStr = StackTraceUtil.getStackTrace(le); Category.getInstance(getClass().getName()).error(le.getUniqueID() + ":" + traceStr); le.setLogged(true); throw le; } </FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR> <P>(zhn)在清单 7 中看到的是一个非常简单明了的异常记录机制。一旦捕获受查系l异常就创徏一个新?<CODE>LoggableEJBException</CODE> 。接着Q用类 <CODE>StackTraceUtil</CODE> 获取 LoggableEJBException 的堆栈跟t,把它作ؓ(f)一个字W串。然后,使用 Log4J category 把该字符串作Z个错误加以记录?</P> <P><A name=N103A7><span id="btvqsgn" class=smalltitle><STRONG><FONT face=Arial>StackTraceUtil cȝ工作原理</FONT></STRONG></SPAN></A></P> <P>在清?7 中,(zhn)看C一个新的称?<CODE>StackTraceUtil</CODE> 的类。因?Log4J 只能记录 <CODE>String</CODE> 消息Q所以这个类负责解决把堆栈跟t{换成 <CODE>String</CODE> 的问题。清?8 说明?<CODE>StackTraceUtil</CODE> cȝ工作原理Q?</P><BR><A name=code8><B>清单 8. StackTraceUtil c?/B></A><BR> <TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <TBODY> <TR> <TD><PRE><CODE class=section> <FONT face="Lucida Console">public class StackTraceUtil { public static String getStackTrace(Exception e) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); return sw.toString(); } .. .. } </FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR> <P><CODE>java.lang.Throwable</CODE> 中缺省的 <CODE>printStackTrace()</CODE> Ҏ(gu)把出错消息记录到 <CODE>System.err</CODE> ?<CODE>Throwable</CODE> q有一个重载的 <CODE>printStackTrace()</CODE> Ҏ(gu)Q它把出错消息记录到 <CODE>PrintWriter</CODE> ?<CODE>PrintStream</CODE> 。上面的 <CODE>StackTraceUtil</CODE> 中的Ҏ(gu)?<CODE>StringWriter</CODE> 包装?<CODE>PrintWriter</CODE> 中。当 <CODE>PrintWriter</CODE> 包含有堆栈跟t时Q它只是调用 <CODE>StringWriter</CODE> ?<CODE>toString()</CODE> Q以获取该堆栈跟t的 <CODE>String</CODE> 表示?</P><BR> <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0> <TBODY> <TR> <TD><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"></TD></TR></TBODY></TABLE> <TABLE class=no-print cellSpacing=0 cellPadding=0 align=right> <TBODY> <TR align=right> <TD> <TABLE cellSpacing=0 cellPadding=0 border=0> <TBODY> <TR> <TD vAlign=center><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></TD> <TD vAlign=top align=right><A class=fbox ><B><FONT color=#996699>回页?/FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR> <P><A name=7><span id="mxvxkjb" class=atitle><FONT face=Arial size=4>Web 层的 EJB 异常处理</FONT></SPAN></A></P> <P>?Web 层设计中Q把异常记录机制攑ֈ客户机端往往更容易也更高效。要能做到这一点,W(xu)eb 层就必须?EJB 层的唯一客户机。此外,W(xu)eb 层必d立在以下模式或框架之一的基上:(x)</P> <UL> <LI><B>模式</B>Q业务委z(Business DelegateQ、FrontController 或拦截过滤器QIntercepting FilterQ? <LI><B>框架</B>QStruts 或Q何包含层ơ结构的cM?MVC 框架的框?</LI></UL> <P>Z么异常记录应该在客户机端上发生呢Q嗯Q首先,控制未传到应用E序服务器之外。所谓的客户机层?J2EE 应用E序服务器本w上q行Q它?JSP c(din)servlet 或它们的助手cȝ成。其ơ,在设计良好的 Web 层中的类有一个层ơ结构(例如Q在业务委派QBusiness DelegateQ类、拦截过滤器QIntercepting FilterQ类、http h处理E序Qhttp request handlerQ类?JSP 基类QJSP base classQ中Q或者在 Struts Action cMQ,或?FrontController servlet 形式的单点调用。这些层ơ结构的基类或?Controller cM的中央点可能包含有异常记录代码。对于基于会(x)?EJB 记录的情况,EJB lg中的每一个方法都必须h记录代码。随着业务逻辑的增加,?x)?EJB Ҏ(gu)的数量也?x)增加,记录代码的数量也会(x)增加。Web 层系l将需要更的记录代码。如果?zhn)?Web 层和 EJB 层在同一地方q且不需要支持Q何其它类型的客户机,那么(zhn)应该考虑q一备用Ҏ(gu)。不怎样Q记录机制不?x)改变;?zhn)可以用与前面的部分所描述的相同技术?/P><BR> <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0> <TBODY> <TR> <TD><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"></TD></TR></TBODY></TABLE> <TABLE class=no-print cellSpacing=0 cellPadding=0 align=right> <TBODY> <TR align=right> <TD> <TABLE cellSpacing=0 cellPadding=0 border=0> <TBODY> <TR> <TD vAlign=center><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></TD> <TD vAlign=top align=right><A class=fbox ><B><FONT color=#996699>回页?/FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR> <P><A name=8><span id="dvbhrji" class=atitle><FONT face=Arial size=4>真实世界的复杂?/FONT></SPAN></A></P> <P>到现在ؓ(f)止,(zhn)已l看C单情形的?x)话和实?EJB lg的异常处理技术。然而,应用E序异常的某些组合可能会(x)更o(h)解,q且有多U解释。清?9 昄了一个示例?<CODE>OrderEJB</CODE> ?<CODE>ejbCreate()</CODE> Ҏ(gu)试图获取 <CODE>CustomerEJB</CODE> 的一个远E引用,q会(x)D <CODE>FinderException</CODE> ?<CODE>OrderEJB</CODE> ?<CODE>CustomerEJB</CODE> 都是实体 EJB lg。?zhn)应该如何解?<CODE>ejbCreate()</CODE> 中的q个 <CODE>FinderException</CODE> 呢?是把它当作应用程序异常对待呢Q因?EJB 规范把它定义为标准应用程序异常)(j)Q还是当作系l异常对待? </P><BR><A name=code9><B>清单 9. ejbCreate() Ҏ(gu)中的 FinderException</B></A><BR> <TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <TBODY> <TR> <TD><PRE><CODE class=section> <FONT face="Lucida Console">public Object ejbCreate(OrderValue val) throws CreateException { try { if (value.getItemName() == null) { throw new CreateException("Cannot create Order without a name"); } String custId = val.getCustomerId(); Customer cust = customerHome.fingByPrimaryKey(custId); this.customer = cust; } catch (FinderException ne) { //How do you handle this Exception ? } catch (RemoteException re) { //This is clearly a System Exception throw ExceptionLogUtil.createLoggableEJBException(re); } return null; } </FONT></CODE></PRE></TD></TR></TBODY></TABLE><BR> <P>虽然没有什么东襉K止?zhn)?<CODE>FinderException</CODE> 当应用程序异常对待,但把它当pȝ异常对待?x)更好。原因是QEJB 客户机們֐于把 EJB lg当黑对待。如?<CODE>createOrder()</CODE> Ҏ(gu)的调用者获得了一?<CODE>FinderException</CODE> Q这对调用者ƈ没有M意义?<CODE>OrderEJB</CODE> 正试图设|客戯E引用这件事对调用者来说是透明的。从客户机的角度看,p|仅仅意味着该订单无法创建?</P> <P>q类情Ş的另一个示例是Q会(x)?EJB lg试图创徏另一个会(x)?EJBQ因而导致了一?<CODE>CreateException</CODE> 。一U类似的情Ş是,实体 EJB Ҏ(gu)试图创徏一个会(x)?EJB lgQ因而导致了一?<CODE>CreateException</CODE> 。这两个异常都应该当作系l异常对待?</P> <P>另一个可能碰到的挑战是会(x)?EJB lg在它的某个容器回调方法中获得了一?<CODE>FinderException</CODE> 。?zhn)必须逐例处理q类情况。?zhn)可能要决定是?<CODE>FinderException</CODE> 当应用程序异常还是系l异常对待。请考虑清单 1 的情况,其中调用者调用了?x)?EJB lg?<CODE>deleteOldOrder</CODE> Ҏ(gu)。如果我们不是捕?<CODE>FinderException</CODE> Q而是它抛出Q会(x)怎么样呢Q在q一特定情况中,?<CODE>FinderException</CODE> 当系l异常对待似乎是W合逻辑的。这里的理由是,?x)?EJB lg們֐于在它们的方法中做许多工作,因ؓ(f)它们处理工作情形,q且它们对调用者而言是黑?</P> <P>另一斚wQ请考虑?x)?EJB 正在处理下订单的情Ş。要下一个订单,用户必须有一个简??但这个特定用户却q没有。业务逻辑可能希望?x)?EJB 昑ּ地通知用户她的档丢׃。丢q档很可能表现Z(x)?EJB lg中的 <CODE>javax.ejb.ObjectNotFoundException</CODE> Q?<CODE>FinderException</CODE> 的一个子c)(j)。在q种情况下,最好的办法是在?x)?EJB lg中捕?<CODE>ObjectNotFoundException</CODE> q抛Z个应用程序异常,让用L(fng)道她的简档丢׃?</P> <P>即是有了很好的异常处理{略Q另一个问题还是经怼(x)在测试中出现Q而且在品中也更加重要。编译器和运行时优化?x)改变一个类的整体结构,q会(x)限制(zhn)用堆栈跟t实用程序来跟踪异常的能力。这是(zhn)需要代码重构的帮助的地斏V?zhn)应该把大的方法调用分割?f)更小的、更易于理的块。而且Q只要有可能Q异常类型需要多就划分为多;每次(zhn)捕获一个异常,都应该捕获已规定好类型的异常Q而不是捕h有类型的异常?/P><BR> <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0> <TBODY> <TR> <TD><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"></TD></TR></TBODY></TABLE> <TABLE class=no-print cellSpacing=0 cellPadding=0 align=right> <TBODY> <TR align=right> <TD> <TABLE cellSpacing=0 cellPadding=0 border=0> <TBODY> <TR> <TD vAlign=center><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></TD> <TD vAlign=top align=right><A class=fbox ><B><FONT color=#996699>回页?/FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR> <P><A name=9><span id="gqwjlon" class=atitle><FONT face=Arial size=4>l束?/FONT></SPAN></A></P> <P>我们已经在本文讨Z很多东西Q?zhn)可能想知道我们已l讨论的主要设计是否都物有所倹{我的经验是Q即便是在中型目中,在开发周期中Q?zhn)的付出就已经能看到回报,更不用说试和品周期了。此外,在宕机对业务h毁灭性媄(jing)响的生pȝ中,良好的异常处理体pȝ构的重要性再怎么也不q分?/P> <P>我希望本文所展示的最?jng)_法对(zhn)有益。要深入理解q里提供的某些信息,请参?<A ><FONT color=#996699>参考资?/FONT></A>部分中的清单?</P><BR> <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0> <TBODY> <TR> <TD><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"></TD></TR></TBODY></TABLE> <TABLE class=no-print cellSpacing=0 cellPadding=0 align=right> <TBODY> <TR align=right> <TD> <TABLE cellSpacing=0 cellPadding=0 border=0> <TBODY> <TR> <TD vAlign=center><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></TD> <TD vAlign=top align=right><A class=fbox ><B><FONT color=#996699>回页?/FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR> <P><A name=resources><span id="wkmwcqp" class=atitle><FONT face=Arial size=4>参考资?</FONT></SPAN></A></P> <UL> <LI>(zhn)可以参阅本文在 developerWorks 全球站点上的 <A ><FONT color=#5c81a7>英文原文</FONT></A>. <BR><BR> <LI>单击本文剙或底部的 <B>讨论</B>参加本文?<A href="javascript:void forumWindow()"><FONT color=#5c81a7>讨论论坛</FONT></A>?<BR><BR><BR> <LI>下蝲本文所讨论?<A href="ftp://www6.software.ibm.com/software/developer/library/j-ejbexcept.zip"><FONT color=#5c81a7>实用E序c?/FONT></A>?<BR><BR><BR> <LI>(zhn)可以阅?Sun Microsystems ?<A ><FONT color=#5c81a7>EJB 规范</FONT></A>了解关于 EJB 体系l构的更多信息?<BR><BR><BR> <LI>Apache ?Jakarta 目有几个珍品?<A ><FONT color=#5c81a7>Log4J 框架</FONT></A>x其中之一?<BR><BR><BR> <LI><A ><FONT color=#5c81a7>Struts 框架</FONT></A>?Jakarta 目的另一个珍品。Struts 建立?MVC 体系l构的基上,提供了一个彻底的分离Q它把系l的表示层从pȝ的业务逻辑层中分离出来?<BR><BR><BR> <LI>要详l了?StrutsQ请阅读 Malcom Davis 所写的讲述q个主题的很受欢q的文章?<A ><FONT color=#5c81a7>Struts, an open-source MVC implementation</FONT></A>”( <I>developerWorks</I>Q?001 q?2 月)(j)。请注意Q有一由 Wellie Chao 撰写的最新文章定?2002 q夏季发表?<BR><BR><BR> <LI>(zhn)可以通过阅读相关?<A ><FONT color=#5c81a7>J2SE 文档</FONT></A>了解关于新的 Java Logging APIQjava.util.loggingQ的更多信息?<BR><BR><BR> <LI>刚接?J2EEQ来自“WebSphere 开发者园地”的q篇文章告诉(zhn)如?<A ><FONT color=#5c81a7>?WebSphere Studio Application Developer 开发和试 J2EE 应用E序</FONT></A>Q?001 q?10 月)(j)?<BR><BR><BR> <LI>如果(zhn)想更多了解关于试Z EJB 的系l的知识Q请从最q的 <I>developerWorks</I>文章?<A ><FONT color=#5c81a7>Test flexibly with AspectJ and mock objects</FONT></A>”(2002 q?5 月)(j)开始?<BR><BR><BR> <LI>如果(zhn)不满于单元测试,q想了解企业U系l测试的知识Q请看看 <A ><FONT color=#5c81a7>IBM Performance Management, Testing, and Scalability Services</FONT></A>企业U测试库提供了什么?<BR><BR><BR> <LI>Sun ?<A ><FONT color=#5c81a7>J2EE 模式</FONT></A>Web 站点着重于使用 J2EE 技术的模式、最?jng)_法、设计策略以?qing)经验证的解x案?<BR><BR><BR> <LI>(zhn)可以在 <I>developerWorks</I> <A ><FONT color=#5c81a7>Java 技术专?/FONT></A>扑ֈC百计关于 Java ~程的方斚w面的文章?<BR></LI></UL><BR> <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0> <TBODY> <TR> <TD><IMG height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"></TD></TR></TBODY></TABLE> <TABLE class=no-print cellSpacing=0 cellPadding=0 align=right> <TBODY> <TR align=right> <TD> <TABLE cellSpacing=0 cellPadding=0 border=0> <TBODY> <TR> <TD vAlign=center><IMG height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><BR></TD> <TD vAlign=top align=right><A class=fbox ><B><FONT color=#996699>回页?/FONT></B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR> <P><A name=author><span id="fmgxznf" class=atitle><FONT face=Arial size=4>关于作?/FONT></SPAN></A></P> <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0> <TBODY> <TR> <TD colSpan=2><FONT face=Arial size=4><IMG height=5 alt="" src="http://www.ibm.com/i/c.gif" width="100%"></FONT></TD></TR> <TR vAlign=top align=left> <TD> <P><FONT face=Arial size=4><IMG height=80 alt="Srikanth Shenoy 的照? src="http://www-128.ibm.com/developerworks/cn/java/j-ejbexcept/p-shenoy.jpg" width=64 align=left></FONT></P></TD> <TD> <P>Srikanth Shenoy 专门从事大型 J2EE ?EAI 目的体pȝ构、设计、开发和部v工作。他?Java q_一出现时就q上了它Q从此便全心投入。Srikanth 已经帮他的制造业、物业和金融业客户实现?Java q_“一ơ编写,随处q行”的梦想。?zhn)可以通过 <A href="mailto:srikanth@srikanth.org"><FONT color=#5c81a7>srikanth@srikanth.org</FONT></A>与他联系?</P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></P><img src ="http://www.tkk7.com/ghawk/aggbug/23249.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/ghawk/" target="_blank">GHawk</a> 2005-12-10 11:25 <a href="http://www.tkk7.com/ghawk/archive/2005/12/10/23249.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>q用Jakarta Struts的七大实战心?/title><link>http://www.tkk7.com/ghawk/archive/2005/12/02/22233.html</link><dc:creator>GHawk</dc:creator><author>GHawk</author><pubDate>Fri, 02 Dec 2005 05:37:00 GMT</pubDate><guid>http://www.tkk7.com/ghawk/archive/2005/12/02/22233.html</guid><wfw:comment>http://www.tkk7.com/ghawk/comments/22233.html</wfw:comment><comments>http://www.tkk7.com/ghawk/archive/2005/12/02/22233.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.tkk7.com/ghawk/comments/commentRss/22233.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/ghawk/services/trackbacks/22233.html</trackback:ping><description><![CDATA[<div id="rnzbsru" class=postText> <P>当作?Chuck CavanessQ著有《Programming Jakarta Struts》一书)(j)所在的|络公司军_采用Struts框架之后QChuck曄p了好几个月来研究如何用它来构建公司的应用pȝ。本文叙q的正是作者在q用Strutsq程中来之不易的若干l验和心得。如果你是个负责通过jsp和servlet开发Web应用的JavaE序员,q且也正在考虑采用ZStruts的构建方法的话,那么你会(x)在这里发现很多颇有见地同时也很有价值的信息?<BR><BR>  1. 只在必要的时候才考虑扩展Struts框架 <BR><BR>  一个好的framework有很多优点,首先Q它必须能够满用户的可预见的需求。ؓ(f)?Struts为Web 应用提供了一个通用的架构,q样开发h员可以把_֊集中在如何解军_际业务问题上。其ơ,一个好的frameworkq必能够在适当的地Ҏ(gu)供扩展接口,以便应用E序能扩展该框架来更好的适应使用者的实际需要?<BR><BR>  如果Struts framework在Q何场合,M目中都能很好的满需求,那真是太了。但是实际上Q没有一个框架声U能做到q一炏V一定会(x)有一些特定的应用需求是框架的开发者们无法预见到的。因此,最好的办法是提供_的扩展接口,使得开发工E师能够调整struts来更好的W合他们的特D要求?<BR><BR>  在Struts framework中有很多地方可供扩展和定制。几乎所有的配置c都能被替换为某个用户定制的版本Q这只要单的修改一下Struts的配|文件就可以做到?<BR><BR>  其他lg如ActionServlet?RequestProcessor 也能用自定义的版本代? 甚至qStruts 1.1里才有的新特性也是按照扩展的原则来设计的。例如,在异常处理机制中允许用户定制异常处理的句柄Q以便更好的对应用系l发生的错误做出响应?<BR><BR>  作ؓ(f)框架的这U可调整Ҏ(gu)在它更适合你的应用的同时也在很大的E度上媄(jing)响了目开发的效果。首先,׃(zhn)的应用是基于一个现有的成熟的、稳定的framework如StrutsQ测试过E中发现的错误数量将?x)大大减,同时也能~短开发时间和减少资源的投入。因Z不再需要投入开发力量用于编写基框架的代码了?<BR><BR>  然? 实现更多的功能是要花Ҏ(gu)大的代h(hun)的。我们必d心避免不必要的滥用扩展性能Q?Struts是由核心包加上很多工具包构成的,它们已经提供了很多已l实现的功能。因此不要盲目的扩展Struts框架Q要先确定能不能采用其他Ҏ(gu)使用现有的功能来实现?在决定编写扩展代码前务必要确认Struts的确没有实现你要的功能。否则重复的功能?x)导致؜乱将来还得花贚w外的_֊清除它?<BR><BR>  2. 使用异常处理声明 <BR><BR>  要定义应用程序的逻辑程Q成熟的l验是推荐在代码之外Q用配置的方法来实现Q而不是写dE序代码中的。在J2EE中,q样的例子比比皆是。从实现EJB的安全性和事务性行为到描述JMS消息和目的地之间的关p,很多q行时的处理程都是可以在程序之外定义的?<BR><BR>  Struts 创徏者从一开始就采用q种Ҏ(gu)Q通过配置Struts的配|文件来定制应用pȝq行时的各个斚w。这一点在版本1.1的新Ҏ(gu)上得到延箋Q包括新的异常处理功能。在Struts framework以前的版本中Q开发h员不得不自己处理Struts应用中发生的错误情况。在最新的版本中,情况大大的改观了QStruts Framework提供了内|的一个称?ExceptionHandler 的类Q?用于pȝ~省处理actionc运行中产生的错误。这也是在上一个技巧中我们提到的framework许多可扩展接口之一?<BR><BR>  Struts~省?ExceptionHandlercM(x)生成一个ActionError对象q保存在适当的范_(d)scopeQ对象中。这样就允许JSP面使用错误cL提醒用户出现什么问题。如果你认ؓ(f)q不能满你的需求,那么可以很方便的实现你自qExcepionHandlercR?<BR><BR>  具体定制异常处理的方法和机制 <BR><BR>  要定制自q异常处理机制Q第一步是l承org.apache.struts.action.ExceptionHandlercR这个类?个方法可以覆盖,一个是excute()另外一个是storeException(). 在多数情况下Q只需要覆盖其中的excute()Ҏ(gu)。下面是ExceptionHandlercȝexcute()Ҏ(gu)声明Q?<BR>  正如你看到的Q该Ҏ(gu)有好几个参数Q其中包括原始的异常。方法返回一个ActionForward对象Q用于异常处理结束后controllercd到请求必{发的地方厅R?<BR><BR>  当然(zhn)可以实CQ何处理,但一般而言Q我们必L查抛出的异常,q对该cd的异常进行特定的处理。缺省的Q系l的异常处理功能是创Z个出错信息,同时把请求{发到配置文g中指定的地方厅R?定制异常处理的一个常见的例子是处理嵌套异常。假设该异常包含有嵌套异常,q些嵌套异常又包含了其他异常Q因此我们必覆盖原来的execute()Ҏ(gu)Q对每个异常~写出错信息?<BR><BR>  一旦你创徏了自qExceptionHandler c,应该在Struts配置文g中的部分声明q个c,以便让Struts知道改用你自定义的异常处理取代缺省的异常处理. <BR><BR>  可以配置你自qExceptionHandler cL用于Action Mapping特定的部分还是所有的Action对象。如果是用于Action Mapping特定的部分就?ACTION></ACTION>元素中配|。如果想让这个类可用于所有的Action对象,可以?GLOBAL-SECTIONS></GLOBAL-SECTIONS> 元素中指定。例如,假设我们创徏了异常处理类CustomizedExceptionHandler用于所有的Actionc? <GLOBAL-EXCEPTIONS></GLOBAL-EXCEPTIONS>元素定义如下所C:(x) <BR><BR>  ?EXCEPTION></EXCEPTION>元素中可以对很多属性进行设|。在本文中,最重要的属性莫q于handler属? handler属性的值就是自定义的承了ExceptionHandlercȝ子类的全名?假如该属性没有定义,Struts?x)采用自q~省倹{当?dng)其他的属性也很重要,但如果想覆盖~省的异常处理的话,handler无疑是最重要的属性?<BR><BR>  最后必L出的一Ҏ(gu)Q你可以有不同的异常处理cL处理不同的异常。在上面的例子中QCustomizedExceptionHandler用来处理Mjava.lang.Exception的子c? 其实Q你也可以定义多个异常处理类Q每一个专门处理不同的异常?wi)。下面的XML片断解释了如何配|以实现q一炏V?<BR><BR>  在这里,一旦有异常抛出Qstruts framework试囑֜配置文g中找到ExceptionHandlerQ如果没有找刎ͼ那么struts沿着该异常的父类链一层层往上找直到发现匚w的ؓ(f)止。因此,我们可以定义一个层ơ型的异常处理关pȝ构,在配|文件中已经体现了这一炏V?<BR><BR>  3. 使用应用模块QApplication ModulesQ?<BR><BR>  Struts 1.1的一个新Ҏ(gu)是应用模块的概c(din)应用模块允许将单个Struts应用划分成几个模块,每个模块有自qStruts配置文gQJSP面QAction{等。这个新Ҏ(gu)是Z解决大中型的开发队伍抱怨最多的一个问题,即ؓ(f)了更好的支持q行开发允许多个配|文件而不是单个配|文件?<BR><BR>  注:(x)在早期的beta版本中,该特性被UCؓ(f)子应用(sub-applicationsQ,最q的改名目的是ؓ(f)了更多地反映它们在逻辑上的分工?<BR><BR>  昄Q当很多开发h员一起参加一个项目时Q单个的Struts配置文g很容易引赯源冲H。应用模块允许Struts按照功能要求q行划分Q许多情况已l证明这h贴近实际。例如,假设我们要开发一个典型的商店应用E序。可以将l成部分划分成模块比如catalogQ商品目录)(j), customerQ顾客)(j), customer serviceQ顾客服务)(j), orderQ订单)(j){。每个模块可以分布到不同的目录下Q这样各部分的资源很Ҏ(gu)定位Q有助于开发和部v。图1 昄了该应用的目录结构?<BR><BR>  ?1. 一个典型的商店应用E序的目录结?<BR>   <BR><BR>  注:(x)如果你无需项目划分成多个模块QStruts框架支持一个缺省的应用模块。这׃得应用程序也可以?.0版本下创建,h可移植性,因ؓ(f)应用E序?x)自动作为缺省的应用模块?<BR><BR>  Z使用多应用模块功能,必须执行以下几个准备步骤Q?<BR><BR>  ?为每个应用模块创建独立的Struts配置文g?<BR><BR>  ?配置Web 部v描述W?Web.xml文g?<BR><BR>  ?使用org.apache.struts.actions.SwitchAction 来实现程序在模块之间的蟩? <BR><BR>  创徏独立的Struts配置文g <BR><BR>  每个Struts应用模块必须拥有自己的配|文件。允许创q独立于其他模块的ActionQActionFormQ异常处理甚x多?<BR><BR>  l箋以上面的商店应用E序ZQ我们可以创Z下的配置文gQ一个文件名为struts-config-catalog.xmlQ包含catalogQ商品目录)(j)、items(商品清单)、和其它与库存相关的功能的配|信息;另一个文件名为struts- config-order.xml, 包含对orderQ订单)(j)和order trackingQ订单跟t)(j)的设|。第三个配置文g是struts-config.xml,其中含有属于~省的应用模块中的一般性的功能?/P> <P>  配置Web部v描述W?<BR><BR>  在Struts的早期版本中Q我们在Web.xml中指定Struts配置文g的\径。好在这Ҏ(gu)变,有助于向后兼宏V但对于多个应用模块Q我们需要在Web部v描述W中增加新的配置文g的设定?<BR><BR>  对于~省的应用(包括Struts的早期版本)(j)QStruts framework 在Web.xml文g中查扑ָ有config的元?INIT-PARAM></INIT-PARAM>Q用于蝲入Action mapping 和其它的应用E序讑֮。作Z子,以下的XML片断展现一个典型的<INIT-PARAM></INIT-PARAM>元素Q?<BR><BR>  注:(x)如果在现有的<INIT-PARAM></INIT-PARAM>元素中找不到"config"关键字,Struts framework缺省地使用/WEB/struts-config.xml <BR><BR>  Z支持多个应用模块(Struts 1.1的新Ҏ(gu)?Q必d加附加的<INIT-PARAM></INIT-PARAM>元素。与~省?INIT-PARAM></INIT-PARAM>元素不同的是Q附加的<INIT-PARAM></INIT-PARAM>元素与每个应用模块对应,必须以config/xxx的Ş式命名,其中字符串xxx代表该模块唯一的名字。例如,在商店应用程序的例子中,<INIT-PARAM></INIT-PARAM>元素可定义如下(注意_体字部分)(j)Q?<BR><BR>  W一?<INIT-PARAM></INIT-PARAM>元素对应~省的应用模块。第二和W三个元素分别代表非~省应用模块catalog ?order?<BR><BR>  当Struts载入应用E序Ӟ它首先蝲入缺省应用模块的配置文g。然后查扑ָ有字W串config/xxx 形式的附加的初始化参数。对每个附加的配|文件也q行解析q蝲入内存。这一步完成后Q用户就可以很随意地用config/后面的字W串也就是名字来调用相应的应用模块?<BR><BR>  多个应用模块之间调用Actionc?<BR><BR>  在ؓ(f)每个应用模块创徏独立的配|文件之后,我们有可能需要调用不同的模块中Action。ؓ(f)此必M用Struts框架提供的SwitchActioncRStruts ?x)自动将应用模块的名字添加到URL,如Struts 自动d应用E序的名字加到URL一栗应用模块是Ҏ(gu)架的一个新的扩充,有助于进行ƈ行的团队开发。如果你的团队很那没必要用到q个Ҏ(gu),不必q行模块化。当?dng)q是只有一个模块,pȝq是一L(fng)q作?<BR><BR>  4. 把JSP攑ֈWEB-INF后以保护JSP源代?<BR><BR>  Z更好C护你的JSP避免未经授权的访问和H视Q?一个好办法是将面文g存放在Web应用的WEB-INF目录下?<BR><BR>  通常JSP开发h员会(x)把他们的面文g存放在Web应用相应的子目录下。一个典型的商店应用E序的目录结构如?所C。跟catalog Q商品目录)(j)相关的JSP被保存在catalog子目录下。跟customer相关的JSPQ跟订单相关的JSP{都按照q种Ҏ(gu)存放?<BR>   <BR>  q种Ҏ(gu)的问题是q些面文gҎ(gu)被偷看到源代码,或被直接调用。某些场合下q可能不是个大问题,可是在特定情形中却可能构成安全隐(zhn)。用户可以绕qStruts的controller直接调用JSP同样也是个问题?<BR><BR>  Z减少风险Q可以把q些面文gUdWEB-INF 目录下。基于Servlet的声明,W(xu)EB-INF不作为Web应用的公共文档树(wi)的一部分。因此,W(xu)EB-INF 目录下的资源不是为客L(fng)接服务的。我们仍然可以用WEB-INF目录下的JSP面来提供视囄客户Q客户却不能直接h讉KJSP?<BR><BR>  采用前面的例子,?昄JSP面UdWEB-INF 目录下后的目录结?<BR><BR>  如果把这些JSP面文gUdWEB-INF 目录下,在调用页面的时候就必须?WEB-INF"d到URL中。例如,在一个Struts配置文g中ؓ(f)一个logoff action写一个Action mapping。其中JSP的\径必M"WEB-INF"开头。如下所C:(x)h意粗体部? <BR><BR>  q个Ҏ(gu)在Q何情况下都不׃ؓ(f)Struts实践中的一个好Ҏ(gu)。是唯一要注意的技巧是你必LJSP和一个Struts action联系h。即使该Action只是一个很基本的很单JSPQ也L要调用一个ActionQ再由它调用JSP?<BR><BR>  最后要说明的是Qƈ不是所有的容器都能支持q个Ҏ(gu)。WebLogic早期的版本不能解释Servlet声明Q因此无法提供支持,据报道在新版本中已经改进了。M使用之前先检查一下你的Servlet容器?<BR><BR>  5. 使用 Prebuilt ActioncL升开发效?<BR><BR>  Struts framework带有好几个prebuilt Actionc,使用它们可以大大节省开发时间。其中最有用的是org.apache.struts.actions.ForwardAction ?org.apache.struts.actions.DispatchAction. <BR><BR>  使用 ForwardAction <BR><BR>  在应用程序中Q可能会(x)l常出现只要Action对象转发到某个JSP的情c(din)在上一点中曾提到L由Action调用JSP是个好习(fn)惯。如果我们不必在Action中执行Q何业务逻辑Q却又想遵@从Action讉K面的话Q就可以使用ForwardActionQ它可以使你免去创徏许多I的ActioncR运用ForwardAction的好处是不必创徏自己的Actionc,你需要做的仅仅是在Struts配置文g中配|一个Action mapping?<BR><BR>  举个例子Q假定你有一个JSP文gindex.jsp Q而且不能直接调用该页面,必须让程序通过一个Actionc调用,那么Q你可以建立以下的Action mapping来实现这一点:(x) <BR><BR>  正如你看到的Q当 /home 被调用时, ׃(x)调用ForwardAction q把h转发?index.jsp 面. <BR><BR>  再讨Z下不通过一个Actioncȝ接{发到某个面的情况,必须注意我们仍然使用<ACTION></ACTION>元素中的forward属性来实现转发的目标。这?ACTION></ACTION>元素定义如下Q?<BR><BR>  以上两种Ҏ(gu)都可以节省你的时_(d)q有助于减少一个应用所需的文件数?<BR><BR>  使用 DispatchAction <BR><BR>  DispatchAction是Struts包含的另一个能大量节省开发时间的ActioncR与其它ActioncM提供单个execute()Ҏ(gu)实现单个业务不同QDispatchAction允许你在单个ActioncM~写多个与业务相关的Ҏ(gu)。这样可以减Actioncȝ数量Qƈ且把相关的业务方法集合在一起得维护v来更Ҏ(gu)?<BR><BR>  要用DispatchAction的功能,需要自己创Z个类Q通过l承抽象的DispatchAction得到。对每个要提供的业务Ҏ(gu)必须有特定的Ҏ(gu)signature。例如,我们惌提供一个方法来实现对购物Rd商品清单Q创Z一个类ShoppingCartDispatchAction提供以下的方法:(x) <BR><BR>  那么Q这个类很可能还需要一个deleteItem()Ҏ(gu)从客L(fng)购物车中删除商品清单Q还有clearCart()Ҏ(gu)清除购物车等{。这时我们就可以把这些方法集合在单个Actionc,不用为每个方法都提供一个ActioncR?<BR><BR>  在调用ShoppingCartDispatchAction里的某个Ҏ(gu)Ӟ只需在URL中提供方法名作ؓ(f)参数倹{就是说Q调用addItem()Ҏ(gu)?URL看v来可能类gQ?<BR><BR>  http://myhost/storefront/action/cart?method=addItem <BR><BR>  其中method参数指定ShoppingCartDispatchAction中要调用的方法。参数的名称可以L配置Q这里用的"method"只是一个例子。参数的名称可以在Struts配置文g中自行设定?<BR><BR>  6.使用动态ActionForm <BR><BR>  在Struts framework中,ActionForm对象用来包装HTML表格数据Q包括请求)(j)Qƈq回q回动态显C给用户的数据。它们必L完全的JavaBeanQƈl承.Struts 里面的ActionFormc,同时Q用户可以有选择地覆盖两个缺省方法?<BR><BR>  该特性能节省很多旉Q因为它可以协助q行自动的表现层的验证。ActionForm的唯一~点是必Mؓ(f)不同的HTML表格生成多个ActionForm cM保存数据。例如,如果有一个页面含有用L(fng)注册信息Q另一个页面则含有用户的介lh的信息,那么需要有两个不同的ActionFormcR这在大的应用系l中׃(x)Dq多的ActionFormcRStruts 1.1Ҏ(gu)做出了很好的改进Q引入了动态ActionFormcL?<BR><BR>  通过Struts framework中的DynaActionFormcd(qing)其子cd以实现动态的ActionForm Q动态的ActionForm允许你通过Struts的配|文件完成ActionForm的全部配|;再也没有必要在应用程序中创徏具体的ActionFormcR具体配|方法是Q在Struts的配|文仉过增加一?FORM-BEAN></FORM-BEAN>元素Q将type属性设定成DynaActionForm或它的某个子cȝ全名。下面的例子创徏了一个动态的ActionForm名ؓ(f)logonFormQ它包含两个实例变量Qusername ?password. <BR><BR>  动态的ActionForm可以用于ActioncdJSPQ用方法跟普通的ActionForm相同Q只有一个小差别。如果用普通的ActionForm对象则需要提供get ?setҎ(gu)取得和设|数据。以上面的例子而言Q我们需要提供getUsername() ?setUsername()Ҏ(gu)取得和设|username变量Q同样地有一Ҏ(gu)法用于取得和讄password变量. <BR><BR>  q里我们使用的是DynaActionFormQ它?yu)变量保存在一个Mapcd象中Q所以必M用DynaActionForm cM的get(name) ?set(name)Ҏ(gu)Q其中参数name是要讉K的实例变量名。例如要讉KDynaActionForm中username的|可以采用cM的代码:(x) <BR><BR>  String username = (String)form.get("username"); <BR><BR>  ׃值存攑֜一个Map对象Q所以要记得对get()Ҏ(gu)q回的Object对象做强制性类型{换?<BR><BR>  DynaActionForm有好几个很有用的子类。其中最重要的是DynaValidatorForm Q这个动态的ActionForm和Validator 一起利用公qValidator包来提供自动验证。这个特性你得以在E序代码之外指定验证规则。将两个Ҏ(gu)结合用对开发h员来说将非常有吸引力?<BR><BR>  7. 使用可视化工?<BR><BR>  自从Struts 1.0 分布以来Q就出现了不可视化工具用于协助创徏Q修改和l护Struts的配|文件。配|文件本w是ZXML格式Q在大中型的开发应用中?x)增大变得很W拙。ؓ(f)了更方便的管理这些文Ӟ一旦文件大C无法一目了然的时候,试着采用其中的一UGUI 工具协助开发。商业性的和开放源代码的工具都有不,?列出了可用的工具和其相关链接Q从那里可以获取更多信息?<BR><BR>  ?1. Struts GUI 工具 <BR>  应用E序 性质 |址 <BR>  Adalon 商业软g http://www.synthis.com/products/adalon <BR>  Easy Struts 开放源?http://easystruts.sourceforge.net/ <BR>  Struts Console 免费 http://www.jamesholmes.com/struts/console <BR>  JForms 商业软g http://www.solanasoft.com/ <BR>  Camino 商业软g http://www.scioworks.com/scioworks_camino.html <BR>  Struts Builder 开放源?http://sourceforge.net/projects/rivernorth/ <BR>  StrutsGUI 免费 http://www.alien-factory.co.uk/struts/struts-index.html <BR><BR>  相关资源 <BR><BR>  要获取更为全面的Struts GUI 工具列表 (包括免费的和商业性的), 误?Struts resource page. </P></DIV><img src ="http://www.tkk7.com/ghawk/aggbug/22233.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/ghawk/" target="_blank">GHawk</a> 2005-12-02 13:37 <a href="http://www.tkk7.com/ghawk/archive/2005/12/02/22233.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我应该用哪U样式的 WSDL 呢? (From IBM developerWorks)http://www.tkk7.com/ghawk/archive/2005/12/02/22232.htmlGHawkGHawkFri, 02 Dec 2005 05:36:00 GMThttp://www.tkk7.com/ghawk/archive/2005/12/02/22232.htmlhttp://www.tkk7.com/ghawk/comments/22232.htmlhttp://www.tkk7.com/ghawk/archive/2005/12/02/22232.html#Feedback0http://www.tkk7.com/ghawk/comments/commentRss/22232.htmlhttp://www.tkk7.com/ghawk/services/trackbacks/22232.html 我应该用哪U样式的 WSDL 呢?
内容Q?/B>
引言
RPC/~码
RPC/文字
文档/~码
文档/文字
文档/文字包装模式
Z么不始终采用文档/文字包装的样?/A>
SOAP 响应消息
l束?/A>
参考资?
关于作?/A>
Ҏ(gu)文的评h(hun)
相关内容Q?/B>
Web services with WSDL
Handle namespaces in SOAP messages you create by hand
订阅:
developerWorks 时事通讯

U别: 高

Russell Butek
Web 服务N, IBM
2003 q?10 ?31 ?BR>2005 q?6 ?29 ?更新

WSDL l定样式可以?RPC 样式或文档样式。用法可以是~码的,也可以是文字的。?zhn)如何军_使用哪一U样?用法的组合呢Q本文将帮助(zhn)解册个问题?/BLOCKQUOTE>

引言
Web 服务是通过 WSDL 文档来描q的。WSDL l定描述了如何把服务l定到消息传递协议(特别?SOAP 消息传递协议)(j)。WSDL SOAP l定可以?RPC 样式的绑定,也可以是文档样式的绑定。同PSOAP l定可以有编码的用法Q也可以有文字的用法。这l我们提供了四种样式/用法模型Q?/P>

  1. RPC/~码
  2. RPC/文字
  3. 文档/~码
  4. 文档/文字

除了q些样式之外Q还有一U样式也很常见,它称为文?文字包装的样式,上q一U,在创?WSDL 文g时?zhn)有了五U绑定样式可以从中选择。?zhn)应该选择哪一U呢Q?/P>

在我q一步讨Z前,让我阐明一些容易؜淆的地方。这里,q些术语是非怸合适的QRPC 与文档。这些术语意味着 RPC 样式应该用于 RPC ~程模型Q文档样式应该用于文档或消息~程模型?但事实完?I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">不是q样。样式对于编E模型没有Q何意义。它只是指明了如何将 WSDL l定转化?SOAP 消息。其他就没什么了。你可以Q一U样式用于Q何编E模型?/P>

同样Q术?I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">~码?I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">文字只对?WSDL ?SOAP 映射有意义,可是Q至这里,q两个单词的字面意思更Ҏ(gu)理解一些?/P>

对于q篇讨论Q让我们?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">清单 1 中的 Java Ҏ(gu)开始,q且应用 JAX-RPC Java-to-WSDL 规则Q参?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">参考资?/A>查看 JAX-RPC 1.1 规范Q?/P>清单 1. Java Ҏ(gu)
public void myMethod(int x, float y);

RPC/~码
采用清单 1 中的Ҏ(gu)q且使用你喜Ƣ的 Java-to-WSDL 工具来运行,指定(zhn)想让它生成 RPC/~码?WSDL。?zhn)最后应该得到如清单 2 所C的 WSDL 片断?/P>清单 2. 用于 myMethod ?RPC/~码?WSDL
<message name="myMethodRequest">
    <part name="x" type="xsd:int"/>
    <part name="y" type="xsd:float"/>
</message>
<message name="empty"/>

<portType name="PT">
    <operation name="myMethod">
        <input message="myMethodRequest"/>
        <output message="empty"/>
    </operation>
</portType>

<binding .../>  
<!-- I won't bother with the details, just assume it's RPC/encoded. -->

现在用?”作为参?x 的|?.0”作为参?y 的值来调用q个Ҏ(gu)。发送一个如清单 3 所C的SOAP 消息?/P>清单 3. 用于 myMethod ?RPC/~码?SOAP 消息
<soap:envelope>
    <soap:body>
        <myMethod>
            <x xsi:type="xsd:int">5</x>
            <y xsi:type="xsd:float">5.0</y>
        </myMethod>
    </soap:body>
</soap:envelope>

关于前缀和命名空间的注意事项
Z单v见,在本文的大部?XML CZ中,我省略了命名I间和前~。不q,我还是用了数前缀Q?zhn)可以假定它们是用下列名称I间q行定义的:(x)

  • xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  • xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  • xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"

关于命名I间?WSDL-to-SOAP 映射的讨论,请参考文章“Handle namespaces in SOAP messages you create by hand”(参阅 参考资?/A>Q?/P>

关于 RPC/~码例子中的 WSDL ?SOAP 消息有一些需要注意的地方Q?/P>

优点

  • WSDL 可能的单明了?
  • 操作名出现在消息中,因此接收者可以很Ҏ(gu)的将消息分派到操作的实现?/LI>



~点

늅 WS-I
各种 Web 服务规范有时候是不一致和不明的。WS-I l织成立用来解决q些规范上的问题。它已经定义了许多概要,指明了你应该如何~写 Web 服务来实C操作性。要获取 WS-I 的更多信息,请参?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">参考资?/A>中的 WS-I 链接?/P>

  • cd~码信息Q?CODE>xsi:type="xsd:int"Q通常是降低吞吐量性能的开销?
  • 你不能很Ҏ(gu)的验证这个消息的有效性,因ؓ(f)只有 <x ...>5</x> ?<y ...>5.0</y> 行包?Schema 中定义的内容Q?CODE>soap:body 内容的其余部分来自于 WSDL 定义?
  • 虽然它是合法?WSDLQ但 RPC/encoded 是不遵守 WS-I 的?/LI>

有没有一U方法可以取其精华,弃其p粕呢?可能有。让我们看一?RPC/文字样式?/P>

RPC/文字
用于q个Ҏ(gu)?RPC/文字样式?WSDL 看v来与 RPC/~码?WSDLQ?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">清单 4Q几乎一栗绑定的用法?~码 变ؓ(f) 文字。仅此而已?/P>清单 4. 用于 myMethod ?RPC/文字样式?WSDL
<message name="myMethodRequest">
    <part name="x" type="xsd:int"/>
    <part name="y" type="xsd:float"/%gt;
</message>
<message name="empty"/>

<portType name="PT">
    <operation name="myMethod">
        <input message="myMethodRequest"/>
        <output message="empty"/>
    </operation>
</portType>

<binding .../>  
<!-- I won't bother with the details, just assume it's RPC/literal. -->

RPC/文字?SOAP 消息又是怎样的呢Q参?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">清单 5Q?q里的更改要多一炏V去掉了cd~码?/P>清单 5. 用于 myMethod ?RPC/literal SOAP 消息
<soap:envelope>
    <soap:body>
        <myMethod>
            <x>5</x>
            <y>5.0</y>
        </myMethod>
    </soap:body>
</soap:envelope>

关于 xsi:type 和文字用法的注意事项
虽然在一般情况下Q?CODE>xsi:type 没有出现在文?WSDL ?SOAP 消息中,但是仍然有一些情况,cd信息是必ȝQƈ且它?yu)以多种形式出现。如?API 期望一个基cdQƈ且发送一个扩展实例,则必L供这个实例的cd以便正确的反序列化该对象?/P>

q里是这U方法的优点和缺点:(x)

优点

  • WSDL 可能的单明了?
  • 操作名仍然出现在消息中?
  • L了类型编码?
  • RPC/文字是遵?WS-I 的?/LI>

~点

  • 你仍然不能很Ҏ(gu)的验证这个消息的有效性,因ؓ(f)只有 <x ...>5</x> ?<y ...>5.0</y> 行中包含定义?Schema 中的内容Q?CODE>soap:body 内容的其余部分来自于 WSDL 定义?/LI>

文档样式如何呢?它们能够帮助克服q些困难吗?

文档/~码
没有Z用这个样式。它不遵?WS-I。因此此处略q?/P>

文档/文字
文档/文字?WSDL ?RPC/文字?WSDL 基础上做了一些修攏V其不同点已l在清单 6 中指出?/P>清单 6. 用于 myMethod 的文?文字 WSDL
<types>
    <schema>
        <element name="xElement" type="xsd:int"/>
        <element name="yElement" type="xsd:float"/>
    </schema>
</types>

<message name="myMethodRequest">
    <part name="x" element="xElement"/>
    <part name="y" element="yElement"/>
</message>
<message name="empty"/>

<portType name="PT">
    <operation name="myMethod">
        <input message="myMethodRequest"/>
        <output message="empty"/>
    </operation>
</portType>

<binding .../>  
<!-- I won't bother with the details, just assume it's document/literal. -->

用于q个 WSDL ?SOAP 消息?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">清单 7 所C:(x)

清单 7. 用于 myMethod 的文?文字 SOAP 消息
<soap:envelope>
    <soap:body>
        <xElement>5</xElement>
        <yElement>5.0</yElement>
    </soap:body>
</soap:envelope>

关于消息l成部分的注意事?/B>
我本来可以只更改l定Q就像我?RPC/~码转到 RPC/所做的那样。它?yu)是合法?WSDL。然而,W(xu)S-I 基本概要QWS-I Basic ProfileQ规定文?文字的消息的l成部分引用元素而不是类型,所以我遵@?WS-IQƈ且此处用元素部分可以很好地把我们带到关于文?文字包装的样式的讨论Q?/P>

下面是这U方法的优点和缺点:(x)

优点

  • 没有cd~码信息?
  • (zhn)可以在最后用M XML (g)验器(g)验此消息的有效性?CODE>soap:body 里面的所有内定w定义?schema 中?
  • 文档/文字是遵?WS-I 的,但是有限Ӟ参阅~点Q?/LI>

~点

  • WSDL 有一点复杂。不q,q是一个非常小的缺点,因ؓ(f) WSDL q没有打由人来d?
  • SOAP 消息中缺操作名。而如果没有操作名Q发送就可能比较困难Qƈ且有时变得不可能?
  • WS-I 仅仅允许 SOAP 消息?soap:body 的一个子元素。正如你?A >清单 7 中所见的那样Q该消息?soap:body 有两个子元素?/LI>

文档/文字样式g只是重新排列了一?RPC/文字模型中的优点和缺炏V你可以验证该消息,但是你已l失M操作名。有没有什么办法可以改q这一点呢Q是的,它就是文?文字包装模式?/P>

文档/文字包装模式
在我描述文档/文字包装模式的规则之前,让我先向(zhn)展C?WSDL ?SOAP 消息Q如清单 8 ?清单 9 所C?/P>清单 8. 用于 myMethod 的文?文字装?WSDL?/B>
<types>
    <schema>
        <element name="myMethod">
            <complexType>
                <sequence>
                    <element name="x" type="xsd:int"/>
                    <element name="y" type="xsd:float"/>
                </sequence>
            </complexType>
        </element>
        <element name="myMethodResponse">
            <complexType/>
        </element>
    </schema>
</types>
<message name="myMethodRequest">
    <part name="parameters" element="myMethod"/>
</message>
<message name="empty">
    <part name="parameters" element="myMethodResponse"/>
</message>

<portType name="PT">
    <operation name="myMethod">
        <input message="myMethodRequest"/>
        <output message="empty"/>
    </operation>
</portType>

<binding .../>  
<!-- I won't bother with the details, just assume it's document/literal. -->

WSDL Schema 现在把参数放在包装中Q参?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">清单 9Q?/P>清单 9. 用于 myMethod 的文?文字包装?SOAP 消息
<soap:envelope>
    <soap:body>
        <myMethod>
            <x>5</x>
            <y>5.0</y>
        </myMethod>
    </soap:body>
</soap:envelope>

注意q个 SOAP 消息?RPC/文字?SOAP 消息Q?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">清单 5Q非常相伹{?zhn)可能会(x)说Q它看v来与 RPC/文字?SOAP 消息是完全一L(fng)Q不q,q两U消息之间存在着微妙的区别。在 RPC/文字?SOAP 消息中,<soap:body> ?<myMethod> 子句是操作的名称。在文档/文字包装?SOAP 消息中,<myMethod> 子句是单个输入消息的l成部分引用的元素的名称。因此,包装的样式具有这L(fng)一个特征,输入元素的名UC操作的名U是相同的。此样式是把操作名放?SOAP 消息的一Uy妙方式?/P>

文档/文字包装的样式的特征有:(x)

  • 输入消息只有一个组成部分?
  • 该部分是一个元素?
  • 该元素同操作有相同的名称?
  • 该元素的复杂cd没有属性?/LI>

下面是该U方法的优缺点:(x)

优点

  • 没有cd~码信息?
  • soap:body 中出现的所有内定w定义?schema 中,所以?zhn)可以很容易地(g)验此消息的有效性?
  • Ҏ(gu)名又出现?SOAP 消息中?
  • 文档/文字是遵?WS-I 的,q且包装模式W合?WS-I 的限Ӟ?SOAP 消息?soap:body 只有一个子元素?/LI>

~点

  • WSDL 更加复杂?/LI>

文档/文字包装的样式还是有一些缺点,不过与优Ҏ(gu)hQ它们都昑־微不道?/P>

RPC/文字包装Q?/B>
?WSDL 的角度来考虑Q没有理由只是把把包装的样式和文?文字l定联系在一赗它可以很容易地应用?RPC/文字l定。但是这样做是相当不明智的。SOAP 包含操作的一?myMethod 元素和元素名U的?myMethod 元素。另外,即它是一个合法的 WSDLQRPC/文字元素部分也不遵@ WS-I?/P>

文档/文字的样式在哪里定义Q?/SPAN>
q种包装cd来源?Microsoft?。ƈ没有M规范来定义这个类型;因此虽然q个cd是一个好东西Q但不幸的是Qؓ(f)了与 Microsoft 和其他公司的实现q行互操作,现在惟一的选择是Ҏ(gu) Microsoft WSDL 的输出来猜测它是如何工作的。该模式已经出现了一D|_(d)q且业界也很好的理解了它Q虽然该模式在例子中是非常明昄Q但是也有一些内容不够清晰。我们希望一个独立的l织比如 WS-I 来帮助稳定和标准化这一模式?/P>

Z么不始终采用文档/文字包装的样?/SPAN>
xQ本文已l给了?zhn)q样的一个印象,文档/文字包装的样式是最好的Ҏ(gu)。而实际的情况往往实如此。不q,仍然存在着一些情况,在这些情况下Q?zhn)最好是换一U别的样式?/P>

采用文档/文字非包装的样式的理?/SPAN>
如果(zhn)已l重载了操作Q就不能采用文档/文字包装的样式?/P>

惌一下,除了我们一直在使用的方法之外,q有另一U方法,请参?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">清单 10?/P>清单 10. 用于文档/文字包装的有问题的方?/B>
public void myMethod(int x, float y);
public void myMethod(int x);

关于重蝲的操作的注意事项
WSDL 2.0 不会(x)允许重蝲的操作。这对于一?I xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">允许该操作的语言Q比?JavaQ来说是不幸的。一些规范(比如 JAX-RPCQ将不得不定义一个名U{换模式(name mangling schemeQ来重载的Ҏ(gu)映射?WSDL 中。WSDL 2.0 只不q将问题?WSDL-to-SOAP 映射转移?WSDL-to-language 映射中?/P>

WSDL 允许重蝲的操作。但是当你向 WSDL 上添加包装模式的时候,需要元素有与操作相同的名称Qƈ且在 XML 中不能有两个名称相同的元素。所以?zhn)必须采用文?文字非包装的样式或某U?RPC 样式?/P>

采用 RPC/文字的样式的理由
׃文档/文字非包装的样式没有提供操作名,所以在有些情况下,(zhn)将需要采用某U?RPC 样式。比如说清单 11 中的一l方法?/P>



清单 11. 用于文档/文字非包装的样式的问题方?/B>
public void myMethod(int x, float y);
public void myMethod(int x);
public void someOtherMethod(int x, float y);

现在假设你的服务器接收到了文?文字?SOAP 消息Q你可以回头看一?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">清单 7。服务器应该发送哪一U方法呢Q所有?zhn)能确切知道的是Q它一定不?myMethod(int x)Q因为消息有两个参数Q而这U方法只需要一个参数。它可能是其他两U方法中的一U。采用文?文字的样式,(zhn)没有办法知道是哪一U方法?/P>

假定服务器接收到一?RPC/文字的消息,而不是文?文字的消息,?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">清单 5 所C。对于这U消息,服务器很Ҏ(gu)军_把它发送到哪一U方法。你知道该操作名U是 myMethodQƈ且你知道你有两个参数Q因此肯定是 myMethod(int x, float y)?/P>

采用 RPC/~码的理?/SPAN>
使用 RPC/~码样式最重要的原因是Z数据图表。设想你有一个二q制?wi),?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">清单 12 所C?/P>清单 12. 二进制树(wi)节点 schema
<complexType name="Node">
    <sequence>
        <element name="name" type="xsd:string"/>
        <element name="left" type="Node" xsd:nillable="true"/>
        <element name="right" type="Node" xsd:nillable="true"/>
    </sequence>
</complexType>

Ҏ(gu)q种节点定义Q你可以构徏一个树(wi)Q其根节?-- A -- 通过?右链接指向节?BQ参?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">?1Q?/P>

?1. ~码?wi)?/B>
~码?src="http://www-128.ibm.com/developerworks/cn/webservices/ws-whichwsdl/encodedtree.jpg"

发送数据图表的标准方式是?href 标签Q它?RPC/~码的样式(清单 13Q的一部分?/P>清单 13. RPC/~码的二q制?/B>
<A>
    <name>A</name>
    <left href="12345"/>
    <right href="12345"/>
</A>
<B id="12345">
    <name>B</name>
    <left xsi:nil="true"/>
    <right xsi:nil="true"/>
</B>

在Q何文字样式中Qhref 属性都是不可用的,q样囑Ş链接׃再v作用了(参阅清单 14 ??2Q。你仍然有一个根节点 AQ其指向左边的节?B和右边的另一个节?B。这些节?B 都是一L(fng)Q但是它们不是相同的节点。数据被复制而不是引用两ơ?/P>清单 14. 文字二进制树(wi)
<A>
    <name>A</name>
    <left>
        <name>B</name>
        <left xsi:nil="true"/>
        <right xsi:nil="true"/>
    </left>
    <right>
        <name>B</name>
        <left xsi:nil="true"/>
        <right xsi:nil="true"/>
    </right>
</A>

?2. 文字?/B>
文字?src="http://www-128.ibm.com/developerworks/cn/webservices/ws-whichwsdl/literaltree.jpg"

在文字样式中Q?zhn)可以通过各种Ҏ(gu)构造图表,但是却没有标准的Ҏ(gu)Q所以?zhn)做的M事情很可能不能与|络中其他端点上的服务进行互操作?/P>

SOAP 响应消息
到目前ؓ(f)止我已经讨论了请求消息。但是响应消息呢Q它们是怎样的呢Q现在你应该很清楚一个文?文字消息的响应消息应该是怎样的?CODE>soap:body 的内Ҏ(gu)?schema 定义的,因此你所需要做的就是查看该 schema 来了解响应消息的内容。比如,参?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">清单 15 来查?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">清单 8 中的 WSDL 文g的响应消息?/P>清单 15. 用于 myMethod 的文?文字包装的响?SOAP 消息
<soap:envelope>
    <soap:body>
        <myMethodResponse/>
    </soap:body>
</soap:envelope>

但是用于 RPC 样式响应?soap:body 的子元素是什么呢QWSDL 1.1 规范q不是很清楚。但?WS-I 解决了这个问题。WS-I ?Basic Profile 指明了在 RPC/文字响应消息中,soap:body 子元素的名称是?.. 相应?wsdl:operation 名称加上字符?'Response' 作ؓ(f)后缀。”奇怪!q正是常规包装模式的响应元素的名U。因?A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">清单 15 可以应用?RPC/文字消息和文?文字包装的消息。(因ؓ(f) RPC/~码q不是遵?WS-I 的,W(xu)S-I Basic Profile q不兛_ RPC/~码的响应是怎样的,但是你可以假讑ֺ用在q里的约定也可以应用在其他Q何地斏V)(j)因此响应消息的内容ƈ不神U?/P>

l束?/SPAN>
q里有四U绑定样式(其实是五个,但是文档/~码的样式是没有意义的)(j)。虽然每U样式都有自q用处Q但是在大多数情况下Q最好的样式是文?文字包装的样式?/P>

参考资?

关于作?/SPAN>
Russell Butek ?IBM 的一?Web 服务N。他?IBM WebSphere Web 服务引擎的开发h员之一。他也是 JAX-RPC Java Specification Request QJSRQ?专家l的 IBM 代表。他从事 Apache ?AXIS SOAP 引擎的实现方面的研究Q推动了 AXIS 1.0 遵@ JAX-RPC 1.0。以前,他是 IBM CORBA ORB 的开发h员和许多 OMG 特别工作l的 IBM 代表Q包括可UL拦截器特别工作组Q他是这个特别工作组的主席)(j)、核心特别工作组以及(qing)互操作性特别工作组。你可以通过 butek@us.ibm.com 与他联系?/TD>


GHawk 2005-12-02 13:36 发表评论
]]>
վ֩ģ壺 ҹһ| þþþ޹AV鶹| ҹӰ| þô| ؼƬѸƵ| ޳av| 츾͵ŷ| ޾ƷƵ| þþþùɫAVѹۿɫ| ޾ƷŮþþþ99| պƷר| Ʒһģʽ | պƷһ | ޾ƷƷԲۿ| Ƶһ߲| ѴƬ߹ۿcom| ĻƵ| ޾Ʒ| ޾ƷŮ| 91۲ݹ߹ۿ| AVAV˵| aŹavۺav| 91ѹۿ| ޾ƷAAƬѽ | ŷպƷһ| ƷƵ׽Ƶ| vƬ߹ۿڵ| ˳77777վ| Ļһ| һ| ޾Ʒ벻߲| 18ŮëƬˮ| ޾ƷҹӰ| ѹվ߹ۿͼ| ëƬ18ŮëƬ96| 18ͬ־videosվ| վ| ޾Ʒ | Ʒվ | 337pձŷ޴󵨾Ʒ555588| 3pˬִƵ|