建国's profile小白的生活PhotosBlogLists Tools Help

Blog


    May 28

    我对EJB3调用原理的彻底理解

    首先里面涉及容器内和跨容器调用,对我来说so easy! 跨容器需要预配置容器外classload的jndi环境,具体咨询我就ok了!
      一个远程对象至少要包括4个class文件:远程对象;远程对象的接口;实现远程接口的对象的stub;对象的skeleton这4个class文件。    
       
      在EJB中则至少要包括10个class:    
      Bean类,特定App   Server的Bean实现类    
      Bean的remote接口,特定App   Server的remote接口实现类,特定App   Server的remote接口的实现类的stub类和skeleton类    
      Bean的home接口,特定App   Server的home接口实现类,特定App   Server的home接口的实现类的stub类和skeleton类    
       
      和RMI不同的是,EJB中这10个class真正需要用户编写的只有3个,分别是Bean类和它的remote接口,home接口,至于其它的7个class到底是怎么生成,被打包在什么地方,或者是否需要更多的类文件,会根据不同的App   Server表现出比较大的差异,不能一概而论。    
       
      拿我最熟悉的Weblogic的来说吧,Weblogic的Bean实现类,以及两个接口的Weblogic的实现类是在ejbc的时候被打包到EJB的jar包里面的,这3个class文件可以看到。而home接口和remote接口的Weblogic的实现类的stub类和skeleton类是在EJB被部署到Weblogic的时候,由Weblogic动态生成stub类和Skeleton类的字节码,因此看不到这4个类文件。    
       
      对于一次客户端远程调用EJB,要经过两个远程对象的多次RMI循环。首先是通过JNDI查找Home接口,获得Home接口的实现类,这个过程其实相当复杂,首先是找到Home接口的Weblogic实现类,然后创建一个Home接口的Weblogic实现类的stub类的对象实例,将它序列化传送给客户端(注意stub类的实例是在第1次RMI循环中,由服务器动态发送给客户端的,因此不需要客户端保存Home接口的Weblogic实现类的stub类),最后客户端获得该stub类的对象实例(普通的RMI需要在客户端保存stub类,而EJB不需要,因为服务器会把stub类的对象实例发送给客户端)。    
       
      客户端拿到服务器给它的Home接口的Weblogic实现类的stub类对象实例以后,调用stub类的create方法,(在代码上就是home.create(),但是后台要做很多事情),于是经过第2次RMI循环,在服务器端,Home接口的Weblogic实现类的skeleton类收到stub类的调用信息后,由它再去调用Home接口的Weblogic实现类的create方法。    
       
      在服务端,Home接口的Weblogic实现类的create方法再去调用Bean类的Weblogic实现类的ejbCreate方法,在服务端创建或者分配一个EJB实例,然后将这个EJB实例的远程接口的Weblogic实现类的stub类对象实例序列化发送给客户端。    
       
      客户端收到remote接口的Weblogic实现类的stub类的对象实例,对该对象实例的方法调用(在客户端代码中实际上就是对remote接口的调用),将传送给服务器端remote接口的Weblogic实现类的skeleton类对象,而skeleton类对象再调用相应的remote接口的Weblogic实现类,然后remote接口的Weblogic实现类再去调用Bean类的Weblogic实现类,如此就完成一次EJB对象的远程调用。    
       
      看了一遍帖子,感觉还是没有说太清楚,既然写了帖子,就想彻底把它说清楚。    
       
      先拿普通RMI来说,有4个class,分别是远程对象,对象的接口,对象的stub类和skeleton类。而对象本身和对象的stub类同时都实现了接口类。而我们在客户端代码调用远程对象的时候,虽然在代码中操纵接口,实质上是在操纵stub类,例如:    
      接口类:Hello    
      远程对象:Hello_Server    
      stub类:Hello_Stub    
      skeleton类:Hello_Skeleton    
       
      客户端代码要这样写:    
      Hello   h   =   new   Hello_Stub();    
      h.getString();    
       
      我们不会这些写:    
      Hello_Stub   h   =   new   Hello_Stub();    
      h.getString();    
       
      因为使用接口适用性更广,就算更换了接口实现类,也不需要更改代码。因此客户端需要Hello.class和Hello_Stub.class这两个文件。但是对于EJB来说,就不需要Hello_Stub.class,因为服务器会发送给它,但是Hello.class文件客户端是省不了的,必须有。表面上我们的客户端代码在操纵Hello,但别忘记了Hello只是一个接口,抽象的,实质上是在操纵Hello_Stub。    
       
      拿Weblogic上的EJB举例子,10个class分别是:    
      Bean类:HelloBean   (用户编写)    
      Bean类的Weblogic实现类:HelloBean_Impl   (EJBC生成)    
       
      Home接口:HelloHome   (用户编写)    
      Home接口的Weblogic实现类   HelloBean_HomeImpl(EJBC生成)    
      Home接口的Weblogic实现类的stub类   HelloBean_HomeImpl_WLStub(部署的时候动态生成字节码)    
      Home接口的Weblogic实现类的skeleton类   HelloBean_HomeImpl_WLSkeleton(部署的时候动态生成字节码)    
       
      Remote接口:   Hello   (用户编写)    
      Remote接口的Weblogic实现类   HelloBean_EOImpl(EJBC生成)    
      Remote接口的Weblogic实现类的stub类   HelloBean_EOImpl_WLStub(部署的时候动态生成字节码)    
      Remote接口的Weblogic实现类的skeleton类   HelloBean_EOImpl_WLSkeleton(部署的时候动态生成字节码)    
       
      客户端只需要Hello.class和HelloHome.class这两个文件。    
       
      HelloHome   home   =   (Home)   PortableRemoteObject.narrow(ctx.lookup("Hello"),   HelloHome.class);    
       
      这一行代码是从JNDI获得Home接口,但是请记住!接口是抽象的,那么home这个对象到底是什么类的对象实例呢?很简单,用toString()输出看一下就明白了,下面一行是输出结果:    
      HelloBean_HomeImpl_WLStub@18c458    
      这表明home这个通过从服务器的JNDI树上查找获得的对象实际上是HelloBean_HomeImpl_WLStub类的一个实例。    
      接下来客户端代码:    
       
      Hello   h   =   home.create()    
       
      同样Hello只是一个抽象的接口,那么h对象是什么东西呢?打印一下:    
      HelloBean_EOImpl_WLStub@8fa0d1    
      原来是HelloBean_EOImpl_WLStub的一个对象实例。    
       
      用这个例子来简述一遍EJB调用过程:    
       
      首先客户端JNDI查询,服务端JNDI树上Hello这个名字实际上绑定的对象是HelloBean_HomeImpl_WLStub,所以服务端将创建HelloBean_HomeImpl_WLStub的一个对象实例,序列化返回给客户端。    
       
      于是客户端得到home对象,表面上是得到HelloHome接口的实例,实际上是进行了一次远程调用得到了HelloBean_HomeImpl_WLStub类的对象实例,别忘记了HelloBean_HomeImpl_WLStub也实现了HelloHome接口。    
       
      然后home.create()实质上就是HelloBean_HomeImpl_WLStub.create(),该方法将发送信息给HelloBean_HomeImpl_WLSkeleton,而HelloBean_HomeImpl_WLSkeleton接受到信息后,再去调用HelloBean_HomeImpl的create方法,至此完成第1次完整的RMI循环。    
       
      注意在这次RMI循环过程中,远程对象是HelloBean_HomeImpl,远程对象的接口是HelloHome,对象的stub是HelloBean_HomeImpl_WLStub,对象的skeleton是HelloBean_HomeImpl_WLSkeleton。    
       
      然后HelloBean_HomeImpl再去调用HelloBean_Impl的ejbCreate方法,而HelloBean_Impl的ejbCreate方法将负责创建或者分配一个Bean实例,并且创建一个HelloBean_EOImpl_WLStub的对象实例。    
       
      这一步比较有趣的是,在前一步RMI循环中,远程对象HelloBean_HomeImpl在客户端有一个代理类HelloBean_HomeImpl_WLStub,但在这一步,HelloBean_HomeImpl自己却充当了HelloBean_Impl的代理类,只不过HelloBean_HomeImpl不在客户端,而是在服务端,因此不进行RMI。    
       
      然后HelloBean_EOImpl_WLStub的对象实例序列化返回给客户端,这一步也很有趣,上次RMI过程,主角是HelloBean_HomeImpl和它的代理类HelloBean_HomeImpl_WLStub,但这这一次换成了HelloBean_EOImpl和它的代理类HelloBean_EOImpl_WLStub来玩了。    
       
       
      Hello   h   =   home.create();h.helloWorld();    
       
      假设Hello接口有一个helloWorld远程方法,那么表面上是在调用Hello接口的helloWorld方法,实际上是在调用HelloBean_EOImpl_WLStub的helloWorld方法。    
       
      然后HelloBean_EOImpl_WLStub的helloWorld方法将发送信息给服务器上的HelloBean_EOImpl_WLSkeleton,而HelloBean_EOImpl_WLSkeleton收到信息以后,再去调用HelloBean_EOImpl的helloWorld方法。至此,完成第2次完整的RMI循环过程。    
       
      在刚才HelloBean_EOImpl是作为远程对象被调用的,它的代理类是HelloBean_EOImpl_WLStub,但现在HelloBean_EOImpl要作为HelloBean_Impl的代理类了。现在HelloBean_EOImpl去调用HelloBean_Impl的helloWorld方法。注意!HelloBean_Impl继承了HelloBean,而HelloBean中的helloWorld方法是我们亲自编写的代码,现在终于调用到了我们编写的代码了!    
       
      至此,一次EJB调用过程终于完成。在整个过程中,服务端主要要调用的类是HelloBean_Impl,   HelloBean_HomeImpl,HelloBean_HomeImpl_WLSkeleton,HelloBean_EOImpl,HelloBean_EOImpl_WLSkeleton。客户端主要调用的类是HelloBean_HomeImpl_WLStub,HelloBean_EOImpl_WLStub,这两个类在客户端代码中并不会直接出现,出现在代码中的类是他们的接口HelloHome和Hello,因此客户端需要这两个接口文件,而Stub是服务器传送给他们的。
    May 27

    我的创业历程-IM的心路历程

    要问我,做IM为了什么,第一,当然是为了赚钱,想它可以赚钱.第二,其实赚钱的方法很多,为什么我想做IM呢?最关键的,我感觉现在网络对我们日常生活的影响,还是太有限.所以想用它让网络进一步的贴近我们的日常生活.
    May 18

    我的VC++之路

    “N次失败,1次成功,还学的不怎么样……你也太笨了吧!”如果您有这样的评价,那么祝贺您,您已经了解了我这人的99.9%。N这个数字具体是多少连我自己也记不清楚,保守地讲(N≥6==TRUE)这个表达式是能够成立的。回想我的Visual C++入门过程,一路过来,绝对不是像黄飞鸿的功夫那样潇洒精彩,而更像是一颗石头顺流而下,在河床底摸爬滚打、磕磕碰碰。今天是周末,我就把以前N次失败留给我的经验教训胡写上几笔,如果有朋友看到这篇拙文,又刚好打算尝试一下Visual C++,也就算是我给您留下的莽原一径吧。

      一.C++语言的基础

      说起入门慢,第一个原因莫过于语言基础了.高中时期学校组织的微机兴趣小组学习的是PASCAL语言(我也不知道为什么要讲这个语言,如果说是为了应付比赛,当时也有C语言组呀),所以在大学转向Windows编程的时候,我首先选择了Delphi.大三的时候学校要求考国家二级,二级没有Delphi,于是又转向了VB,原因是VB做起来与Delphi很像。后来发现VB的IDE做的比Delphi好用,而且BASIC语言写起来简单,于是便弃Delphi而去(明眼人恐怕又要骂我了,若不是太懒,怎么会喜欢VB的IDE呢?的确是这样,后文会提到,懒不仅仅是学习VC的大敌,而且懒人是什么都学不好的)。长年与VB打交道,让我对C/C++语言很不习惯——我不喜欢C++写一个句语要打一个分号,我不喜欢大小写字母要严格区分,我不喜欢比较的时候要写两个等号,我不喜欢……总之,对C++很没好感,没好感也就没兴趣学了(后面提到兴趣是相当重要的)。当然如果你现在再问我应该学习什么语言,我会毫不犹豫地向你推荐C++,因为就常用语言而言,C++语言中包含的知识是相当全面的——从面向过程,到基于对象/面向对象,再到模板和范型,可以说是应有尽有,不夸张地说,别的语言在某种程度上而言是C++语言的子集或者说是在模仿C++、向C++靠拢。

      在数次失败中,给我很明显的感觉就是,不学好C++语言就学习Visual C++纯粹是一种自虐。这次入门之前,我花了3个多月的时间系统地学习了C++语言,够意思吧。然后我信心实足地敲响Visual C++的家门,呵呵,这次她终于肯给面子了。举个例子吧,在看Dll的调用时,用到“函数指针”,顺理成章就看下去了,想一想如果没有C++语言的基础,基本是不可能的。所以说,没学会中文之前,别看《红楼梦》,那不是《看图识字》。奉劝想从VB转向VC学习的朋友,如果你指望能像学习VB一样边学习VC边学习C++语言,那你可就错了:)

      顺便提醒C++语言入门的朋友一点,应该关注ANSI/ISO C++,也就是标准C++了,市面上C++的书良莠不齐,很多书是“旧书换新皮”,讲的仍然是非标准C++,一定要选好。计算机书很贵,大家不妨找电子版的来看,网上有很多,甚至《C++ Primer》或者《C++沉思录》这样的好书也有热心朋友放到了网上。不过,我最喜欢的是《C++编程金典》这本书,不愧是教育大师写的书,用来学习很合适。至于编译器的选择,如果条件允许就安装VS.NET2003吧,据说Visual C++7.1的编译器是目前对标准C++支持的最好的编译器了。

      二.VC学习资料的选择

      VC入门难有很多原因,其中不容忽视的一个就是优秀的VC学习资相对较少。C++语言较深,Visual C++用起来复杂,再加上资料少——难上加难。资料少,并不意味着没有,怎样选择或者说挖掘就是关键。暂把资料分为光盘、书籍(包括电子书)和文档(包括网上的)三类。

      在选择资料方面,大家一定要摈弃中国人思想中的两大劣根性:<1>不劳而获<2>一夜暴富。

      “不劳而获”的思想会导致趋向于选择“讲课”类的资料,比如多媒体光盘。结果是光盘容量往往很少但又要求内容面面俱到(不然怎么卖出去呀),这就造成了知识的连贯性差而且讲的又飞快,任你一遍一遍地听,不见成效又打击信心,最后只能放弃。期待早日有内容丰富,讲解精彩的光盘面市。

      “一夜暴富”的思想会让你趋向于选择“速成”类教材。那样的教材大多是骗人的——能写个弹出窗口Hello一下World,这就能算是会Visual C++了?我们还是不要自欺欺人的好。至少也要能连数据库、能使用Socket吧……而这些知识怎么可能“速成”呢?

      我有很多Visual C++的学习资料,但没有一本我是抱着一啃到底的,因为没有哪本书十全十美,我是交替着使用些资料,这样做的好处在于:

      <1>知识的连贯性好,跳跃性小,进阶坡度较小,读起来舒服。都说Visual C++的学习坡度比较陡,那个陡坡是出现在由单纯的C++语言学习转向Windows编程的时候,C++语言本身的学习并没有那么困难。

      <2>有积累效应,这本书讲的不精不透,另一本书会帮你补上,这本书你没留心,下本书总该长个心眼吧。还有就是一些小例子程序,把MFC的类或者函数拆开来给你看,目的非常明确,效果也不错。每天学一点,不图快,图扎实。呵呵,跟VC搞“面向对象”,当然要一天一点恋爱了。

      <3>举一返三,动手实践。如果多本书中都把它列为重点,那就一定要熟记在心而且上机操作,书上的例子一定要分析透彻,不能有“差不多”的思想——差多少算多呢?程序这东东,错一个字母都不行呀。光看会了还差远着呢,自己要能写,而且能对例子进行扩展才行。

      <4>内容详实丰富,这一点上,首推MSDN啦,还有就是在网上能找到的微软出的Visual C++的丛书,希望译的电子版,是wdl格式的。虽然MSDN是英文版,但其中的英文并不难——您尽可以相信我,因为在下的英文水平是奇烂无比的。MSDN有两种用法,一种是当字典用,因为内容全;一种是当消遣,没事了看一个类,敲几行代码,看到那个MFC的继承图了吗,挺好玩儿的,感觉像逛街——而且东西不要钱,help yourself。

      互联网上的资源是非常非常丰富的,千万不要错过!好网站和下载站BB皆是。还有论坛、新闻组、在线QQ群……你问我有哪些?呵呵,远在天边近在眼前呀:)
     三.内因与外因:“三心二意”和“高手朋友”你有吗?

      啊哦,我不是在开玩笑。“三心”是指决心,信心和耐心。决心来源于动机,说来好笑,我最初动机很简单,大学时有个朋友,计算机系的,我总认为我比他聪明(我的天~~~~),他会VC我不会,我就想超过他,现在都毕业两年了,最初的动机早已经不在了,而学习却VC已经成了我的心愿——最关键的一点是我的愿望是写自己的输入法,而写输入法只能用Visual C++去实现,所以我会有决心学好Visual C++。至于信心,有两次失败完全是信心不足造成的,促成这次成功的信心说起来还挺传奇:我去北京玩儿,回家的火车上一姓赵位老师看见我别着一个MCP的领章就过来跟我聊天,得知他是一位有着十多年VC开发经验的程序员,敬意油然而生。聊天的过程中,赵老师给了我极大的鼓励和支持——我问他像我这种Wood Head能不能在半年内入门VC,他告诉我,一定能,于是我就坚定了自己的信心,现在刚好是4个月,如果赵老师有机会看到这篇文章——我在这里谢谢您啦!(花絮:下车,两个小时后我与女友分手了,是被甩呀同志们!随后的一段日子里,一直与VC相伴……) 还要说说耐心:如果您已经看到这里了,说明您很有耐心(竟然能看到这里还没有拂袖而去),耐心与个人的风格有关,没耐心的人多半是懒人,懒人什么都做不成,学习VC就是不能懒,书懒得看,问题懒得问,英语懒得译……或者是有点挫折就放弃,学好VC是没指望了。我不知道别人怎样,反正我是没少受挫,其实有两次离入门就那么一点点了,我放弃了……学VC要越挫越勇,学VC要肯定执着,Gogogo!

      “二意”是指第一你要感觉学习VC有“意思”,二是你要感觉学习VC有“意义”。有意思,就是说你喜欢写程序,“三心”的源动力来源于你对程序设计的热爱,不喜欢编程的人可能能学好VB但绝学不好VC。有意义,就是说你要给自己一个理由:自己都不能给自己一个交待的事情是做不长久的。前面说过,我是为了写自己的输入法,解放中国人的双手,这个理由够纯洁够崇高,还有一个理由就是通过学习VC来砺练自己,成为一个真正的程序员。你可以有自己的理由,比如提高薪水或者取得认证云云,一定要有!这就像是给自己的“报酬”,没有报酬只凭激情做事是任何事都做不长久的。

      我小小的成功,有严重的原因是因为我有位“高手朋友”——杨W,他是个VC高手,大家会好奇地问:他教你写什么呢?是MFC还是ATL或者是COM?呵呵,都不是,他从来没教我写过一行代码,但他对我的每一次帮助都弥足珍贵,当我不知道从哪里查找类库资源的时候,他告诉我:MSDN;当我不知道从哪里找到类的成员函数时,他告诉我:在页面的左下角有一个class member链接,当我问他能不能完成XXXX时,他说:别白费力气了……在他的帮助下,我少走了很多弯路,这也正是高手朋友的可贵之处。在此,我要衷心地说一声:谢谢!

      并不是每位学习VC的朋友都有我这么好的运气,如果你身边没有这样的朋友也不用着急吗,我这位好朋友可是经常出没于CSDN的坛坛里,明白了?不过,提醒与我一样的初学者:一定要做一个会问问题的人哦!怎么做一个会问题的人呢?概括一下就是:目的明确,言简意赅,核心代码,客气谦虚。
    四.VC入门随笔

      本人写东西向来思绪凌乱、颠三倒四。剩下好多东西不知道写到哪里,没办法了,只好叫“随笔”咯。

      ……学习VC编程,首先要竖立一个“系统/全局观”。无论是VB、C#、Delphi,写程序的时候只需要考虑程序本身就行了,换句话说就是你不用考虑消息是如何映射和传递的。而VC写程序就要多多少少考虑到这些东西。打个比方:以前用VB写程序,就好像是在一座山上建一个亭子,山是山,亭子是亭子,我只管造亭子就是了;而用VC写程序,还是这个亭子,那么你应该意识到,亭子是山的亭子,是山的一部分而不是一个孤立的建筑。“亭子”就是程序,“山”就是Windows系统,亭子的地基是山留给建筑的“接口”,也就是API了……

      ……VC相对VB入门难,一上来不是像VB那样给个窗体从头做起,而且AppWizard要分好几步,每一步里还有一大堆不知所云的选项,不等生成一个程序就已经晕头转向了。怎么办呢?一句话,从对话框程序入手,因为它最简单,生成的类最少,而且相对是与VB编程最“像”的。在对话框程序里,你可以充分练习添加类和成员变量或者成员函数。……不过我有一点始终搞不明白,由易到难是对话框程序、单文档程序、多文档程序,在AppWizard里微软为什么不按这个顺序排列,非要倒着来呢?成心跟我们这些初学的做对!(国骂省去)……

      ……又是没大写……又是少分号……又是少一个等号……提醒VB转过来的程序员,别总像我这么没记性哦!

      ……还是提醒那些学习了VB或者是VB.NET/C#的DDMM,MFC的类虽然是面向对象的,但它没有“属性”这个概念地!不要指望有Me.TextBox1.Text="Hello World!"这样的语法,C/C++是函数型的语言,类已经把“属性”封装成了成员变量,那些私有的成员变量你看不到,只能通过函数来更改——this->myTextBox.SetWindowText("Hello World!");……

      ……晕,原来Win32程序和MFC程序不是一回事呀(看看,这就是一本烂书带给我的,让我一直以为Win32程序就是MFC程序,直到拜读《深入浅出MFC》时才恍然大悟)……

      ……VC好还是VB好?(拜托,别再问这种无聊的问题了)……

      ……VC的确能做底层,但不是最底层;VC的确功能强大,但不是万能的——拿手术刀切西瓜或者用菜刀动手术都不对……

      ……VC高手都是用记事本写程序的:笑不笑由你……

      ……VC程序员比VB程序员强:呵呵,毛主席说过,武器不是战争胜利的决定因素……

      ……在快速开发工具(RAD)中,控件与后台代码是捆绑在一起的,而MFC的“控件类”不一样,它的“资源”(或者说是皮)与“类”(或者说是瓤)是分开的,要通过ClassWizard把它们“粘”起来……

      ……如果说C++是一种程序设计语言,那么Visual C++中的C++语言不如叫“Windows语言”更合适——Visual C++就是在编程Windows,用到的宏或者Windows数据类型和Windows结构数不胜数,做好心理准备哦!……

      ……我的天,那么长的函数或者结构都要一个字母一个字母写呀!呵呵,按一下Ctrl+J看看发生了什么?我就奇怪了,几乎没看到有书上提醒我们的初学者要这样去做。这可是着实吓跑了不少初学者呢!(至少我就被吓跑过)。器利工善,我们要把IDE用熟哦,微软送的好礼物可不能浪费……

      ……很多书在添加完对新话框类之后都写着要在主对话框类里手动添加对这个新类头文件的引用,何必呢?用添加成员变量的方法添加这个新对话框类的实例,头文件自动引用,一举两得。一句话:尽量多用Class Wizard,能不手写的地方就不手写……

      五.virtual BOOL LongWayToGo(void)

      {

       //头一次写文章,其中Bug肯定少不了,大家一起来DeBug。

       //由于是入门级文章,如果有错误,很可能影响初学者学习,恐误人子弟,有错必纠!

       //希望大家多提宝贵意见,帮助我前进,谢谢先!

       //这是虚函数,留待有所得时续以后文。我还有很长的路……

       return TRUE;

      }