﻿<?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-Vikings-文章分类-frame-work</title><link>http://www.blogjava.net/vikings/category/1406.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 02 Mar 2007 06:29:52 GMT</lastBuildDate><pubDate>Fri, 02 Mar 2007 06:29:52 GMT</pubDate><ttl>60</ttl><item><title>Tapestry 4.0 beta 新特性4-7</title><link>http://www.blogjava.net/Vikings/articles/18825.html</link><dc:creator>Vikings</dc:creator><author>Vikings</author><pubDate>Tue, 08 Nov 2005 10:00:00 GMT</pubDate><guid>http://www.blogjava.net/Vikings/articles/18825.html</guid><wfw:comment>http://www.blogjava.net/Vikings/comments/18825.html</wfw:comment><comments>http://www.blogjava.net/Vikings/articles/18825.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vikings/comments/commentRss/18825.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vikings/services/trackbacks/18825.html</trackback:ping><description><![CDATA[<TABLE class="fixedTable blogpost" cellSpacing=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=ellipse><SPAN class=bvTitle id=subjcns!1p1ioi_eYVz9QsG8enaV3Qww!117><STRONG>Tapestry4新特性(四)-源代码标注的异常处理</STRONG></SPAN></TD></TR>
<TR>
<TD class=bvh8><STRONG></STRONG></TD></TR>
<TR>
<TD id=msgcns!1p1ioi_eYVz9QsG8enaV3Qww!117>Tapestry本来提供的debug功能就十分强大，4.0版本中提供了更加详细的报错机制，可以显示错误的代码，并在报错的地方加亮标注，具体截图请看附件(谁能告诉我怎么将多余的照片删除呀)<BR></TD></TR>
<TR>
<TD>
<TABLE cellSpacing=0 border=0>
<TBODY>
<TR height=8>
<TD></TD></TR>
<TR>
<TD vAlign=top><A href="http://storage.msn.com/x1pc_jqddVOWRleOL7C8xpqaKS3AGUAvBT1MIRFANda_NKbU4VLeU4oBwzLDK28sn7jVevA1K85S_hQ00Oz6G95NKXye0F245JuqXGvav5vixzNs9HU6A4cW4wlt3uPg1dt" target=_blank></A></TD>
<TD width=15></TD>
<TD vAlign=top><A href="http://storage.msn.com/x1pc_jqddVOWRleOL7C8xpqaE6wMcs6GHfkEeobzxw3gm9L74d_98X_HPelfrDAeP4ryZOv3Na0PSRGZRf4Vd2egUFimfWPaMluwFJhPlY-yeupo2171dzHh9-_8XAZIzkS" target=_blank></A></TD></TR></TBODY></TABLE><IMG height=362 alt=x1pc_jqddVOWRleOL7C8xpqaKS3AGUAvBT1MIRFANda_NKbU4VLeU4oBwzLDK28sn7jVevA1K85S_hQ00Oz6G95NKXye0F245JuqXGvav5vixzNs9HU6A4cW4wlt3uPg1dt.jpg src="http://www.blogjava.net/images/blogjava_net/vikings/tapestry/x1pc_jqddVOWRleOL7C8xpqaKS3AGUAvBT1MIRFANda_NKbU4VLeU4oBwzLDK28sn7jVevA1K85S_hQ00Oz6G95NKXye0F245JuqXGvav5vixzNs9HU6A4cW4wlt3uPg1dt.jpg" width=600 border=0></TD></TR></TBODY></TABLE><BR><BR>
<TABLE class="fixedTable blogpost" cellSpacing=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=ellipse><SPAN class=bvTitle id=subjcns!1p1ioi_eYVz9QsG8enaV3Qww!120><STRONG></STRONG></SPAN></TD></TR>
<TR>
<TD class=bvh8><STRONG></STRONG></TD></TR>
<TR>
<TD id=msgcns!1p1ioi_eYVz9QsG8enaV3Qww!120>
<TABLE class="fixedTable blogpost" cellSpacing=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=ellipse><SPAN class=bvTitle id=subjcns!1p1ioi_eYVz9QsG8enaV3Qww!120><STRONG>Tapestry4新特性(五)-Friendly URLs</STRONG></SPAN></TD></TR>
<TR>
<TD class=bvh8><STRONG></STRONG></TD></TR>
<TR>
<TD id=msgcns!1p1ioi_eYVz9QsG8enaV3Qww!120>Tapestry4.0以前版本中的URL一直被人所诟病，当然现在已经有很多的解决方<BR>案，4.0版本中已经对此做了改进，<BR>因为现在的版本需要通过hivemind来配置，所以需要设置hivemind.xml中的一些属<BR>性，具体配置如下：<BR>&lt;?xml version="1.0"?&gt;&nbsp; <BR>&lt;module id="tapestry4" version="1.1.0"&gt;<BR>&nbsp;&lt;contribution configuration-id="tapestry.url.ServiceEncoders"&gt;<BR>&nbsp;&nbsp;&lt;page-service-encoder id="page" extension="html" service="page"/&gt;<BR>&nbsp;&nbsp;&lt;direct-service-encoder id="direct" stateless-extension="direct" <BR>&nbsp;&nbsp;&nbsp;stateful-extension="sdirect"/&gt;<BR>&nbsp;&nbsp;&lt;asset-encoder id="asset" path="/assets/"/&gt;<BR>&nbsp;&nbsp;&lt;extension-encoder id="extension" extension="svc" after="*"/&gt;<BR>&nbsp;&lt;/contribution&gt;<BR>&lt;/module&gt;<BR><BR>同时web.xml中加入映射：<BR>&lt;servlet&gt;<BR>&lt;servlet-name&gt;tapestry4&lt;/servlet-name&gt;<BR>&lt;servlet-class&gt; org.apache.tapestry.ApplicationServlet&lt;/servlet-class&gt;<BR>&lt;load-on-startup&gt;0&lt;/load-on-startup&gt;<BR>&lt;/servlet&gt;<BR>&lt;servlet-mapping&gt;<BR>&lt;servlet-name&gt;tapestry4&lt;/servlet-name&gt;<BR>&lt;url-pattern&gt;*.html&lt;/url-pattern&gt;<BR>&lt;/servlet-mapping&gt;<BR>&lt;servlet-mapping&gt;<BR>&lt;servlet-name&gt;tapestry4&lt;/servlet-name&gt;<BR>&lt;url-pattern&gt;*.direct&lt;/url-pattern&gt;<BR>&lt;/servlet-mapping&gt;<BR><BR>&lt;servlet-mapping&gt;<BR>&lt;servlet-name&gt;tapestry4&lt;/servlet-name&gt;<BR>&lt;url-pattern&gt;*.sdirect&lt;/url-pattern&gt;<BR>&lt;/servlet-mapping&gt;<BR>&lt;servlet-mapping&gt;<BR>&lt;servlet-name&gt;tapestry4&lt;/servlet-name&gt;<BR>&lt;url-pattern&gt;/assets/*&lt;/url-pattern&gt;<BR>&lt;/servlet-mapping&gt;<BR>&lt;servlet-mapping&gt;<BR>&lt;servlet-name&gt;tapestry4&lt;/servlet-name&gt;<BR>&lt;url-pattern&gt;*.svc&lt;/url-pattern&gt;<BR>&lt;/servlet-mapping&gt;<BR>如果希望首页的调用不是通过/app来映射，可以在web.xml中更改redirect：<BR>&lt;filter-name&gt;redirect&lt;/filter-name&gt;<BR>&lt;filter-class&gt;org.apache.tapestry.RedirectFilter&lt;/filter-class&gt;<BR>&lt;init-param&gt;<BR>&lt;param-name&gt;redirect-path&lt;/param-name&gt;<BR>&lt;param-value&gt;/Home.html&lt;/param-value&gt;<BR>&lt;/init-param&gt;<BR>&lt;/filter&gt;<BR>这样键入http://localhost:8080/tapestry4，系统导航到http://localhost:<BR>8080/tapestry4/Home.html,<BR>添加一个Page页面例如Test.page，在Home.html中加入&lt;a href="#"<BR>jwcid="@PageLink" page="Test"&gt;test&lt;/a&gt;，<BR>在生成的Home.html中生成的test的链接地址为：http://localhost:<BR>8080/tapestry4/Test.html<BR></TD></TR></TBODY></TABLE><BR></TD></TR>
<TR>
<TD>
<TABLE cellSpacing=0 border=0>
<TBODY></TBODY></TABLE></TD></TR></TBODY></TABLE>
<TABLE class="fixedTable blogpost" cellSpacing=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=ellipse><SPAN class=bvTitle id=subjcns!1p1ioi_eYVz9QsG8enaV3Qww!124><STRONG>Tapestry4新特性(六)-自动定位页面类文件</STRONG></SPAN></TD></TR>
<TR>
<TD class=bvh8><STRONG></STRONG></TD></TR>
<TR>
<TD id=msgcns!1p1ioi_eYVz9QsG8enaV3Qww!124>
<P><STRONG></STRONG></P>关于此特性的介绍请参考：<A href="http://jakarta.apache.org/tapestry/current/UsersGuide/page-class.html"><FONT color=#e86424>http://jakarta.apache.org/tapestry/current/UsersGuide/page-class.html </FONT></A><STRONG>说明：<BR></STRONG>通俗点说就是您可以不定义.page文件或者定义的.page文件中不指定class 属性，而让服务器自动根据.html文件的路径来寻找对应的类文件。 <STRONG>配置：<BR></STRONG>在.application的定义文件中添加： 
<META value="org.edynasty.pages" key="org.apache.tapestry.page-class-packages">这样如果在文档根目录下有个Home.html文件，你就可以将Home.java放到 org.edynasty.pages(实际开发中配置为您自己的包名)包中，tapestry自动根据 Home.hmtl构造org.edynasty.pages.Home来定位页面的类文件,当然您也可以在WEB -INF目录下放一个Home.page,不需要定义class属性，tapestry自动按照上边的原 理定位。 <STRONG>效果：<BR></STRONG>这样您可以不需要维护.page中的class属性，直接根据.html文件来写对应 的类文件。而且可以根据业务逻辑来定义目录结构，例如将 org.edynasty.pages.user定义为user相关的类，.html也就可以放到user目录下 边，目录结构如下： user/ListUsers.html user/EditUser.html course/ListCourses.html course/EditCourses.html Home.html</TD></TR></TBODY></TABLE><BR><BR>
<TABLE class="fixedTable blogpost" cellSpacing=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=ellipse><SPAN class=bvTitle id=subjcns!1p1ioi_eYVz9QsG8enaV3Qww!125><STRONG></STRONG></SPAN></TD></TR>
<TR>
<TD class=bvh8><STRONG></STRONG></TD></TR>
<TR>
<TD id=msgcns!1p1ioi_eYVz9QsG8enaV3Qww!125>
<TABLE class="fixedTable blogpost" cellSpacing=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=ellipse><SPAN class=bvTitle id=subjcns!1p1ioi_eYVz9QsG8enaV3Qww!125><STRONG>Tapestry4新特性(七)-Application和Session范围对象的使用</STRONG></SPAN></TD></TR>
<TR>
<TD class=bvh8><STRONG></STRONG></TD></TR>
<TR>
<TD id=msgcns!1p1ioi_eYVz9QsG8enaV3Qww!125>Application和Session范围对象的使用<BR><BR>关于此特性的介绍请参考：http://jakarta.apache.org/tapestry/UsersGuide/state.html<BR>说明：<BR>Application和Session范围的概念就不说了，T4以前的版本只可以分别指定一个对象，<BR>以前版本的定义如下:<BR>&lt;property name="org.apache.tapestry.visit-class" value="your.package.Visit"/&gt;<BR>&lt;property name="org.apache.tapestry.global-class" value="your.package.Global"/&gt;,<BR>T4中可以指定任意多的对象，而且默认的visit和global仍然可以使用。<BR><BR>配置：在hivemodule.xml的定义文件中添加：<BR>&lt;contribution configuration-id="tapestry.state.ApplicationObjects"&gt;<BR>&lt;state-object name="applicationUser" scope="application"&gt;<BR>&lt;create-instance class="org.edynasty.model.User"/&gt;<BR>&lt;/state-object&gt; <BR>&lt;state-object name="sessionUser" scope="session"&gt;<BR>&lt;create-instance class="org.edynasty.model.User"/&gt;<BR>&lt;/state-object&gt; <BR>&lt;/contribution&gt;<BR>两个user分别对应Application和Session范围，在需要使用user的page中注入：<BR>&lt;inject property="applicationUser" type="state" object="applicationUser"/&gt;<BR>&lt;inject property="sessionUser" type="state" object="sessionUser"/&gt;，通过<BR>getter和setter方法调用。<BR><BR>效果：怎么说呢，可以不需要在一个visit中定义N多属性，因为Session的创建需要资源，<BR>只要操作一个visit的属性，就需要创建整个visit，分别定义之后，可以在需要存取时分别创建。</TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><img src ="http://www.blogjava.net/Vikings/aggbug/18825.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vikings/" target="_blank">Vikings</a> 2005-11-08 18:00 <a href="http://www.blogjava.net/Vikings/articles/18825.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TapeStry 4.0 beta 新特性 1-3</title><link>http://www.blogjava.net/Vikings/articles/18824.html</link><dc:creator>Vikings</dc:creator><author>Vikings</author><pubDate>Tue, 08 Nov 2005 09:55:00 GMT</pubDate><guid>http://www.blogjava.net/Vikings/articles/18824.html</guid><wfw:comment>http://www.blogjava.net/Vikings/comments/18824.html</wfw:comment><comments>http://www.blogjava.net/Vikings/articles/18824.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vikings/comments/commentRss/18824.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vikings/services/trackbacks/18824.html</trackback:ping><description><![CDATA[[原文]<BR><A href="http://spaces.msn.com/members/jface/PersonalSpace.aspx?_c01_blogpart=blogmgmt&amp;_c=blogpart">http://spaces.msn.com/members/jface/PersonalSpace.aspx?_c01_blogpart=blogmgmt&amp;_c=blogpart</A><BR><BR>
<TABLE class="fixedTable blogpost" cellSpacing=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=ellipse><SPAN class=bvTitle id=subjcns!1p1ioi_eYVz9QsG8enaV3Qww!114><STRONG>Tapestry4新特性(一)－default binding types</STRONG></SPAN></TD></TR>
<TR>
<TD class=bvh8><STRONG></STRONG></TD></TR>
<TR>
<TD id=msgcns!1p1ioi_eYVz9QsG8enaV3Qww!114>
<P><EM>一、default binding types(</EM>默认的绑定类型)<BR>&nbsp;&nbsp;&nbsp; 每一个组件的参数都可以定义默认的绑定类型，如果一个绑定的参数没有前缀，将使用默认的绑定类型。<BR>&nbsp;&nbsp;&nbsp; 下面的代码实现同样的功能:<BR></P>
<P>
<UL element="ul" jwcid="@Foreach" source="ognl:items" value="ognl:item">
<LI><SPAN jwcid="@Insert" value="<B>ognl:item.name</B>"></LI></UL>
<P></P>
<P>
<UL element="ul" jwcid="@Foreach" source="items" value="item">
<LI><SPAN jwcid="@Insert" value="<B>item.name</B>"></LI></UL>&nbsp;&nbsp;&nbsp; 
<P></P>
<P>&nbsp;&nbsp;&nbsp;&nbsp; 加粗的部分显示前后的变化，之所以可以这样定义，是因为Insert组件定义value参数的默认绑定类型为ongl.<BR>&nbsp;&nbsp;&nbsp;&nbsp; 注意：默认的绑定参数总是可以被显式的绑定声明覆盖掉。<BR>&nbsp;&nbsp;&nbsp; 如果没有定义默认的绑定参数，那么在html模板中定义的默认绑定参数为literal，页面定义文件里的默认绑定参数为ognl<BR><BR></P>
<P><STRONG>修订：</STRONG></P>
<P>从beta4版本开始，此特性已经被删除， </P>
<P>Beta4的change log：</P>
<P>&nbsp;Remove default-binding attribute from element(HLS) </P>
<P>但是“如果没有定义默认的绑定参数，那么在html模板中定义的默认绑定参数为literal，页面定义文件里的默认绑定参数为ognl”这个效果经测试依然存在。 </P>
<P>怀念：</P>
<P>此段文字在beta3中存在，beta4后就删掉了！</P>
<H2>Binding Type Defaults</H2>
<DIV>
<P>Tapestry 4.0 introduces a new idea: <EM>default binding types</EM>. Each component parameter may define a default binding type (using the default-binding attribute of the <A href="http://spaces.msn.com/mmm2005-08-03_15.21/spec.html#spec.parameter"><U><FONT color=#0000ff><PARAMETER></FONT></U></A>element). </P>
<P>If a binding reference does not have a prefix, the default binding type is used. </P>
<P>Because of this, the following two snippets are identical: </P><PRE><UL element="ul" jwcid="@Foreach" source="ognl:items" value="ognl:item">
  <LI><SPAN jwcid="@Insert" value="ognl:item.name">
</LI></UL></PRE><PRE><UL element="ul" jwcid="@Foreach" source="items" value="item">
  <LI><SPAN jwcid="@Insert" value="item.name">
</LI></UL></PRE>
<P>This works because the <A href="http://spaces.msn.com/tapestry/ComponentReference/Insert.html"><U><FONT color=#0000ff>Insert</FONT></U></A> component defines the default-binding for the value parameter to be "ognl". Likewise, the source and value parameters of the <A href="http://spaces.msn.com/tapestry/ComponentReference/Foreach.html"><U><FONT color=#0000ff>Foreach</FONT></U></A> component are defined to be "ognl". However, the element parameter of the <A href="http://spaces.msn.com/tapestry/ComponentReference/Foreach.html"><U><FONT color=#0000ff>Foreach</FONT></U></A> component has a binding type of "literal". </P>
<P>This is a decision made by the component author. If a particular parameter is (nearly) always bound using a particular binding type, then a default-binding may be set. The default binding can <EM>always</EM> be overriden with an explicit binding type prefix. </P>
<P>What about parameters that don't define a default binding type? The answer to this question (which includes all informal parameters), is that it depends on whether the parameter is bound in an HTML template, or in a page or component specification. In an HTML template, the default binding type is "literal". In a specification, the default binding type is "ognl". </P></DIV></SPAN></SPAN></SPAN></SPAN></TD></TR></TBODY></TABLE><BR><BR>
<TABLE class="fixedTable blogpost" cellSpacing=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=ellipse><SPAN class=bvTitle id=subjcns!1p1ioi_eYVz9QsG8enaV3Qww!115><STRONG>Tapestry4新特性(二)－listener method</STRONG></SPAN></TD></TR>
<TR>
<TD class=bvh8><STRONG></STRONG></TD></TR>
<TR>
<TD id=msgcns!1p1ioi_eYVz9QsG8enaV3Qww!115>二、listener method<BR>&nbsp;&nbsp;&nbsp;&nbsp; 如果使用过tapestry的应该知道listener方法在4.X以前版本中的定义，如public void formSubmit(IRequestCycle cycle)，方法必须<BR>有一个IRequestCycle参数。参数的取得方式如下：Object[] parameters = cycle.getServiceParameters();<BR>&nbsp;&nbsp;&nbsp;&nbsp; 在4.X中参数的取得可以通过以下两种方式：<BR>
<OL>
<LI>调用<A href="http://jakarta.apache.org/tapestry/current/tapestry/apidocs/org/apache/tapestry/IRequestCycle.html"><FONT color=#e86424>IRequestCycle</FONT></A>.getListenerParameters()方法,需要传入IRequestCycle实例作为参数。 
<LI>按照参数的声明顺序依次定义为listener方法的参数。</LI></OL>
<P>&nbsp;&nbsp;&nbsp;&nbsp; 第二种方法比较符合软件的设计思维，而且参数的类型在传入后保存，而不是想象中的统一String类型。<BR>例如：<BR><A jwcid="@DirectLink" listener="doClick" parameters="{ objectId, index }">. . . </A><BR>其中objectId为String类型，index为int，声明中使用了默认的参数绑定类型。 <BR>对应的方法声明如下 <BR>public void doClick(String objectId, int index) <BR>{ . . . } <BR>此为第二种方式，可见方法的定义符合自然习惯，当然你也可以通过传统的方法，如下所示： public void doClick(IRequestCycle cycle) <BR>{ Object[] parameters = cycle.getListenerParameters(); <BR>String objectId = (String)parameters[0]; <BR>int index = ((Integer)parameters[1]).intValue(); . . . }&nbsp;<BR>这种方式是为了向后兼容以前的版本，当然也适用那种参数数目不确定的情况。 Tapestry默认搜索以下的方法声明： </P>
<UL>
<LI>public void <EM>method</EM>(<EM>parameters</EM>)（页面的跳转 cycle.activate()如何实现？） 
<LI>public void <EM>method</EM>(IRequestCycle cycle, <EM>parameters</EM>) （倾向于使用此方式） 
<LI>public void <EM>method</EM>()（无需参数传递和页面跳转的情况，估计可能性不大） 
<LI>public void <EM>method(IRequestCycle cycle)（传统方式）</EM></LI></UL>&nbsp;&nbsp; 不要试图通过参数的类型来映射listener方法，tapestry是根据参数的数目来确定方法的。<BR><BR></TD></TR></TBODY></TABLE>
<TABLE class="fixedTable blogpost" cellSpacing=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=ellipse><SPAN class=bvTitle id=subjcns!1p1ioi_eYVz9QsG8enaV3Qww!116><STRONG>Tapestry4新特性(三)－global property source</STRONG></SPAN></TD></TR>
<TR>
<TD class=bvh8><STRONG></STRONG></TD></TR>
<TR>
<TD id=msgcns!1p1ioi_eYVz9QsG8enaV3Qww!116>三、Global Property Source(全局的消息属性配置)<BR>消息属性配置听起来不是很舒服，暂时这样称呼好了，消息属性配置也就是通称的国际化配<BR>置，通过配置一个properties文件使不同语言的浏览者看到对应语言的版本，一般<BR>的使用如下，一个page页面，例如example.page,同目录下放一个<BR>example.properties,在 example.html中使用<SPAN key="key">来指定显示值，<BR>中文可以使用example_zh_CN.properties来配置。看起来挺方便的，可<BR>tapestry4.0以前的版本的国际化不支持全局的属性配置文件，必须每个页面定义<BR>自己的，无法几个页面共享，但实际开发中，多页面共享属性配置是很常见的，<BR>tapestry4.0中可以通过以下方式获得全局的属性配置文件：<BR>创建一个跟你的项目全局配置文件，如yourApp.application,此文件在4.0以前的<BR>版本中是必须的，4.0中如果没有必要配置，可以不需要此文件(扯远了),yourApp<BR>是根据你在web.xml定义的，例如<BR><SERVLET><BR><SERVLET-NAME>tapesty4</SERVLET-NAME><BR><SERVLET-CLASS>org.apache.tapestry.ApplicationServlet</SERVLET-CLASS><BR><LOAD-ON-STARTUP>1</LOAD-ON-STARTUP><BR></SERVLET><BR>那属性定义文件就应该是tapestry4.properties,这样在此文件中定义一个：test=<BR>测试，在Home.html中使用&lt; span key="test"&gt;test</SPAN>,看到“测试”正确显示。<BR></TD></TR></TBODY></TABLE><img src ="http://www.blogjava.net/Vikings/aggbug/18824.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vikings/" target="_blank">Vikings</a> 2005-11-08 17:55 <a href="http://www.blogjava.net/Vikings/articles/18824.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Jive论坛与Spring框架,经典代码和架构! </title><link>http://www.blogjava.net/Vikings/articles/4815.html</link><dc:creator>Vikings</dc:creator><author>Vikings</author><pubDate>Wed, 18 May 2005 15:46:00 GMT</pubDate><guid>http://www.blogjava.net/Vikings/articles/4815.html</guid><wfw:comment>http://www.blogjava.net/Vikings/comments/4815.html</wfw:comment><comments>http://www.blogjava.net/Vikings/articles/4815.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vikings/comments/commentRss/4815.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vikings/services/trackbacks/4815.html</trackback:ping><description><![CDATA[Jive论坛与Spring框架 
<P align=center><A href="http://www.jdon.com/aboutme.htm"><FONT color=#002c99>板桥里人</FONT></A> http://www.jdon.com 2004/07/01</P>
<P>　　没有一种新技术是凭空诞生的，它的萌芽或胚胎总是或多或少显现于以前的技术中，Jive论坛是大家潜心研究的设计型应用程序，其相关解析可见本栏的GoF设计模式专栏。</P>
<P>　　Jive和Spring同为由JavaBeans组成的J2EE Web系统，Jive作为早期成功设计案例，其主要架构成为大多数纯JavaBeans系统的流行架构，Spring也不例外。</P>
<P>　　Spring框架除了是一种Web层应用框架，还提供了访问EJB层的接口，也有JDBC/ORM的直接操作。Spring框架主要魅力是使用IoC模式和AOP实现了Jive系统的通用功能，从而使得Jive这样的纯JavaBeans架构设计可以重用在其它系统中。</P>
<P>　　如果你感慨于Jive的设计理念，但是又苦于无法重用其设计时，Spring框架已经帮你实现了。</P>
<P>　　同时也要注意到：Spring框架类似“杂烩”，它包含了很多J2EE应用的工具，类如对EJB的调用，它的MVC与Struts JSF也是相竞争的，以纯Ioc和AOP设计来说，Spring框架也是一种很重的(Heavy、Weight)框架。Spring框架是复杂的，如果想以Spring替代EJB，那么无疑按了葫芦浮起瓢。</P>
<P>　　将Jive论坛和Spring框架联系起来，会帮助更多理解设计模式的程序员迅速掌握最新的设计思潮，而不是一种跳跃式的强迫接受。如果你对Jive有很好的研究，将会发现Spring框架是Jive设计的更加通用的提升。</P>
<P>　　在Jive中,ForumFactory是整个系统的入口和突破点，Jive通过ForumFactory将整个系统掌控在一个工厂模式下，这样做的好处是：便于控制系统的JavaBeans，例如，客户端通过ForumFactory可创建一个Forum或访问一个Forum，但是是否有权限访问呢？如下图：</P>
<P align=center><IMG height=155 src="http://www.jdon.com/AOPdesign/images/jivespring.jpg" width=272><BR>　　<BR>　　 Jive通过ForumFactory将这种访问引导到相应的Proxy类去，如ForumFactoryProxy类等，通过代理模式对这些类进行权限控制访问。这是代理模式的一个主要用处，但是研读Jive的代理模式会发现，要为每个类实现一个Proxy类，非常琐碎，有没有更优雅的方式呢？ 当然使用动态代理。</P>
<P>　　Spring框架基本是抽象上述设计，Spring框架对所有JavaBeans的管理也是基于一个总入口Bean Factory机制，不同的是，BeanFactory可以 管理所有应用的JavaBeans，使用者只要将自己的JavaBeans通过配置文件告诉BeanFactory，那么BeanFactory将会加载这些JavaBeans，例如：</P>
<P>　　&lt;beans&gt;<BR>　　　　&lt;bean id="exampleBean" class="eg.ExampleBean"/&gt;<BR>　　　　&lt;bean id="anotherExample" class="eg.ExampleBeanTwo"/&gt;<BR>　　&lt;/beans&gt;<BR><BR>　　在Jive中，ForumFactory加载Jive自己的JavaBeans是通过工厂实现DbForumFactory实现的，如下代码，DbForumFactory引发了后台一系列功能实现，这是纵向，而return new ForumFactoryProxy这个语句则类似引来一个切面，从一个横向方面实现了权限访问等功能：</P>
<TABLE width="90%" bgColor=#cccccc border=0>
<TBODY>
<TR>
<TD>
<P>private static String className = "com.jivesoftware.forum.database.DbForumFactory"; </P>
<P>public static ForumFactory getInstance(Authorization authorization) { <BR>　　　　 //If no valid authorization passed in, return null. <BR>　　　　 if (authorization == null) { <BR>　　　　　　 return null; <BR>　　　　 } <BR>　　　　 //以下使用了Singleton 单态模式 <BR>　　　　 if (factory == null) { <BR>　　　　　　 synchronized(initLock) { <BR>　　　　　　　　 if (factory == null) { <BR>　　　　　　　　　　　　 ...... </P>
<P>　　　　 　　　　 try { <BR>　　　　　　　　　　　　　　 //动态转载类 <BR>　　　　　　　　　　　　　　 Class c = Class.forName(className); <BR>　　　　　　　　　　　　　　 factory = (ForumFactory)c.newInstance(); <BR>　　　　　　　　　　 } <BR>　　　　　　　　　　 catch (Exception e) { <BR>　　　　　　　　　　　　　　 return null; <BR>　　　　　　　　　　 } <BR>　　　　　　　　 } <BR>　　　　　　 } <BR>　　　　 } </P>
<P>　　　　 //Now, 返回 proxy.用来限制授权对forum的访问 <BR>　　　　 return new ForumFactoryProxy(authorization, factory, 　　　　　　　　　　　　　　　　　　　 factory.getPermissions(authorization)); <BR>　　 } </P></TD></TR></TBODY></TABLE>
<P>　　既然Spring框架也是通过一个Bean Factory加载所有的类，那么它是如何加载的？通过IoC模式，也就是依赖性注射模式。在我以前文章“<A href="http://www.jdon.com/AOPdesign/Ioc.htm" target=_blank><FONT color=#002c99>IoC模式</FONT></A>”中，我比较了Factory工厂模式创建对象和Ioc模式的注射对象实现之间的异同，Ioc相比工厂模式则更加解耦了调用者和被调用者之间关系，使用Ioc模式，无需在调用者代码中涉及被调用者的具体实现。</P>
<P>　　Spring框架不但可以向自己容器中注射应用者自己定义的JavaBeans（也就是创建它们），而且也可以向这些JavaBeans通过set方法实现数据赋值。</P>
<P>　　一旦Bean Factory运行时刻掌管这些激活的对象，Spring通过AOP方式，从一个横切面为这些JavaBeans提供了权限访问、事务锁等通用功能的实现，这种实现是基于动态代理模式，而动态代理是AOP实现的一种方式。</P>
<P>　　前面提到，Jive中使用代理模式实现权限访问，比代理模式更加简洁和抽象的是动态代理，使用动态代理将使得调用者无需指定被调用者的代理类，这是动态代理区别代理模式的本质。</P>
<P>　　动态代理这一优势，又可以体现在另外一句话语上：动态代理拦截了调用者对被调用者的调用，正是这一功能符合了AOP的拦截器功能，为AOP实现提供了可能。</P>
<P>　　Spring框架使用了动态代理实现的AOP，正是通过动态代理机制拦截了外界对Bean Factory管理下的对象的调用。如下图：</P>
<P align=center><IMG height=166 src="http://www.jdon.com/AOPdesign/images/springfwk.jpg" width=300></P>
<P align=center>&nbsp;</P>
<P align=left>　　以上只是大体解构了Spring的架构，Spring框架在这个架构下，还顺带了很多其它功能，如Web MVC、 DAO JDBC、 DAO ORM 、以及remote，后者类似我设计的EJB方法调用框架。</P>
<P align=left>　　总之，Spring确实是Ioc和AOP的完美应用，Ioc用来装载JavaBeans，创建这些对象；AOP用来拦截这些对象的使用，这才是框架设计的必然经典方式。</P>
<P align=left>&nbsp;</P>
<P align=left>ZT:<BR><A href="http://www.zahui.com/html/6/40477.htm">http://www.zahui.com/html/6/40477.htm</A></P></SPAN><img src ="http://www.blogjava.net/Vikings/aggbug/4815.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vikings/" target="_blank">Vikings</a> 2005-05-18 23:46 <a href="http://www.blogjava.net/Vikings/articles/4815.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EJB 工作原理 (ZT) -相见恨晚</title><link>http://www.blogjava.net/Vikings/articles/4013.html</link><dc:creator>Vikings</dc:creator><author>Vikings</author><pubDate>Tue, 03 May 2005 19:04:00 GMT</pubDate><guid>http://www.blogjava.net/Vikings/articles/4013.html</guid><wfw:comment>http://www.blogjava.net/Vikings/comments/4013.html</wfw:comment><comments>http://www.blogjava.net/Vikings/articles/4013.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Vikings/comments/commentRss/4013.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Vikings/services/trackbacks/4013.html</trackback:ping><description><![CDATA[<SPAN class=postbody>原帖: xanada ----<A href="http://www.hibernate.org.cn/viewtopic.php?t=3832&amp;postdays=0&amp;postorder=asc&amp;start=0"><BR>http://www.hibernate.org.cn/viewtopic.php?t=3832&amp;postdays=0&amp;postorder=asc&amp;start=0</A><BR><BR>前两天在这个版块的精华区里翻到了Robbin关于EJB的调用原理的分析，受益非浅，但感觉用纯文字来表达效果似乎不够直观，而且对RMI的阐述也略嫌少了些。这里我根据自己的一点体会，在Robbin帖子的基础上再来说说这个话题，供大家参考。 <BR><BR>首先，我想先说说RMI的工作原理，因为EJB毕竟是基于RMI的嘛。废话就不多讲了，RMI的本质就是实现在不同JVM之间的调用，工作原理图如下： <BR><BR><IMG src="http://www.cs.ucsd.edu/classes/sp00/cse225/notes/eric/DayoftheLollipop_files/image011.jpg" border=0> <BR><BR>它的实现方法就是在两个JVM中各开一个Stub和Skeleton，二者通过socket通信来实现参数和返回值的传递。 <BR><BR>有关RMI的例子代码网上可以找到不少，但绝大部分都是通过extend the interface java.rmi.Remote实现，已经封装的很完善了，不免使人有雾里看花的感觉。下面的例子是我在《Enterprise JavaBeans》里看到的，虽然很粗糙，但很直观，利于很快了解它的工作原理。 <BR><BR>1. 定义一个Person的接口，其中有两个business method, getAge() 和getName() <BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR><SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>interface</SPAN> Person <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>int</SPAN> getAge<SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>throws</SPAN> <SPAN style="COLOR: #aaaadd" ?>Throwable</SPAN>; <BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> <SPAN style="COLOR: #aaaadd" ?>String</SPAN> getName<SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>throws</SPAN> <SPAN style="COLOR: #aaaadd" ?>Throwable</SPAN>; <BR><SPAN style="COLOR: #000000">}</SPAN> <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>2. Person的实现PersonServer类 <BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR><SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>class</SPAN> PersonServer <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>implements</SPAN> Person <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>int</SPAN> age; <BR>&nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>String</SPAN> name; <BR><BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> PersonServer<SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #aaaadd" ?>String</SPAN> name, <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>int</SPAN> age<SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; this.<SPAN style="COLOR: #000000">age</SPAN> = age; <BR>&nbsp; &nbsp; &nbsp; &nbsp; this.<SPAN style="COLOR: #000000">name</SPAN> = name; <BR>&nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR><BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>int</SPAN> getAge<SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>return</SPAN> age; <BR>&nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR><BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> <SPAN style="COLOR: #aaaadd" ?>String</SPAN> getName<SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>return</SPAN> name; <BR>&nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR><SPAN style="COLOR: #000000">}</SPAN> <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>3. 好，我们现在要在Client机器上调用getAge()和getName()这两个business method，那么就得编写相应的Stub(Client端)和Skeleton(Server端)程序。这是Stub的实现： <BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR><SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>import</SPAN> java.<SPAN style="COLOR: #000000">io</SPAN>.<SPAN style="COLOR: #000000">ObjectOutputStream</SPAN>; <BR><SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>import</SPAN> java.<SPAN style="COLOR: #000000">io</SPAN>.<SPAN style="COLOR: #000000">ObjectInputStream</SPAN>; <BR><SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>import</SPAN> java.<SPAN style="COLOR: #000000">net</SPAN>.<SPAN style="COLOR: #000000">Socket</SPAN>; <BR><BR><SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>class</SPAN> Person_Stub <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>implements</SPAN> Person <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>Socket</SPAN> socket; <BR><BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> Person_Stub<SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>throws</SPAN> <SPAN style="COLOR: #aaaadd" ?>Throwable</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #6666ff">// connect to skeleton</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; socket = <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>new</SPAN> <SPAN style="COLOR: #aaaadd" ?>Socket</SPAN><SPAN style="COLOR: #000000">(</SPAN>"computer_name", <SPAN style="COLOR: #000000" ?>9000</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR><BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>int</SPAN> getAge<SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>throws</SPAN> <SPAN style="COLOR: #aaaadd" ?>Throwable</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #6666ff">// pass method name to skeleton</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>ObjectOutputStream</SPAN> outStream = <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>new</SPAN> <SPAN style="COLOR: #aaaadd" ?>ObjectOutputStream</SPAN><SPAN style="COLOR: #000000">(</SPAN>socket.<SPAN style="COLOR: #000000">getOutputStream</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; outStream.<SPAN style="COLOR: #000000">writeObject</SPAN><SPAN style="COLOR: #000000">(</SPAN>"age"<SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; outStream.<SPAN style="COLOR: #000000">flush</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR><BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>ObjectInputStream</SPAN> inStream = <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>new</SPAN> <SPAN style="COLOR: #aaaadd" ?>ObjectInputStream</SPAN><SPAN style="COLOR: #000000">(</SPAN>socket.<SPAN style="COLOR: #000000">getInputStream</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>return</SPAN> inStream.<SPAN style="COLOR: #000000">readInt</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR><BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> <SPAN style="COLOR: #aaaadd" ?>String</SPAN> getName<SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>throws</SPAN> <SPAN style="COLOR: #aaaadd" ?>Throwable</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #6666ff">// pass method name to skeleton</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>ObjectOutputStream</SPAN> outStream = <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>new</SPAN> <SPAN style="COLOR: #aaaadd" ?>ObjectOutputStream</SPAN><SPAN style="COLOR: #000000">(</SPAN>socket.<SPAN style="COLOR: #000000">getOutputStream</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; outStream.<SPAN style="COLOR: #000000">writeObject</SPAN><SPAN style="COLOR: #000000">(</SPAN>"name"<SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; outStream.<SPAN style="COLOR: #000000">flush</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR><BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>ObjectInputStream</SPAN> inStream = <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>new</SPAN> <SPAN style="COLOR: #aaaadd" ?>ObjectInputStream</SPAN><SPAN style="COLOR: #000000">(</SPAN>socket.<SPAN style="COLOR: #000000">getInputStream</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>return</SPAN> <SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #aaaadd" ?>String</SPAN><SPAN style="COLOR: #000000">)</SPAN>inStream.<SPAN style="COLOR: #000000">readObject</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR><SPAN style="COLOR: #000000">}</SPAN> <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>注意，Person_Stub和PersonServer一样，都implements Person。它们都实现了getAge()和getName()两个business method，不同的是PersonServer是真的实现，Person_Stub是建立socket连接，并向Skeleton发请求，然后通过Skeleton调用PersonServer的方法，最后接收返回的结果。 <BR><BR>4. Skeleton实现 <BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR><SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>import</SPAN> java.<SPAN style="COLOR: #000000">io</SPAN>.<SPAN style="COLOR: #000000">ObjectOutputStream</SPAN>; <BR><SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>import</SPAN> java.<SPAN style="COLOR: #000000">io</SPAN>.<SPAN style="COLOR: #000000">ObjectInputStream</SPAN>; <BR><SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>import</SPAN> java.<SPAN style="COLOR: #000000">net</SPAN>.<SPAN style="COLOR: #000000">Socket</SPAN>; <BR><SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>import</SPAN> java.<SPAN style="COLOR: #000000">net</SPAN>.<SPAN style="COLOR: #000000">ServerSocket</SPAN>; <BR><BR><SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>class</SPAN> Person_Skeleton <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>extends</SPAN> <SPAN style="COLOR: #aaaadd" ?>Thread</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; PersonServer myServer; <BR><BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> Person_Skeleton<SPAN style="COLOR: #000000">(</SPAN>PersonServer server<SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #6666ff">// get reference of object server</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; this.<SPAN style="COLOR: #000000">myServer</SPAN> = server; <BR>&nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR><BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>void</SPAN> run<SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>try</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #6666ff">// new socket at port 9000</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>ServerSocket</SPAN> serverSocket = <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>new</SPAN> <SPAN style="COLOR: #aaaadd" ?>ServerSocket</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000" ?>9000</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #6666ff">// accept stub's request</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>Socket</SPAN> socket = serverSocket.<SPAN style="COLOR: #000000">accept</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR><BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>while</SPAN> <SPAN style="COLOR: #000000">(</SPAN>socket != <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>null</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #6666ff">// get stub's request</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>ObjectInputStream</SPAN> inStream = <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>new</SPAN> <SPAN style="COLOR: #aaaadd" ?>ObjectInputStream</SPAN><SPAN style="COLOR: #000000">(</SPAN>socket.<SPAN style="COLOR: #000000">getInputStream</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>String</SPAN> method = <SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #aaaadd" ?>String</SPAN><SPAN style="COLOR: #000000">)</SPAN>inStream.<SPAN style="COLOR: #000000">readObject</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR><BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #6666ff">// check method name</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>if</SPAN> <SPAN style="COLOR: #000000">(</SPAN>method.<SPAN style="COLOR: #000000">equals</SPAN><SPAN style="COLOR: #000000">(</SPAN>"age"<SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #6666ff">// execute object server's business method</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>int</SPAN> age = myServer.<SPAN style="COLOR: #000000">getAge</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>ObjectOutputStream</SPAN> outStream = <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>new</SPAN> <SPAN style="COLOR: #aaaadd" ?>ObjectOutputStream</SPAN><SPAN style="COLOR: #000000">(</SPAN>socket.<SPAN style="COLOR: #000000">getOutputStream</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR><BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #6666ff">// return result to stub</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; outStream.<SPAN style="COLOR: #000000">writeInt</SPAN><SPAN style="COLOR: #000000">(</SPAN>age<SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; outStream.<SPAN style="COLOR: #000000">flush</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR><BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>if</SPAN><SPAN style="COLOR: #000000">(</SPAN>method.<SPAN style="COLOR: #000000">equals</SPAN><SPAN style="COLOR: #000000">(</SPAN>"name"<SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #6666ff">// execute object server's business method</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>String</SPAN> name = myServer.<SPAN style="COLOR: #000000">getName</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>ObjectOutputStream</SPAN> outStream = <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>new</SPAN> <SPAN style="COLOR: #aaaadd" ?>ObjectOutputStream</SPAN><SPAN style="COLOR: #000000">(</SPAN>socket.<SPAN style="COLOR: #000000">getOutputStream</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR><BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #6666ff">// return result to stub</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; outStream.<SPAN style="COLOR: #000000">writeObject</SPAN><SPAN style="COLOR: #000000">(</SPAN>name<SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; outStream.<SPAN style="COLOR: #000000">flush</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>catch</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #aaaadd" ?>Throwable</SPAN> t<SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.<SPAN style="COLOR: #000000">printStackTrace</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>System</SPAN>.<SPAN style="COLOR: #000000">exit</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000" ?>0</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR>&nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR><BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>static</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>void</SPAN> main<SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #aaaadd" ?>String</SPAN> args <SPAN style="COLOR: #000000">[</SPAN><SPAN style="COLOR: #000000">]</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #6666ff">// new object server</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; PersonServer person = <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>new</SPAN> PersonServer<SPAN style="COLOR: #000000">(</SPAN>"Richard", <SPAN style="COLOR: #000000" ?>34</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR><BR>&nbsp; &nbsp; &nbsp; &nbsp; Person_Skeleton skel = <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>new</SPAN> Person_Skeleton<SPAN style="COLOR: #000000">(</SPAN>person<SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; skel.<SPAN style="COLOR: #000000">start</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR><SPAN style="COLOR: #000000">}</SPAN> <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>Skeleton类 extends from Thread，它长驻在后台运行，随时接收client发过来的request。并根据发送过来的key去调用相应的business method。 <BR><BR>5. 最后一个，Client的实现 <BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR><SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>class</SPAN> PersonClient <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>public</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>static</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>void</SPAN> main<SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #aaaadd" ?>String</SPAN> <SPAN style="COLOR: #000000">[</SPAN><SPAN style="COLOR: #000000">]</SPAN> args<SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>try</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Person person = <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>new</SPAN> Person_Stub<SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>int</SPAN> age = person.<SPAN style="COLOR: #000000">getAge</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>String</SPAN> name = person.<SPAN style="COLOR: #000000">getName</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>System</SPAN>.<SPAN style="COLOR: #000000">out</SPAN>.<SPAN style="COLOR: #000000">println</SPAN><SPAN style="COLOR: #000000">(</SPAN>name + " is " + age + " years old"<SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>catch</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #aaaadd" ?>Throwable</SPAN> t<SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.<SPAN style="COLOR: #000000">printStackTrace</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR>&nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR><SPAN style="COLOR: #000000">}</SPAN> <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>Client的本质是，它要知道Person接口的定义，并实例一个Person_Stub，通过Stub来调用business method，至于Stub怎么去和Server沟通，Client就不用管了。 <BR><BR>注意它的写法： <BR>Person person = new Person_Stub(); <BR>而不是 <BR>Person_Stub person = new Person_Stub(); <BR><BR>为什么？因为要面向接口编程嘛，呵呵。 <BR><BR>感谢您有耐心看到这里，关于RMI，我想说的就这么多了。但是好象还没写到EJB，本人就累了个半死，算了，我还是先去睡觉，明天再往下续吧。。。<BR><BR><SPAN class=postbody>本人没有用过Weblogic，这里就结合WebSphere来讲讲各个类的调用关系吧。 <BR><BR>假定我们要创建一个读取User信息的SessionBean，需要我们写的有3个文件： <BR>1. UserServiceHome.java <BR>Home接口 <BR><BR>2. UserService.java <BR>Remote接口 <BR><BR>3. UserServiceBean.java <BR>Bean实现 <BR><BR>WSAD最终会生成10个class。其它7个是什么呢？我们一个一个数过来： <BR><BR>4. _UserServiceHome_Stub.java <BR>这个当然就是Home接口在Client端(动态加载)的Stub类了，它implements UserServiceHome。 <BR><BR>5. _EJSRemoteStatelessUserServiceHome_a940aa04_Tie.java <BR>Home接口在Server端的Skeleton类，"a940aa04"应该是随机生成的，所有其他的相关class名里都会有这个标志串，Tie是Corba对Skeleton的叫法。 <BR><BR>6. EJSRemoteStatelessUserServiceHome_a940aa04.java <BR>Home接口在Server端的实现，当然，它也implements UserServiceHome。 <BR><BR>7. EJSStatelessUserServiceHomeBean_a940aa04.java <BR>由#6调用，create _UserService_Stub。(为什么#6不能直接create _UserService_Stub呢？后面再讲。) <BR><BR>8. _UserService_Stub.java <BR>Remote接口在Client端(动态加载)的Stub类。它implements UserService。 <BR><BR>9. _EJSRemoteStatelessUserService_a940aa04_Tie.java <BR>Remote接口在Server端的Skeleton类。 <BR><BR>10. EJSRemoteStatelessUserService_a940aa04.java <BR>Remote接口在Server端的实现，当然，它也implements UserService。并且，它负责调用UserServiceBean——也就是我们所写的Bean实现类——里面的business method。 <BR><BR>那么，各个类之间的调用关系到底是怎么样的呢？简单的说，就是两次RMI循环。<BR><BR><SPAN class=postbody>先来看看Client端的程序是怎么写的： <BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR><SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>try</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>InitialContext</SPAN> ctx = <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>new</SPAN> <SPAN style="COLOR: #aaaadd" ?>InitialContext</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR><BR>&nbsp; &nbsp; <SPAN style="COLOR: #6666ff">//第一步</SPAN> <BR>&nbsp; &nbsp; UserServiceHome home = <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #000000">(</SPAN>UserServiceHome<SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #aaaadd" ?>PortableRemoteObject</SPAN>.<SPAN style="COLOR: #000000">narrow</SPAN><SPAN style="COLOR: #000000">(</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx.<SPAN style="COLOR: #000000">lookup</SPAN><SPAN style="COLOR: #000000">(</SPAN>JNDIString<SPAN style="COLOR: #000000">)</SPAN>, <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UserServiceHome.<SPAN style="COLOR: #000000">class</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR><BR>&nbsp; &nbsp; <SPAN style="COLOR: #6666ff">//home: _UserServiceHome_Stub</SPAN> <BR>&nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>System</SPAN>.<SPAN style="COLOR: #000000">out</SPAN>.<SPAN style="COLOR: #000000">println</SPAN><SPAN style="COLOR: #000000">(</SPAN>home.<SPAN style="COLOR: #000000">toString</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR><BR>&nbsp; &nbsp; <SPAN style="COLOR: #6666ff">//第二步</SPAN> <BR>&nbsp; &nbsp; UserService object = home.<SPAN style="COLOR: #000000">create</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR><BR>&nbsp; &nbsp; <SPAN style="COLOR: #6666ff">//ojbect: _UserService_Stub</SPAN> <BR>&nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>System</SPAN>.<SPAN style="COLOR: #000000">out</SPAN>.<SPAN style="COLOR: #000000">println</SPAN><SPAN style="COLOR: #000000">(</SPAN>object.<SPAN style="COLOR: #000000">toString</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR><BR>&nbsp; &nbsp; <SPAN style="COLOR: #6666ff">//第三步</SPAN> <BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>int</SPAN> userId = <SPAN style="COLOR: #000000" ?>1</SPAN>; <BR>&nbsp; &nbsp; UserInfo ui = object.<SPAN style="COLOR: #000000">getUserInfo</SPAN><SPAN style="COLOR: #000000">(</SPAN>userId<SPAN style="COLOR: #000000">)</SPAN>; <BR><SPAN style="COLOR: #000000">}</SPAN> <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>在第一步之后，我们得到了一个UserServiceHome(interface)定义的对象home，那么，home到底是哪个class的instance呢？用debug看一下，知道了home原来就是_UserServiceHome_Stub的实例。 <BR><BR>从第二步开始，就是我们的关注所在，虽然只有简单的一行代码， <BR>UserService object = home.create(); <BR>但是他背后的系统是怎么运做的呢？我们进入代码来看吧： <BR><BR>1. 调用home.create() <BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR>UserServiceHome home; <BR>UserService obj = home.<SPAN style="COLOR: #000000">create</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>2. 实际是调用_UserServiceHome_Stub.create()，在这个方法里面，Stub向Skeleton发送了一个create的字串： <BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR>org.<SPAN style="COLOR: #000000">omg</SPAN>.<SPAN style="COLOR: #000000">CORBA</SPAN>.<SPAN style="COLOR: #000000">portable</SPAN>.<SPAN style="COLOR: #000000">OutputStream</SPAN> out = _request<SPAN style="COLOR: #000000">(</SPAN>"create", <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>true</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>in = <SPAN style="COLOR: #000000">(</SPAN>org.<SPAN style="COLOR: #000000">omg</SPAN>.<SPAN style="COLOR: #000000">CORBA_</SPAN><SPAN style="COLOR: #000000" ?>2</SPAN>_<SPAN style="COLOR: #000000" ?>3</SPAN>.<SPAN style="COLOR: #000000">portable</SPAN>.<SPAN style="COLOR: #000000">InputStream</SPAN><SPAN style="COLOR: #000000">)</SPAN>_invoke<SPAN style="COLOR: #000000">(</SPAN>out<SPAN style="COLOR: #000000">)</SPAN>; <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>3. Server端的Skeleton接收Stub发来的request，并调用相应的方法： <BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR>_EJSRemoteStatelessUserServiceHome_a940aa04_Tie._invoke<SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; ...... <BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>switch</SPAN> <SPAN style="COLOR: #000000">(</SPAN>method.<SPAN style="COLOR: #000000">length</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>case</SPAN> <SPAN style="COLOR: #000000" ?>6</SPAN>: <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>if</SPAN> <SPAN style="COLOR: #000000">(</SPAN>method.<SPAN style="COLOR: #000000">equals</SPAN><SPAN style="COLOR: #000000">(</SPAN>"create"<SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>return</SPAN> create<SPAN style="COLOR: #000000">(</SPAN>in, reply<SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; ...... <BR>&nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR><SPAN style="COLOR: #000000">}</SPAN> <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR>_EJSRemoteStatelessUserServiceHome_a940aa04_Tie.<SPAN style="COLOR: #000000">create</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; EJSRemoteStatelessUserServiceHome_a940aa04 target = <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>null</SPAN>; <BR>&nbsp; &nbsp; result = target.<SPAN style="COLOR: #000000">create</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; org.<SPAN style="COLOR: #000000">omg</SPAN>.<SPAN style="COLOR: #000000">CORBA</SPAN>.<SPAN style="COLOR: #000000">portable</SPAN>.<SPAN style="COLOR: #000000">OutputStream</SPAN> out = reply.<SPAN style="COLOR: #000000">createReply</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; <SPAN style="COLOR: #aaaadd" ?>Util</SPAN>.<SPAN style="COLOR: #000000">writeRemoteObject</SPAN><SPAN style="COLOR: #000000">(</SPAN>out,result<SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>return</SPAN> out; <BR><SPAN style="COLOR: #000000">}</SPAN> <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>4. Skeleton调用的是UserServiceHome的Server端实现类的create方法 <BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR>EJSRemoteStatelessUserServiceHome_a940aa04.<SPAN style="COLOR: #000000">create</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; UserService _EJS_result; <BR>&nbsp; &nbsp; _EJS_result = EJSStatelessUserServiceHomeBean_a940aa04.<SPAN style="COLOR: #000000">create</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR><SPAN style="COLOR: #000000">}</SPAN> <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>5. #4又调用EJSStatelessUserServiceHomeBean_a940aa04.create() <BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR>&nbsp; &nbsp; UserService result = super.<SPAN style="COLOR: #000000">createWrapper</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>new</SPAN> BeanId<SPAN style="COLOR: #000000">(</SPAN>this, <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>null</SPAN><SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>至此，我们终于结束了第一个RMI循环，并得到了Remote接口UserService的Stub类_UserService_Stub，就是#5里面的result。 <BR><BR>这里有一个问题，为什么#4不直接create _UserService_Stub，而又转了一道#5的手呢？因为#4 extends from EJSWrapper，它没有能力create Stub，因此必须借助#5，which extends from EJSHome，这样才可以生成一个Stub。如果不是为了生成这个Stub，应该可以不走#5这一步。<BR><BR><SPAN class=postbody>OK, now we got the object which is instanceOf _UserService_Stub, and implements UserService <BR><BR>现在我们的Client端走到第三步了： <BR>UserInfo ui = object.getUserInfo(userId); <BR><BR>继续看代码，开始第二个RMI循环： <BR><BR>1. 调用object.getUserInfo() <BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR>UserService object; <BR>object.<SPAN style="COLOR: #000000">getUserInfo</SPAN><SPAN style="COLOR: #000000">(</SPAN>userId<SPAN style="COLOR: #000000">)</SPAN>; <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>2. 实际是调用_UserService_Stub.getUserInfo(int arg0)，在这个方法里面，Stub向Skeleton发送了一个getUserInfo的字串和arg0这个参数： <BR><BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR>org.<SPAN style="COLOR: #000000">omg</SPAN>.<SPAN style="COLOR: #000000">CORBA</SPAN>.<SPAN style="COLOR: #000000">portable</SPAN>.<SPAN style="COLOR: #000000">OutputStream</SPAN> out = _request<SPAN style="COLOR: #000000">(</SPAN>"getUserInfo", <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>true</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>out.<SPAN style="COLOR: #000000">write_long</SPAN><SPAN style="COLOR: #000000">(</SPAN>arg0<SPAN style="COLOR: #000000">)</SPAN>; <BR>in = <SPAN style="COLOR: #000000">(</SPAN>org.<SPAN style="COLOR: #000000">omg</SPAN>.<SPAN style="COLOR: #000000">CORBA_</SPAN><SPAN style="COLOR: #000000" ?>2</SPAN>_<SPAN style="COLOR: #000000" ?>3</SPAN>.<SPAN style="COLOR: #000000">portable</SPAN>.<SPAN style="COLOR: #000000">InputStream</SPAN><SPAN style="COLOR: #000000">)</SPAN>_invoke<SPAN style="COLOR: #000000">(</SPAN>out<SPAN style="COLOR: #000000">)</SPAN>; <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>3. Server端的Skeleton接收Stub发来的request，并调用相应的方法： <BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR>_EJSRemoteStatelessUserService_a940aa04_Tie._invoke<SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>switch</SPAN> <SPAN style="COLOR: #000000">(</SPAN>method.<SPAN style="COLOR: #000000">charAt</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000" ?>5</SPAN><SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN> <BR>&nbsp; &nbsp; <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>case</SPAN> <SPAN style="COLOR: #000000" ?>83</SPAN>: <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>if</SPAN> <SPAN style="COLOR: #000000">(</SPAN>method.<SPAN style="COLOR: #000000">equals</SPAN><SPAN style="COLOR: #000000">(</SPAN>"getUserInfo"<SPAN style="COLOR: #000000">)</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>return</SPAN> getUserInfo<SPAN style="COLOR: #000000">(</SPAN>in, reply<SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR>&nbsp; &nbsp; &nbsp; &nbsp; ...... <BR>&nbsp; &nbsp; <SPAN style="COLOR: #000000">}</SPAN> <BR><SPAN style="COLOR: #000000">}</SPAN> <BR><BR>_EJSRemoteStatelessUserService_a940aa04_Tie.<SPAN style="COLOR: #000000">getUserInfo</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; EJSRemoteStatelessUserService_a940aa04 target = <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>null</SPAN>; <BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>int</SPAN> arg0 = in.<SPAN style="COLOR: #000000">read_long</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; UserDTO result = target.<SPAN style="COLOR: #000000">getUserInfo</SPAN><SPAN style="COLOR: #000000">(</SPAN>arg0<SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; org.<SPAN style="COLOR: #000000">omg</SPAN>.<SPAN style="COLOR: #000000">CORBA_</SPAN><SPAN style="COLOR: #000000" ?>2</SPAN>_<SPAN style="COLOR: #000000" ?>3</SPAN>.<SPAN style="COLOR: #000000">portable</SPAN>.<SPAN style="COLOR: #000000">OutputStream</SPAN> out = reply.<SPAN style="COLOR: #000000">createReply</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; out.<SPAN style="COLOR: #000000">write_value</SPAN><SPAN style="COLOR: #000000">(</SPAN>result,UserDTO.<SPAN style="COLOR: #000000">class</SPAN><SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; <SPAN style="FONT-WEIGHT: bold; COLOR: #990066" ?>return</SPAN> out; <BR><SPAN style="COLOR: #000000">}</SPAN> <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>4. Skeleton调用的是UserService的Server端实现类的getUserInfo方法 <BR></SPAN>
<TABLE cellSpacing=1 cellPadding=3 width="90%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=genmed><B>java代码:&nbsp;</B></SPAN></TD></TR>
<TR>
<TD class=code>
<DIV style="FONT-FAMILY: 'Courier New', Courier, monospace"><BR><BR>EJSRemoteStatelessUserService_a940aa04.<SPAN style="COLOR: #000000">getUserInfo</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #000000">)</SPAN> <SPAN style="COLOR: #000000">{</SPAN> <BR>&nbsp; &nbsp; UserServiceBean _EJS_beanRef = container.<SPAN style="COLOR: #000000">preInvoke</SPAN><SPAN style="COLOR: #000000">(</SPAN>this, <SPAN style="COLOR: #000000" ?>0</SPAN>, _EJS_s<SPAN style="COLOR: #000000">)</SPAN>; <BR>&nbsp; &nbsp; _EJS_result = _EJS_beanRef.<SPAN style="COLOR: #000000">getUserInfo</SPAN><SPAN style="COLOR: #000000">(</SPAN>id<SPAN style="COLOR: #000000">)</SPAN>; <BR><SPAN style="COLOR: #000000">}</SPAN> <BR></DIV><BR></TD></TR></TBODY></TABLE><SPAN class=postbody><BR><BR>最后的最后，#4终于调用了我们写的UserServiceBean里的getUserInfo方法，这才是我们真正想要去做的事情。 <BR><BR>至此，第二个RMI循环也终于结束了。<BR><BR><SPAN class=postbody>回顾一下上面的分析，可以很清晰的看到两次RMI循环的过程，下图(见链接)描述了整个流程： <BR><BR><A class=postlink href="http://www.pbase.com/image/27229257" target=_blank><FONT color=#002c99>http://www.pbase.com/image/27229257</FONT></A>&nbsp;<BR><A href="http://mk23.image.pbase.com/u42/nobo123/upload/27229257.ejb2.jpg">http://mk23.image.pbase.com/u42/nobo123/upload/27229257.ejb2.jpg</A><BR><BR>黄色的1，6，10是程序员要写的，其余是系统生成的。 <BR><BR>#1是Home interface, #2和#4都implements 了它。 <BR>#6是Remote interface, #7和#9都implements 了它。 <BR>#10是Bean实现。 <BR><BR>写到这里，基本要说的就说完了。这实在是一项累死人的工作，希望您能稀饭。欢迎补充，欢迎摘错。谢谢，呵呵。<BR><BR></SPAN><SPAN class=postbody></SPAN><SPAN class=gensmall><BR><SPAN class=postbody>简单讲，就是为了适应分布式开发的需要。 <BR><BR>首先，回到我最后给出的流程图。 <BR><BR>Client端最原始的冲动，肯定是能直接调用#10.UserServiceBean就爽了。那么第一个问题来了， <BR><SPAN style="FONT-WEIGHT: bold">Client和Server不在一个JVM里</SPAN>。 <BR><BR>这好办，我们不是有RMI吗，好，这个问题就这么解决了： <BR>1. UserServiceBeanInterface.getUserInfo() <BR>2. UserServiceBeanStub <BR>3. UserServiceBeanSkeleton <BR>4. UserServiceBean <BR><BR>用着用着，第二个问题来了， <BR><SPAN style="FONT-WEIGHT: bold">UserServiceBean只有人用，没人管理，transaction logic, security logic, bean instance pooling logic这些不得不考虑的问题浮出水面了</SPAN>。 <BR><BR>OK，我们想到用一个delegate，EJBObject，来进行所有这些logic的管理。client和EJBObject打交道，EJBObject调用UserServiceBean。 <BR><BR>注意，这个EJBObject也是一个Interface，#6.UserService这个interface正是从它extends而来。并且EJBObject所管理的这些logic，正是AppServer的一部分。 <BR><BR>现在的流程变为了： <BR>EJBObject <BR>1. UserService.getUserInfo() <BR>2. UserServiceStub <BR>3. UserServiceSkeleton <BR>4. UserServiceImp <BR>5. UserServiceBean <BR><BR>这已经和整幅图里的#6, #7, #8, #9, #10一一对应了。 <BR><BR>现在能满足我们的需求了吗？不，第三个问题又来了： <BR><SPAN style="FONT-WEIGHT: bold">既然是分布式开发，那么我当然没理由只用一个Specified Server，我可能需要用到好几个不同的Server，而且EJBObject也需要管理呀</SPAN> <BR><BR>OK，为了适应你的需要，我们还得加再一个HomeObject，首先它来决定用哪个Server(当然，是由你用JNDI String设定的)，其次，它来管理EJBObject。 <BR><BR>注意，这个EJBHome也是一个Interface，#1.UserServiceHome这个interface正是从它extends而来。并且EJBHome管理EJBObject的logic，也是AppServer的一部分。 <BR><BR>现在的调用次序是 <BR>1. EJBHome.create() <BR>2. EJBHomeStub <BR>3. EJBHomeSkeleton <BR>4. EJBHomeImp(EJSWrapper) <BR>5. EJSHome <BR><BR>得到EJBObject <BR><BR>6. UserService.getUserInfo() <BR>7. UserServiceStub <BR>8. UserServiceSkeleton <BR>9. UserServiceImp <BR>10. UserServiceBean <BR><BR>现在已经完全和流程图的调用顺序一致了。 <BR><BR>综上所述，EJB的调用确实很麻烦，但是搞的这么麻烦，确实是有搞的麻烦的道理，实在是不得不为也。 <BR><BR>哎哟，好累啊。希望我把这个问题说清楚了，您也没给我绕迷糊。谢谢。</SPAN></SPAN></SPAN></SPAN></SPAN></SPAN><img src ="http://www.blogjava.net/Vikings/aggbug/4013.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Vikings/" target="_blank">Vikings</a> 2005-05-04 03:04 <a href="http://www.blogjava.net/Vikings/articles/4013.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>