﻿<?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-鹰翔宇空-文章分类-EJB</title><link>http://www.blogjava.net/TrampEagle/category/9798.html</link><description>学习和生活
</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 14:19:30 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 14:19:30 GMT</pubDate><ttl>60</ttl><item><title>EJB技术及应用</title><link>http://www.blogjava.net/TrampEagle/articles/28636.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Thu, 19 Jan 2006 03:35:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/28636.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/28636.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/28636.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/28636.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/28636.html</trackback:ping><description><![CDATA[引自：<A href="http://www.cnjsp.org/view.jsp?column=2&amp;id=739">http://www.cnjsp.org/view.jsp?column=2&amp;id=739</A><BR><BR><STRONG>一、EJB技术简介&nbsp;<BR></STRONG>&nbsp;&nbsp;&nbsp;&nbsp;EJB的全称是Enterprise&nbsp;java&nbsp;bean。是JAVA中的商业应用组件技术。EJB结构中的角色&nbsp;EJB&nbsp;组件结构是基于组件的分布式计算结构，是分布式应用系统中的组件。<BR>一个完整的基于EJB的分布式计算结构由六个角色组成，这六个角色可以由不同的开发商提供，每个角色所作的工作必须遵循Sun公司提供的EJB规范，以保证彼此之间的兼容性。这六个角色分别是EJB组件开发者(Enterprise&nbsp;Bean&nbsp;Provider)&nbsp;、应用组合者(Application&nbsp;Assembler)、部署者(Deployer)、EJB&nbsp;服务器提供者(EJB&nbsp;Server&nbsp;Provider)、EJB&nbsp;容器提供者(EJB&nbsp;Container&nbsp;Provider)、系统管理员(System&nbsp;Administrator)：<BR><BR><STRONG>二、EJB中各角色的分析</STRONG><BR><BR>1、EJB组件开发者(Enterprise&nbsp;Bean&nbsp;Provider)<BR>EJB组件开发者负责开发执行商业逻辑规则的EJB组件，开发出的EJB组件打包成ejb-jar文件。EJB组件开发者负责定义EJB的remote和home接口，编写执行商业逻辑的EJB&nbsp;class,提供部署EJB的部署文件(deployment&nbsp;descriptor)。部署文件包含EJB的名字，EJB用到的资源配置，如JDBC等。EJB组件开发者是典型的商业应用开发领域专家。<BR>EJB组件开发者不需要精通系统级的编程，因此，不需要知道一些系统级的处理细节，如事务、同步、安全、分布式计算等。<BR><BR>2、应用组合者(Application&nbsp;Assembler)<BR>应用组合者负责利用各种EJB组合一个完整的应用系统。应用组合者有时需要提供一些相关的程序，如在一个电子商务系统里，应用组合者需要提供JSP(Java&nbsp;Server&nbsp;Page)程序。<BR>应用组合者必须掌握所用的EJB的home和remote接口，但不需要知道这些接口的实现。<BR><BR>3、部署者(Deployer)<BR>部署者负责将ejb-jar文件部署到用户的系统环境中。系统环境包含某种EJB&nbsp;Server和EJB&nbsp;Container。部署者必须保证所有由EJB组件开发者在部署文件中声明的资源可用，例如，部署者必须配置好EJB所需的数据库资源。<BR>部署过程分两步：部署者首先利用EJB&nbsp;Container提供的工具生成一些类和接口，使EJB&nbsp;Container能够利用这些类和接口在运行状态管理EJB。&nbsp;部署者安装EJB组件和其他在上一步生成的类到EJB&nbsp;Container中。&nbsp;部署者是某个EJB运行环境的专家。<BR>某些情况下，部署者在部署时还需要了解EJB包含的业务方法，以便在部署完成后，写一些简单的程序测试。<BR><BR>4、EJB&nbsp;服务器提供者(EJB&nbsp;Server&nbsp;Provider)<BR>EJB&nbsp;服务器提供者是系统领域的专家，精通分布式交易管理，分布式对象管理及其它系统级的服务。EJB&nbsp;服务器提供者一般由操作系统开发商、中间件开发商或数据库开发商提供。<BR>在目前的EJB规范中，假定EJB&nbsp;服务器提供者和EJB&nbsp;容器提供者来自同一个开发商，所以，没有定义EJB&nbsp;服务器提供者和EJB容器提供者之间的接口标准。<BR><BR>5、EJB&nbsp;容器提供者(EJB&nbsp;Container&nbsp;Provider)<BR>EJB&nbsp;容器提供者提供以下功能：<BR>提供EJB部署工具为部署好的EJB组件提供运行环境&nbsp;。EJB容器负责为EJB提供交易管理，安全管理等服务。<BR>EJB&nbsp;容器提供者必须是系统级的编程专家，还要具备一些应用领域的经验。EJB&nbsp;容器提供者的工作主要集中在开发一个可伸缩的，具有交易管理功能的集成在EJB&nbsp;服务器中的容器。EJB&nbsp;容器提供者为EJB组件开发者提供了一组标准的、易用的API访问EJB&nbsp;容器，使EJB组件开发者不需要了解EJB服务器中的各种技术细节。<BR>EJB容器提供者负责提供系统监测工具用来实时监测EJB容器和运行在容器中的EJB组件状态。<BR><BR>6、系统管理员(System&nbsp;Administrator)<BR>系统管理员负责为EJB服务器和容器提供一个企业级的计算和网络环境。<BR>系统管理员负责利用EJB&nbsp;服务器和容器提供的监测管理工具监测EJB组件的运行情况。<BR><BR><STRONG>三、EJB的体系结构：</STRONG><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;EJB分布式应用程序是基于对象组件模型的，低层的事务服务用了API技术。EJB技术简化了用JAVA语言编写的企业应用系统的开发，配置。EJB技术定义了一组可重用的组件：Enterprise&nbsp;Beans。你可以利用这些组件，象搭积木一样的建立你的分布式应用程序。当你把代码写好之后，这些组件就被组合到特定的文件中去。每个文件有一个或多个Enterprise&nbsp;Beans，在加上一些配置参数。最后，这些Enterprise&nbsp;Beans被配置到一个装了EJB容器的平台上。客户能够通过这些Beans的home接口，定位到某个beans，并产生这个beans的一个实例。这样，客户就能够调用Beans的应用方法和远程接口。<BR>EJB服务器作为容器和低层平台的桥梁管理着EJB容器和函数。它向EJB容器提供了访问系统服务的能力。例如：数据库的管理和事务的管理，或者对于其它的Enterprise的应用服务器。所有的EJB&nbsp;实例都运行在EJB容器中。&nbsp;&nbsp;&nbsp;&nbsp;容器提供了系统级的服务，控制了EJB的生命周期。EJB中的有一些易于使用的管理工具如：Security--配置描述器（The&nbsp;Deployment&nbsp;descriptor）定义了客户能够访问的不同的应用函数。容器通过只允许授权的客户访问这些函数来达到这个效果。Remote&nbsp;Connectivity--容器为远程链接管理着低层的通信issues，而且对Enterprise&nbsp;Beas的开发者和客户都隐藏了通信细节。EJB的开发者在编写应用方法的时候，就象是在条用本地的平台一样的。客户也不清楚他们调用的方法可能是在远程被处理的。Life&nbsp;Cycle&nbsp;managment--客户简单的创建一个Enterprise&nbsp;beans的实例，并通常取消一个实例。而容器管理着Enterprise&nbsp;Beans的实例，使Enterprise&nbsp;Beans实现最大的效能和内存利用率。容器能够这样来激活和使Enterprise&nbsp;Beans失效，保持众多客户共享的实例池。等等。&nbsp;&nbsp;Trasction&nbsp;management-配置描述器定义了Enterprise&nbsp;beans&nbsp;的事务处理的需求。容器管理着那些管理分布式事务处理的复杂的issues。这些事务可能要在不同的平台之间更新数据库。容器使这些事务之间互相独立，互不干扰。保证所有的更新数据库都是成功发生的，否者，就回滚到事务处理之前的状态。<BR>EJB&nbsp;组件是基于分布式事务处理的企业级应用程序的组件。所有的EJB都有如下的特点：EJB包含了处理企业数据的应用逻辑。定义了EJB的客户界面。这样的界面不受容器和服务器的影响。于是，当一个EJB被集合到一个应用程序中去时，不用更改代码和重新编译。EJB能够被定制&nbsp;各种系统级的服务，例如安全和事务处理的特性，都不是属于EJB类的。而是由配置和组装应用程序的工具来实现。&nbsp;有两种类型的EJB:&nbsp;Session&nbsp;beans&nbsp;和&nbsp;entity&nbsp;beans.Session&nbsp;beans是一种作为单用户执行的对象。作为对远程的任务请求的相应，容器产生一个Session&nbsp;beans&nbsp;的实例。一个Session&nbsp;beans有一个用户.从某种程度上来说，一个Session&nbsp;bean&nbsp;对于服务器来说就代表了它的那个用户.Session&nbsp;beans&nbsp;也能用于事务，它能够更新共享的数据，但它不直接描绘这些共享的数据。Session&nbsp;beans&nbsp;的生命周期是相对较短的。典型的是，只有当用户保持会话的时候，Session&nbsp;beans&nbsp;才是活着的。一旦用户退出了，Session&nbsp;beans&nbsp;就不再与用户相联系了。Session&nbsp;beans被看成是瞬时的，因为如果容器崩溃了，那么用户必须重新建立一个新的Session对象来继续会话。<BR>Session&nbsp;bean典型的声明了与用户的互操作或者会话。也就是说，Session&nbsp;bean了在客户会话期间，通过方法的调用，掌握用户的信息。一个具有状态的Session&nbsp;bean称为有状态的Session&nbsp;bean.当用户终止与Session&nbsp;beans互操作的时候.会话终止了，而且，bean&nbsp;也不再拥有状态值。Session&nbsp;bean也可能是一个无状态的&nbsp;session&nbsp;bean.无状态的Session&nbsp;beans并不掌握它的客户的信息或者状态。用户能够调用beans的方法来完成一些操作。但是，beans只是在方法调用的时候才知道用户的参数变量。当方法调用完成以后，beans并不继续保持这些参数变量。这样，所有的无状态的session&nbsp;beans的实例都是相同的，除非它正在方法调用期间。这样，无状态的Session&nbsp;beans就能够支持多个用户.容器能够声明一个无状态的Session&nbsp;beans.能够将任何Session&nbsp;beans指定给任何用户.<BR>Entity&nbsp;Beans对数据库中的数据提供了一种对象的视图。例如：一个Entity&nbsp;bean能够模拟数据库表中一行相关的数据。多个client能够共享访问同一个Entity&nbsp;bean.多个client也能够同时的访问同一个Entity&nbsp;bean.Entity&nbsp;beans通过事务的上下文来访问或更新下层的数据。这样，数据的完整性就能够被保证。Entity&nbsp;Beans能存活相对教长的时间，并且状态是持续的。只要数据库中的数据存在，Entity&nbsp;beans就一直存活。而不是按照应用程序或者服务进程来说的。即使EJB容器崩溃了，Entity&nbsp;beans也是存活的。Entity&nbsp;Beans生命周期能够被容器或者&nbsp;Beans自己管理。如果由容器控制着保证&nbsp;Entity&nbsp;beans持续的issus。如果由Beans自己管理，就必须写Entity&nbsp;beans的代码，包括访问数据库的调用。<BR>Entity&nbsp;Beans是由主键（primary&nbsp;key&nbsp;一种唯一的对象标识符）标识的。通常，主键与标识数据库中的一块数据，例如一个表中的一行，的主键是相同的。主键是client能够定位特定的数据块。<BR><BR><STRONG>四、开发EJB</STRONG><BR><BR>1、类介绍：<BR>开发EJB的主要步骤一般来说，整个的开发步骤（开发，配置，组装）包括如下几个方面。开发：首先要定义三个类：Bean类本身，Bean的本地和远程接口类。&nbsp;配置：配置包括产生配置描述器--这是一个XML文件、声明了Enterprise&nbsp;Bean的属性、绑定了bean的class文件（包括stub文件和skeleton文件）。最后将这些配置都放到一个jar文件中。还需要在配置器中定义环境属性。组装应用程序：包括将Enterprise&nbsp;beans安装到Server服务器中，测试各层的连接情况。程序组装器将若干个Enterprise&nbsp;Beans与其它的组件结合起来。组合成一个完整的应用程序。或者将若干个Enterprise&nbsp;beans组合成一个复杂的Enterprise&nbsp;Bean。管理Enterprise&nbsp;Bean。<BR>我们必须定义和编写一些EJB中的基本类。如Enterprise&nbsp;bean类：这是Enterprise&nbsp;bean内部应用逻辑的实现。编写Enterprise&nbsp;bean的远程接口类。编写Enterprise&nbsp;bean的本地接口类。说明主键类，主键类只是对于Entity&nbsp;bean才需要的。在Enterprise&nbsp;bean的配置描述器中指定主键的名字。Enterprise&nbsp;beans提供者定义了远程接口和本地接口，实现了EJB类本身。Remote接口中提供了客户调用EJB实现的应用逻辑函数的接口。而home接口提供了产生和定位remote接口实例的方法。<BR>在Enterprise&nbsp;bean本身类的实现，本地home接口，远程remote接口之间并没有正式的联系（例如继承关系）。但是，在三个类里声明的方法却必须遵守EJB里面定义的规范。例如：&nbsp;你在Enterprise&nbsp;bean里面声明了一个应用程序的方法或者说应用逻辑。也在beans的remote接口中声明了这个方法，那么，这两个地方必须要同样的名字。Bean的实现里面必须至少有一个Create()方法：ejbCreate()。但是可以有多个带有不同参数的create()方法。&nbsp;&nbsp;&nbsp;&nbsp;在home接口中，也必须有相同的方法定义（参数的个数相同）。EjbCreate()方法返回的一个容器管理的持久对象。它们都返回一个容器管理持久性的主键值。但是，在home的相应的Create()方法中返回值的类型是remote接口。<BR>注意：实体bean的实现的ejbCreate方法有点不同。实体bean可以不定义ejbCreate方法。如果实体只是通过应用程序或通过数据库管理程序的途径被加到数据库中，实体bean就省略了ejbCreate方法。EjbCreate返回的值是主键类型。如果ejbCreate方法是容器管理持久性的实体bean的方法，它的返回值就是NULL类型。如果实体bean实现了Bean管理的持久性，ejbCreate方法就返回值类型就是主键类型。容器的任务是把各接口和Enterprise&nbsp;bean的实现类结合起来。保证在编译时和运行时，各接口和实现类是相对应的。<BR>EJB的实现类，各接口要从不同的基类中继承下来。一个会话bean必须实现基类javax.ejb.SessionBean。而实体bean必须实现基类javax.ejb.EntiyBean。这些EJB的基类都是从javax.ejb.EnterpriseBean继承而来。而javax.ejb.EnterpriseBean又是从java.io.Serializable继承而来。每一个Enterprise&nbsp;Bean都必须有一个remote接口。Remote接口定义了应用程序规定客户可以调用的逻辑操作。这些是一些可以由客户调用的公共的方法，通常由Enterprise&nbsp;beans类来实现。注意，Enterprise&nbsp;bean的客户并不直接访问Bean。而是通过remote接口来访问。Enterprise&nbsp;bean类的remote接口扩展了javax.ejb.EJBObject类的公共java接口。而Javax.ejb.EJBObject是所有remote接口的基类。其代码如下：<BR>
<BLOCKQUOTE><FONT size=-1>CODE:</FONT> 
<HR>
<PRE><BR>package&nbsp;javax.ejb;<BR>public&nbsp;interface&nbsp;EJBObject&nbsp;extends&nbsp;java.rmi.Remote{<BR>public&nbsp;EJBHome&nbsp;getEJBHome()&nbsp;throws&nbsp;java.rmi.RemoteException;<BR>public&nbsp;Object&nbsp;getPrimaryKey()&nbsp;throws&nbsp;java.rmi.RemoteException;<BR>public&nbsp;void&nbsp;Remove()&nbsp;throws&nbsp;java.rmi.RemtoeException,&nbsp;java.rmi.RemoveException<BR>public&nbsp;Handle&nbsp;getHandle()&nbsp;throws&nbsp;java.rmi.RemoteException;<BR>boolean&nbsp;isIdentical&nbsp;(EJBObject&nbsp;p0)&nbsp;throws&nbsp;java.rmi.RemoteException;<BR>}<BR></PRE>
<HR>
</BLOCKQUOTE><BR>getEJBHome()方法允许你取得一个相关的Home接口。对于&nbsp;实体Bean，用getPrimaryKey（）方法获得实体Bean的主键值。Remove（）可以删除一个Enterprise&nbsp;bean。具体的语义在各种不同类型的enterprise&nbsp;beans的生命周期中，由上下文中解释的。方法getHandle（）返回了一个Enterprise&nbsp;bean实例的持久的句柄。IsIndentical()方法允许你去比较Enterprise&nbsp;beans是否相同。<BR><BR>2、方法：<BR>所有的remote接口中的方法必须声明为公共（public）的，并必须抛出java.rmi.RemotException异常。另外，所有的remote接口中的方法定义的参数和都必须是在RMI-IIOP中有效的。对每一个在remote接口中定义的方法，在Enterprise&nbsp;bean&nbsp;类里面都要有相应的方法。相应的方法必须要有同样的名字，同样类型和数量的参数，同样的返回值，而且还要抛出同样的例外。&nbsp;如下代码显示了一个ATM例子的会话bean的remote接口Atm，。里面声明了一个应用方法transfer（）。黑体部分表示EJB规范中必须要有的内容。Remote接口必须扩展javax.ejb.EJBObject类。从客户端调用的Enterprise&nbsp;bean的每一个方法都必须在remote接口中声明。Transfer（）方法抛出了两个意外。其中InSufficientFundsException例外是应用程序定义的意外。<BR>
<BLOCKQUOTE><FONT size=-1>CODE:</FONT> 
<HR>
<PRE><BR>Public&nbsp;interface&nbsp;Atm&nbsp;extends&nbsp;javax.ejb.EJBObject{<BR>Public&nbsp;void&nbsp;transfer(String&nbsp;Source,&nbsp;String&nbsp;Target,&nbsp;float&nbsp;amount)<BR>Throws&nbsp;java.rmi.RemoteException,&nbsp;InSufficientFundsException;<BR>}<BR></PRE>
<HR>
</BLOCKQUOTE><BR>Home接口必须定义一个或多个的Create()方法。每一个这样的Create()方法都必须命名为Create。并且，它的参数，不管是类型还是数量都必须与bean类里面的ejbCreate()方法对应。注意，home接口中的Create()方法和bean类中ejbCreate()方法的返回值类型是不同的。实体bean的home接口还包含find（）方法。&nbsp;每一个Home接口都扩展了javax.ejb.EJBHome接口。如下代码显示了javax.ejb.EJBHome接口的定义：<BR>
<BLOCKQUOTE><FONT size=-1>CODE:</FONT> 
<HR>
<PRE><BR>package&nbsp;javax.ejb;<BR>public&nbsp;interface&nbsp;EJBHome&nbsp;extends&nbsp;java.rmi.Remote()&nbsp;{<BR>void&nbsp;remove(Handle&nbsp;handle)&nbsp;throws&nbsp;java.rmi.RemoteException,RemoveException;<BR>void&nbsp;remove(Object&nbsp;primarykey)&nbsp;throws&nbsp;java.rmi.RemoteException,RemoveException;<BR>EJBMetaData&nbsp;getEJBMetaData()&nbsp;throws&nbsp;RemoteException;<BR>Homehandle&nbsp;getHomeHandle()&nbsp;throws&nbsp;RemoteException;<BR>}<BR></PRE>
<HR>
</BLOCKQUOTE><BR>这里提供了两个remove（）方法来删除Enterprise&nbsp;bean的实例。第一个remove方法是通过句柄来删除一个Enterprise&nbsp;bean的实例。第二个remove方法通过主键来删除一个Enterprise&nbsp;bean的实例。&nbsp;在众多的Enterprise&nbsp;bean实例中，句柄唯一的标识一个实例。一个句柄与它引用的Enterprise&nbsp;bean有相同的生命期。考虑一个实体对象，客户可以通过一个句柄来重新获得相应的Enterprise&nbsp;bean的实例。一个句柄能够对应一个Enterprise&nbsp;bean对象的多个实例。例如，即使当Enterprise&nbsp;bean对象所在的主机崩溃了，或者Enterprise&nbsp;bean对象在不同的机器之间移动，句柄仍是有效的。这里的句柄是Serialized句柄，与CORBA中的字符串化的CORBA对象的引用是相似的概念。在EJBHome接口中的第二个remove操作通过其主键来决定要删除的Enterprise&nbsp;bean。主键可以是扩展了Java&nbsp;Object类的任何类型，但是，必须要实现Java的Serializable接口。主键是标识实体bean的主要的方法。通常，主键是数据库中的一个关键字，唯一的定义了由实体bean代表的数据。<BR>方法getEJBMetaData（）返回了Enterprise&nbsp;bean对象的metadata接口。这个接口允许客户获得Enterprise&nbsp;bean的metadata信息。当开发工具来编译链接应用程序的时候，或者配置工具来配置的时候，可能会用到metadata信息。Javax.ejb.EJBMetadata接口提供了获得javax.ejb.EJBHome接口，home类，remote接口，还有获得主键的方法。也提供了一个isSesson()的方法来确定在放这个home接口的对象是会话bean还是实体bean。&nbsp;&nbsp;&nbsp;&nbsp;IsStatelessSession()方法指示这个会话bean是有状态还是无状态的。如下代码显示了javax.ejb.EJBMetadata接口的定义部分的代码。<BR>
<BLOCKQUOTE><FONT size=-1>CODE:</FONT> 
<HR>
<PRE><BR>Public&nbsp;javax.ejb;&nbsp;Public&nbsp;interface&nbsp;EJBMetaData{<BR>EJBHome&nbsp;getEJBHome();<BR>Class&nbsp;getHomeInterfaceClass();<BR>Class&nbsp;getRemoteInterfaceClasss();<BR>Class&nbsp;getPrimaryKeyClass();<BR>Boolean&nbsp;isSession();<BR>Boolean&nbsp;isStatelesssSession();<BR>}<BR></PRE>
<HR>
</BLOCKQUOTE><BR>对每一个Create（）方法，EJB规范定义了如下的命名约定。它的返回值是会话bean的remote接口的类型。方法的名字只能是Create()。对会话bean类中的每一个ejbCreate()方法都必须有一个Create()与之对应。&nbsp;对于每一个Create()方法的参数的类型和数量都必须与会话bean类中的ejbCreate()方法相对应。方法必须抛出java.rmi.RemoteException例外。&nbsp;方法必须抛出javax.rmi.CreateExeption例外。&nbsp;Create（）方法的参数是用来初始化新的会话bean对象的。&nbsp;如下代码显示了一个会话bean对象的不同的Create()方法，其中必须的部分用粗体显示：<BR>
<BLOCKQUOTE><FONT size=-1>CODE:</FONT> 
<HR>
<PRE><BR>public&nbsp;interface&nbsp;AtmHome&nbsp;extends&nbsp;javax.ejb.EJBHome{<BR>Atm&nbsp;create()&nbsp;throws&nbsp;java.rmi.RemoteException,javax.ejb.CreateException;<BR>Atm&nbsp;create(Profile&nbsp;preferredProfile)<BR>Throws&nbsp;java.rmi.RemoteExeption,javax.ehrows&nbsp;java.rmi.RemoteException,RemoveException;<BR>EJBMetaData&nbsp;getEJBMetaData()&nbsp;throws&nbsp;RemoteException;<BR>Homehandle&nbsp;getHomeHandle()&nbsp;throws&nbsp;RemoteException;<BR>}<BR></PRE>
<HR>
</BLOCKQUOTE><BR>这里提供了两个remove（）方法来删除Enterprise&nbsp;bean的实例。第一个remove方法是通过句柄来删除一个Enterprise&nbsp;bean的实例。第二个remove方法通过主键来删除一个Enterprise&nbsp;bean的实例。在众多的Enterprise&nbsp;bean实例中，句柄唯一的标识一个实例。一个句柄与它引用的Enterprise&nbsp;bean有相同的生命期。考虑一个实体对象，客户可以通过一个句柄来重新获得相应的Enterprise&nbsp;bean的实例。一个句柄能够对应一个Enterprise&nbsp;bean对象的多个实例。例如，即使当Enterprise&nbsp;bean对象所在的主机崩溃了，或者Enterprise&nbsp;bean对象在不同的机器之间移动，句柄仍是有效的。这里的句柄是Serialized句柄，与CORBA中的字符串化的CORBA对象的引用是相似的概念。<BR>在EJBHome接口中的第二个remove操作通过其主键来决定要删除的Enterprise&nbsp;bean。主键可以是扩展了Java&nbsp;Object类的任何类型，但是，必须要实现Java的Serializable接口。主键是标识实体bean的主要的方法。通常，主键是数据库中的一个关键字，唯一的定义了由实体bean代表的数据。方法getEJBMetaData（）返回了Enterprise&nbsp;bean对象的metadata接口。这个接口允许客户获得Enterprise&nbsp;bean的metadata信息。当开发工具来编译链接应用程序的时候，或者配置工具来配置的时候，可能会用到metadata信息。Javax.ejb.EJBMetadata接口提供了获得javax.ejb.EJBHome接口，home类，remote接口，还有获得主键的方法。也提供了一个isSesson()的方法来确定在放这个home接口的对象是会话bean还是实体bean。IsStatelessSession()方法指示这个会话bean是有状态还是无状态的。如下代码显示了javax.ejb.EJBMetadata接口的定义部分的代码。<BR>
<BLOCKQUOTE><FONT size=-1>CODE:</FONT> 
<HR>
<PRE><BR>Public&nbsp;javax.ejb;<BR>Public&nbsp;interface&nbsp;EJBMetaData{<BR>EJBHome&nbsp;getEJBHome();<BR>Class&nbsp;getHomeInterfaceClass();<BR>Class&nbsp;getRemoteInterfaceClasss();<BR>Class&nbsp;getPrimaryKeyClass();<BR>Boolean&nbsp;isSession();<BR>Boolean&nbsp;isStatelesssSession();<BR>}<BR></PRE>
<HR>
</BLOCKQUOTE><BR><STRONG>五、EJB的编程环境：</STRONG><BR><BR>1、&nbsp;使用Jbuilder<BR>Jbuilder与EJB&nbsp;Container能够进行无缝连接。Jbuilder和Inprise的应用服务器包括了所有的开发和配置Enterprise&nbsp;Beans的工具以及所需要的库：运行和管理Enterprise&nbsp;Bean的容器、命名服务、&nbsp;事务服务、Java数据库、开发Enterprise&nbsp;Beans所需要的API、一个增强的java-to-iiop编译器，支持值类型和RMI信号等等。<BR>Jbuilder还提供了一个快速开发应用程序Enterprise&nbsp;Beans的工具和向导。通过简单而且直观的步骤，向导帮助你建立一个Enterprise&nbsp;Bean。自己设定某些缺省值，产生了bean的模板，在上面，我们可以增加我们自己的应用逻辑。Jbuilder也提供了一个EJB的接口生成向导。向导在Enterprise&nbsp;Bean的公共方法基础上生成了Remote接口和Home接口。Jbuilder还提供一个配置器的向导帮助我们逐步的建立XML描述器文件。并将生成的Stubs集中到一个jar文件中。<BR><BR>2、使用Jbuilder之外的集成环境：<BR>如果你使用其它的除了别的集成环境（IDE）。要确定使用了集成环境IDE所带的容器工具。也要验证IDE是否支持EJB规范的相应的版本，还要确定它是否正确的支持EJB的API。<BR>要确定JD到所支持的EJB容器的版本。可以通过检查Inprise的安装说明来确定EJB容器所支持的支持JDK的版本。<BR>在配置Enterprise&nbsp;Bean的时候，你必须使用Inprise的应用服务器所提供的工具。这些工具能够编辑和修改第三方的代理商提供的Inprise配置描述器。还能够验证配置描述器，能够验证bean的源代码。<BR><BR><STRONG>六、一个简单的HELLO例子</STRONG><BR><BR>1、安装Apusic&nbsp;Application&nbsp;Server<BR>Note:以下以Linux为例，来说明Apusic&nbsp;Application&nbsp;Server的安装过程。其他平台的安装，可参考Apusic&nbsp;Application&nbsp;Server安装手册。<BR>下载JDK1.3，Apusic&nbsp;Application&nbsp;Server必须运行在jdk1.3以上环境中。可从以下站点下载最新JDK。<BR>http://java.sun.com<BR>下载Apusic&nbsp;Application&nbsp;Server<BR>Apusic&nbsp;Application&nbsp;Server&nbsp;试用版可从以下网址得到：<BR>http://www.apusic.com/download/enter.jsp<BR>在下载完成后，你可以得到一个包裹文件apusic.zip，选定安装目录，假设安装到/usr下，则用以下命令：<BR>cd&nbsp;/usr<BR>jar&nbsp;xvf&nbsp;apusic.zip<BR>/usr下会出现一个目录apusic，Apusic&nbsp;Application&nbsp;Server的所有程序都被解压到/usr/apusic下。<BR>将以下路径加入到CLASSPATH中<BR>/usr/apusic/lib/apusic.jar<BR>$JAVA_HOME/lib/tools.jar<BR>用以下命令运行Apusic&nbsp;Application&nbsp;Server<BR>java&nbsp;-Xms64m&nbsp;com.apusic.server.Main&nbsp;-root&nbsp;/usr/apusic<BR><BR>2、定义EJB远程接口(Remote&nbsp;Interface)<BR>任何一个EJB都是通过Remote&nbsp;Interface被调用，EJB开发者首先要在Remote&nbsp;Interface中定义这个EJB可以被外界调用的所有方法。执行Remote&nbsp;Interface的类由EJB生成工具生成。<BR>以下是HelloBean的Remote&nbsp;Inteface程序：<BR>
<BLOCKQUOTE><FONT size=-1>CODE:</FONT> 
<HR>
<PRE><BR>package&nbsp;ejb.hello;<BR><BR>import&nbsp;java.rmi.RemoteException;<BR>import&nbsp;java.rmi.Remote;<BR>import&nbsp;javax.ejb.*;<BR><BR>public&nbsp;interface&nbsp;Hello&nbsp;extends&nbsp;EJBObject,&nbsp;Remote&nbsp;{<BR><BR>//this&nbsp;method&nbsp;just&nbsp;get&nbsp;"Hello&nbsp;World"&nbsp;from&nbsp;HelloBean.<BR>public&nbsp;String&nbsp;getHello()&nbsp;throws&nbsp;RemoteException;<BR>}<BR></PRE>
<HR>
</BLOCKQUOTE><BR>3、定义Home&nbsp;Interface<BR>EJB容器通过EJB的Home&nbsp;Interface来创建EJB实例，和Remote&nbsp;Interface一样，执行Home&nbsp;Interface的类由EJB生成工具生成。<BR>以下是HelloBean&nbsp;的Home&nbsp;Interface程序：<BR>
<BLOCKQUOTE><FONT size=-1>CODE:</FONT> 
<HR>
<PRE><BR>package&nbsp;ejb.hello;<BR><BR>import&nbsp;javax.ejb.*;<BR>import&nbsp;java.rmi.Remote;<BR>import&nbsp;java.rmi.RemoteException;<BR>import&nbsp;java.util.*;<BR><BR>/**<BR>*&nbsp;This&nbsp;interface&nbsp;is&nbsp;extremely&nbsp;simple&nbsp;it&nbsp;declares&nbsp;only<BR>*&nbsp;one&nbsp;create&nbsp;method.<BR>*/<BR>public&nbsp;interface&nbsp;HelloHome&nbsp;extends&nbsp;EJBHome&nbsp;{<BR><BR>public&nbsp;Hello&nbsp;create()&nbsp;throws&nbsp;CreateException,<BR>RemoteException;<BR><BR>}<BR></PRE>
<HR>
</BLOCKQUOTE><BR>4、写EJB类<BR>在EJB类中，编程者必须给出在Remote&nbsp;Interface中定义的远程方法的具体实现。EJB类中还包括一些&nbsp;EJB规范中定义的必须实现的方法，这些方法都有比较统一的实现模版，编程者只需花费精力在具体业务方法的实现上。<BR>以下是HelloBean的代码：<BR>
<BLOCKQUOTE><FONT size=-1>CODE:</FONT> 
<HR>
<PRE><BR>package&nbsp;ejb.hello;<BR><BR>import&nbsp;javax.ejb.*;<BR>import&nbsp;java.util.*;<BR>import&nbsp;java.rmi.*;<BR><BR>public&nbsp;class&nbsp;HelloBean&nbsp;implements&nbsp;SessionBean&nbsp;{<BR>static&nbsp;final&nbsp;boolean&nbsp;verbose&nbsp;=&nbsp;true;<BR><BR>private&nbsp;transient&nbsp;SessionContext&nbsp;ctx;<BR><BR>//&nbsp;Implement&nbsp;the&nbsp;methods&nbsp;in&nbsp;the&nbsp;SessionBean<BR>//&nbsp;interface<BR>public&nbsp;void&nbsp;ejbActivate()&nbsp;{<BR>if&nbsp;(verbose)<BR>System.out.println("ejbActivate&nbsp;called");<BR>}<BR><BR>public&nbsp;void&nbsp;ejbRemove()&nbsp;{<BR>if&nbsp;(verbose)<BR>System.out.println("ejbRemove&nbsp;called");<BR>}<BR><BR>public&nbsp;void&nbsp;ejbPassivate()&nbsp;{<BR>if&nbsp;(verbose)<BR>System.out.println("ejbPassivate&nbsp;called");<BR>}<BR><BR>/**<BR>*&nbsp;Sets&nbsp;the&nbsp;session&nbsp;context.<BR>*<BR>*&nbsp;@param&nbsp;SessionContext<BR>*/<BR>public&nbsp;void&nbsp;setSessionContext(SessionContext&nbsp;ctx)&nbsp;{<BR>if&nbsp;(verbose)<BR>System.out.println("setSessionContext&nbsp;called");<BR>this.ctx&nbsp;=&nbsp;ctx;<BR>}<BR><BR>/**<BR>*&nbsp;This&nbsp;method&nbsp;corresponds&nbsp;to&nbsp;the&nbsp;create&nbsp;method&nbsp;in<BR>*&nbsp;the&nbsp;home&nbsp;interface&nbsp;HelloHome.java.<BR>*&nbsp;The&nbsp;parameter&nbsp;sets&nbsp;of&nbsp;the&nbsp;two&nbsp;methods&nbsp;are<BR>*&nbsp;identical.&nbsp;When&nbsp;the&nbsp;client&nbsp;calls<BR>*&nbsp;HelloHome.create(),&nbsp;the&nbsp;container&nbsp;allocates&nbsp;an<BR>*&nbsp;instance&nbsp;of&nbsp;the&nbsp;EJBean&nbsp;and&nbsp;calls&nbsp;ejbCreate().<BR>*/<BR>public&nbsp;void&nbsp;ejbCreate&nbsp;()&nbsp;{<BR>if&nbsp;(verbose)<BR>System.out.println("ejbCreate&nbsp;called");<BR>}<BR>/**<BR>*&nbsp;****&nbsp;HERE&nbsp;IS&nbsp;THE&nbsp;BUSINESS&nbsp;LOGIC&nbsp;*****<BR>*&nbsp;the&nbsp;getHello&nbsp;just&nbsp;return&nbsp;a&nbsp;"Hello&nbsp;World"&nbsp;string.<BR>*/<BR>public&nbsp;String&nbsp;getHello()<BR>throws&nbsp;RemoteException<BR>{<BR>return("Hello&nbsp;World");<BR>}<BR>}<BR></PRE>
<HR>
</BLOCKQUOTE><BR>5、创建ejb-jar.xml文件<BR>ejb-jar.xml文件是EJB的部署描述文件，包含EJB的各种配置信息，如是有状态Bean(Stateful&nbsp;Bean)&nbsp;还是无状态Bean(Stateless&nbsp;Bean)，交易类型等。ejb-jar.xml文件的详细信息请参阅EJB规范。以下是HelloBean的配置文件：<BR>
<BLOCKQUOTE><FONT size=-1>CODE:</FONT> 
<HR>
<PRE><BR>&lt;?xml&nbsp;version="1.0"?&gt;<BR>&lt;!DOCTYPE&nbsp;ejb-jar&nbsp;PUBLIC&nbsp;"-//Sun&nbsp;Microsystems&nbsp;Inc.//DTD&nbsp;Enterprise&nbsp;JavaBeans&nbsp;1.2//EN"&nbsp;"http://java.sun.com/j2ee/dtds/ejb-jar_1_2.dtd"&gt;<BR>&lt;ejb-jar&gt;<BR>&lt;enterprise-beans&gt;<BR>&lt;session&gt;<BR>&lt;ejb-name&gt;Hello&lt;/ejb-name&gt;<BR>&lt;home&gt;ejb.hello.HelloHome&lt;/home&gt;<BR>&lt;remote&gt;ejb.hello.Hello&lt;/remote&gt;<BR>&lt;ejb-class&gt;ejb.hello.HelloBean&lt;/ejb-class&gt;<BR>&lt;session-type&gt;Stateless&lt;/session-type&gt;<BR>&lt;transaction-type&gt;Container&lt;/transaction-type&gt;<BR>&lt;/session&gt;<BR>&lt;/enterprise-beans&gt;<BR>&lt;assembly-descriptor&gt;<BR>&lt;container-transaction&gt;<BR>&lt;method&gt;<BR>&lt;ejb-name&gt;Hello&lt;/ejb-name&gt;<BR>&lt;method-name&gt;*&lt;/method-name&gt;<BR>&lt;/method&gt;<BR>&lt;trans-attribute&gt;Required&lt;/trans-attribute&gt;<BR>&lt;/container-transaction&gt;<BR>&lt;/assembly-descriptor&gt;<BR>&lt;/ejb-jar&gt;<BR></PRE>
<HR>
</BLOCKQUOTE><BR>6、编译和部署<BR>编译Java源文件并将编译后class和ejb-jar.xml打包到Hello.jar<BR>mkdir&nbsp;build<BR>mkdir&nbsp;build/META-INF<BR>cp&nbsp;ejb-jar.xml&nbsp;build/META-INF<BR>javac&nbsp;-d&nbsp;build&nbsp;*.java<BR>cd&nbsp;build<BR>jar&nbsp;cvf&nbsp;Hello.jar&nbsp;META-INF&nbsp;ejb<BR>cd&nbsp;..<BR>用EJB工具生成可部署到Apusic&nbsp;Application&nbsp;Server中运行的jar文件:<BR>java&nbsp;com.apusic.ejb.utils.EJBGen&nbsp;-d&nbsp;/usr/apusic/classes/Hello.jar&nbsp;build/Hello.jar<BR>增加/usr/apusic/classes/Hello.jar到CLASSPATH中<BR>将Hello.jar加入到Apusic&nbsp;Application&nbsp;Server配置文件中。在/usr/apusic/config/server.xml&nbsp;加入以下几行：<BR>
<BLOCKQUOTE><FONT size=-1>CODE:</FONT> 
<HR>
<PRE><BR>&lt;module&gt;<BR>&lt;ejb&gt;<BR>&lt;ejb-uri&gt;classes/Hello.jar&lt;/ejb-uri&gt;<BR>&lt;bean&gt;<BR>&lt;ejb-name&gt;Hello&lt;/ejb-name&gt;<BR>&lt;jndi-name&gt;HelloHome&lt;/jndi-name&gt;<BR>&lt;/bean&gt;<BR>&lt;/ejb&gt;<BR>&lt;/module&gt;<BR></PRE>
<HR>
</BLOCKQUOTE><BR>启动服务器<BR>java&nbsp;-Xms64m&nbsp;com.apusic.server.Main&nbsp;-root&nbsp;/usr/apusic<BR><BR>7、写客户端调用程序<BR>您可以从Java&nbsp;Client，JSP，Servlet或别的EJB调用HelloBean。<BR>调用EJB有以下几个步骤：<BR>通过JNDI(Java&nbsp;Naming&nbsp;Directory&nbsp;Interface)得到EJB&nbsp;Home&nbsp;Interface<BR>通过EJB&nbsp;Home&nbsp;Interface&nbsp;创建EJB对象，并得到其Remote&nbsp;Interface<BR>通过Remote&nbsp;Interface调用EJB方法<BR><BR>以下是一个从Java&nbsp;Client中调用HelloBean的例子：<BR>
<BLOCKQUOTE><FONT size=-1>CODE:</FONT> 
<HR>
<PRE><BR>package&nbsp;ejb.hello;<BR><BR>import&nbsp;javax.naming.Context;<BR>import&nbsp;javax.naming.InitialContext;<BR>import&nbsp;java.util.Hashtable;<BR>import&nbsp;javax.ejb.*;<BR>import&nbsp;java.rmi.RemoteException;<BR><BR>/**<BR>*&nbsp;@author&nbsp;Copyright&nbsp;(c)&nbsp;2000&nbsp;by&nbsp;Apusic,&nbsp;Inc.&nbsp;All&nbsp;Rights&nbsp;Reserved.<BR>*/<BR>public&nbsp;class&nbsp;HelloClient{<BR>public&nbsp;static&nbsp;void&nbsp;main(String&nbsp;args[]){<BR>String&nbsp;url&nbsp;=&nbsp;"rmi://localhost:6888";<BR>Context&nbsp;initCtx&nbsp;=&nbsp;null;<BR>HelloHome&nbsp;hellohome&nbsp;=&nbsp;null;<BR>try{<BR>Hashtable&nbsp;env&nbsp;=&nbsp;new&nbsp;Hashtable();<BR>env.put(Context.INITIAL_CONTEXT_FACTORY,<BR>"com.apusic.jndi.InitialContextFactory");<BR>env.put(Context.PROVIDER_URL,&nbsp;url);<BR>initCtx&nbsp;=&nbsp;new&nbsp;InitialContext(env);<BR>}catch(Exception&nbsp;e){<BR>System.out.println("Cannot&nbsp;get&nbsp;initial&nbsp;context:&nbsp;"&nbsp;+&nbsp;e.getMessage());<BR>System.exit(1);<BR>}<BR>try{<BR>hellohome&nbsp;=&nbsp;(HelloHome)initCtx.lookup("HelloHome");<BR>Hello&nbsp;hello&nbsp;=&nbsp;hellohome.create();<BR>String&nbsp;s&nbsp;=&nbsp;hello.getHello();<BR>System.out.println(s);<BR>}catch(Exception&nbsp;e){<BR>System.out.println(e.getMessage());<BR>System.exit(1);<BR>}<BR>}<BR><BR>}<BR></PRE>
<HR>
</BLOCKQUOTE><BR>运行HelloClient，可得到以下输出：<BR>Hello&nbsp;World&nbsp;<BR><img src ="http://www.blogjava.net/TrampEagle/aggbug/28636.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-01-19 11:35 <a href="http://www.blogjava.net/TrampEagle/articles/28636.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>漫谈EJB (2)</title><link>http://www.blogjava.net/TrampEagle/articles/28634.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Thu, 19 Jan 2006 03:33:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/28634.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/28634.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/28634.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/28634.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/28634.html</trackback:ping><description><![CDATA[<TABLE width="92%" border=0>
<TBODY>
<TR>
<TD align=left colSpan=3>引自：<A href="http://www.cnjsp.org/view.jsp?column=2&amp;id=560">http://www.cnjsp.org/view.jsp?column=2&amp;id=560</A><BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp; &nbsp;EJB技术的基础是另外两种技术：RMI-IIOP和JNDI。要想了解EJB，一定要先了解RMI-IIOP和JNDI。因此，我们在介绍EJB细节之前，先了解这两项技术。我们的介绍比较基本，因此大多数组织只要了解这些就已经够了。<BR><BR>Java&nbsp;RMI-IIOP<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;Java&nbsp;RMI-IIOP（Java&nbsp;Remote&nbsp;Method&nbsp;Invocation&nbsp;over&nbsp;the&nbsp;Internet&nbsp;Inter-ORB&nbsp;Protocol）是J2EE的网络机制。Java&nbsp;RMI-IIOP允许你编写分布式对象，使得对象的通信范围能够在内存中，跨Java虚拟机，跨物理设备。<BR><BR>Remote&nbsp;Method&nbsp;Invocation<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;RPC（remote&nbsp;procedure&nbsp;call）是一台机器的进程调用另一台机器的进程的过程。而remote&nbsp;method&nbsp;invocation则比RPC的概念更进一步，允许分布式对象间的通信。RMI-IIOP允许调用远程对象的方法，而不仅仅是过程。这有利于面向对象编程。Java&nbsp;RMI&nbsp;（Remote&nbsp;Method&nbsp;Invocation&nbsp;远程方法调用）是用Java在JDK1.1中实现的，它大大增强了Java开发分布式应用的能力。Java作为一种风靡一时的网络开发语言，其巨大的威力就体现在它强大的开发分布式网络应用的能力上，而RMI就是开发百分之百纯Java的网络分布式应用系统的核心解决方案之一。其实它可以被看作是RPC的Java版本。但是传统RPC并不能很好地应用于分布式对象系统。而Java&nbsp;RMI&nbsp;则支持存储于不同地址空间的程序级对象之间彼此进行通信，实现远程对象之间的无缝远程调用。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;remote&nbsp;method&nbsp;invocation决不简单，需要考虑几个问题：<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;marshalling和unmarshalling.在不同机器间通过网络传递变量（包括Java基本类型和对象），如果目标机器表示数据的方式和原机器不同该怎么办？例如二进制库不同。因此marshalling和unmarshalling就是传递变量的过程。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;变量传递方法.变量有两种传递方法：pass-by-value和pass-by-reference。对于前者，你的目标方法只需使用一份copy，但对于后者，远程方法对变量的任何修改都会影响到源数据。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;网络和机器的不稳定.需要有一种机制保证一个JVM崩溃之后，不会影响系统的正常运作。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;在&nbsp;Java&nbsp;分布式对象模型中，remote&nbsp;object&nbsp;是这样一种对象：它的方法可以从其它&nbsp;Java&nbsp;虚拟机（可能在不同的主机上）中调用。该类型的对象由一种或多种&nbsp;remote&nbsp;interfaces（它是声明远程对象方法的&nbsp;Java&nbsp;接口）描述。远程方法调用&nbsp;(RMI)&nbsp;就是调用远程对象上远程接口的方法的动作。更为重要的是，远程对象的方法调用与本地对象的方法调用语法相同。<BR><BR>Remote&nbsp;Interface<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;RMI-IIOP遵循了接口和实现的原则。你写的所有网络代码都是应用于接口，而不是实现。实际上，你必须使用RMI-IIOP中的范例，没有其它的选择。直接在你的对象实现上执行远程调用是不可能的，你只能在对象类的接口上单独进行这一操作。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;所以我们在使用RMI-IIOP时，你必须建立一个客户接口，叫做remote&nbsp;interface。这个远程接口应该扩展java.rmi.Remote接口。<BR><BR>Remote&nbsp;Object&nbsp;Implementation<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;远程对象和客户机的物理位置并不是很重要。可以运行在同一地址空间或是跨Internet运行。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;为了使对象成为一个远程对象，你需要执行一下步骤：<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;继承javax.rmi.PortableRemoteObject。PortableRemoteObject是进行远程调用的基类，当你的远程对象调用构造器时，PortableRemoteObject对象的构造器也会自动被调用。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;不继承javax.rmi.PortableRemoteObject。如果你的远程对象需要继承其它的类，而Java不允许多重继承，因此你不能继承PortableRemoteObject。这时，你需要手动调用javax.rmi.PortableRemoteObject.exportObject()。<BR><BR>Stub和Skeletons<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;我们来看看在RMI-IIOP背后隐藏的网络架构。RMI-IIOP的一个好处就是你可以不用管你要调用的对象是本地的还是远程的。这就叫做local/remote&nbsp;transparency。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;RMI应用程序通常包括两个独立的程序：服务器程序和客户机程序。典型的服务器应用程序将创建多个远程对象，使这些远程对象能够被引用，然后等待客户机调用这些远程对象的方法。而典型的客户机程序则从服务器中得到一个或多个远程对象的引用，然后调用远程对象的方法。RMI为服务器和客户机进行通信和信息传递提供了一种机制。<BR><BR><BR><BR><BR><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;在与远程对象的通信过程中，RMI使用标准机制：stub和skeleton。远程对象的stub担当远程对象的客户本地代表或代理人角色。调用程序将调用本地stub的方法，而本地stub将负责执行对远程对象的方法调用。在RMI中，远程对象的stub与该远程对象所实现的远程接口集相同。调用stub的方法时将执行下列操作：(1)&nbsp;初始化与包含远程对象的远程虚拟机的连接；(2)&nbsp;对远程虚拟机的参数进行编组（写入并传输）；(3)&nbsp;等待方法调用结果；(4)&nbsp;解编（读取）返回值或返回的异常；(5)&nbsp;将值返回给调用程序。为了向调用程序展示比较简单的调用机制，stub将参数的序列化和网络级通信等细节隐藏了起来。在远程虚拟机中，每个远程对象都可以有相应的skeleton（在JDK1.2环境中无需使用skeleton）。Skeleton负责将调用分配给实际的远程对象实现。它在接收方法调用时执行下列操作：(1)&nbsp;解编（读取）远程方法的参数；(2)&nbsp;调用实际远程对象实现上的方法；(3)&nbsp;将结果（返回值或异常）编组（写入并传输）给调用程序。stub和skeleton由rmic编译器生成。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;要实现local/remote&nbsp;transparency可没有那么简单。为了屏蔽你调用的是远端主机上的对象，RMI-IIOP需要模拟一个本地对象供你调用。这个本地对象叫做stub。它负责接受本地的方法调用请求，把这些请求委托给真正实现它们的对象（可以通过网络定位）。这样就使得远程调用看起来就和本地调用一样。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;利用RMI编写分布式对象应用程序需要完成以下工作：(1)&nbsp;定位远程对象。应用程序可使用两种机制中的一种得到对远程对象的引用。它既可用RMI的简单命名工具rmiregistry来注册它的远程对象，也可以将远程对象引用作为常规操作的一部分来进行传递和返回。（2）与远程对象通信。远程对象间通信的细节由RMI处理，对于程序员来说，远程通信看起来就像标准的Java方法调用。（3）给作为参数或返回值传递的对象加载类字节码。因为RMI允许调用程序将纯Java对象传给远程对象，所以，RMI将提供必要的机制，既可以加载对象的代码又可以传输对象的数据。在RMI分布式应用程序运行时，服务器调用注册服务程序以使名字与远程对象相关联。客户机在服务器上的注册服务程序中用远程对象的名字查找该远程对象，然后调用它的方法。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;定位远程对象。应用程序可使用两种机制中的一种得到对远程对象的引用。它既可用&nbsp;RMI&nbsp;的简单命名工具&nbsp;rmiregistry&nbsp;来注册它的远程对象；也可将远程对象引用作为常规操作的一部分来进行传递和返回。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;与远程对象通讯。远程对象间通讯的细节由&nbsp;RMI&nbsp;处理；对于程序员来说，远程通讯看起来就象标准的&nbsp;Java&nbsp;方法调用。给作为参数或返回值传递的对象加载类字节码因为&nbsp;RMI允许调用程序将纯&nbsp;Java&nbsp;对象传给远程对象，所以&nbsp;RMI&nbsp;将提供必要的机制，既可以加载对象的代码又可以传输对象的数据。服务器调用注册服务程序以使名字与远程对象相关联。客户机在服务器注册服务程序中用远程对象的名字查找该远程对象，然后调用它的方法。RMI&nbsp;能用&nbsp;Java系统支持的任何&nbsp;URL&nbsp;协议（例如&nbsp;HTTP、FTP、file&nbsp;等）加载类字节码。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;stub只是解决了一半的问题。我们还希望远程对象也不用考虑网络问题。因此远程对象也需要一个本地的skeleton来接受调用。skeleton接受网络调用并把调用委托给远程对象实现。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;你的J2EE服务器应当提供一种方法来产生必须的stub和skeleton，以减轻你的对网络问题考虑的负担。典型的是通过命令行工具来完成，例如sun的J2EE参考实现包就使用了一个名为rmic（RMI&nbsp;compiler）的工具来产生stub和skeleton类。你应当把stub部署在客户机上，并把skeleton部署在服务器上。<BR><BR>对象序列化和变量传递<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;在RMI分布式应用系统中，服务器与客户机之间传递的Java对象必须是可序列化的对象。不可序列化的对象不能在对象流中进行传递。对象序列化扩展了核心Java输入/输出类，同时也支持对象。对象序列化支持把对象编码以及将通过它们可访问到的对象编码变成字节流；同时，它也支持流中对象图形的互补重构造。序列化用于轻型持久性和借助于套接字或远程方法调用(RMI)进行的通信。序列化中现在包括一个&nbsp;API（Application&nbsp;Programming&nbsp;Interface，应用程序接口），允许独立于类的域指定对象的序列化数据，并允许使用现有协议将序列化数据域写入流中或从流中读取，以确保与缺省读写机制的兼容性。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;为编写应用程序，除多数瞬态应用程序外，都必须具备存储和检索&nbsp;Java对象的能力。以序列化方式存储和检索对象的关键在于提供重新构造该对象所需的足够对象状态。存储到流的对象可能会支持&nbsp;Serializable（可序列化）或&nbsp;Externalizable（可外部化）接口。对于Java对象，序列化形式必须能标识和校验存储其内容的对象所属的&nbsp;Java类，并且将该内容还原为新的实例。对于可序列化对象，流将提供足够的信息将流的域还原为类的兼容版本。对于可外部化对象，类将全权负责其内容的外部格式。序列化&nbsp;Java&nbsp;对象的目的是：提供一种简单但可扩充的机制，以序列化方式维护&nbsp;Java对象的类型及安全属性；具有支持编组和解编的扩展能力以满足远程对象的需要；具有可扩展性以支持&nbsp;Java&nbsp;对象的简单持久性；只有在自定义时，才需对每个类提供序列化自实现；允许对象定义其外部格式。<BR><BR>java.rmi.Remote&nbsp;接口&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;在&nbsp;RMI&nbsp;中，远程接口是声明了可从远程&nbsp;Java&nbsp;虚拟机中调用的方法集。远程接&nbsp;<BR>口必须满足下列要求：&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;远程接口至少必须直接或间接扩展&nbsp;java.rmi.Remote&nbsp;接口。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;远程接口中的方法声明必须满足下列远程方法声明的要求：&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;远程方法声明在其&nbsp;throws&nbsp;子句中除了要包含与应用程序有关的异常（注意与应用程序有关的异常无需扩展&nbsp;java.rmi.RemoteException&nbsp;）之外，还必须包括&nbsp;java.rmi.RemoteException&nbsp;异常（或它的超类，例如java.io.IOException&nbsp;或&nbsp;java.lang.Exception&nbsp;）。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;远程方法声明中，作为参数或返回值声明的（在参数表中直接声明或嵌入到参数的非远程对象中）远程对象必须声明为远程接口，而非该接口的实现类。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;java.rmi.Remote&nbsp;接口是一个不定义方法的标记接口：&nbsp;<BR><BR>public&nbsp;interface&nbsp;Remote&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;远程接口必须至少扩展&nbsp;java.rmi.Remote&nbsp;接口（或其它扩展java.rmi.Remote&nbsp;的远程接口）。然而，远程接口在下列情况中可以扩展非远程接口：&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;远程接口也可扩展其它非远程接口，只要被扩展接口的所有方法（如果有）满足远程方法声明的要求。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;例如，下面的接口&nbsp;BankAccount&nbsp;即为访问银行帐户定义了一个远程接口。它包含往帐户存款、使帐户收支平衡和从帐户取款的远程方法：&nbsp;<BR><BR>public&nbsp;interface&nbsp;BankAccount&nbsp;extends&nbsp;java.rmi.Remote&nbsp;<BR>{&nbsp;<BR>public&nbsp;void&nbsp;deposit(float&nbsp;amount)&nbsp;<BR>throws&nbsp;java.rmi.RemoteException;&nbsp;<BR>public&nbsp;void&nbsp;withdraw(float&nbsp;amount)&nbsp;<BR>throws&nbsp;OverdrawnException,&nbsp;java.rmi.RemoteException;&nbsp;<BR>public&nbsp;float&nbsp;getBalance()&nbsp;<BR>throws&nbsp;java.rmi.RemoteException;&nbsp;<BR>}&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;下例说明了有效的远程接口&nbsp;Beta。它扩展非远程接口&nbsp;Alpha（有远程方法）和接口&nbsp;java.rmi.Remote：&nbsp;<BR>public&nbsp;interface&nbsp;Alpha&nbsp;<BR>{&nbsp;<BR>public&nbsp;final&nbsp;String&nbsp;okay&nbsp;=&nbsp;"constants&nbsp;are&nbsp;okay&nbsp;too";&nbsp;<BR>public&nbsp;Object&nbsp;foo(Object&nbsp;obj)&nbsp;<BR>throws&nbsp;java.rmi.RemoteException;&nbsp;<BR>public&nbsp;void&nbsp;bar()&nbsp;throws&nbsp;java.io.IOException;&nbsp;<BR>public&nbsp;int&nbsp;baz()&nbsp;throws&nbsp;java.lang.Exception;&nbsp;<BR>}&nbsp;<BR><BR>public&nbsp;interface&nbsp;Beta&nbsp;extends&nbsp;Alpha,&nbsp;java.rmi.Remote&nbsp;{&nbsp;<BR>public&nbsp;void&nbsp;ping()&nbsp;throws&nbsp;java.rmi.RemoteException;&nbsp;<BR>}&nbsp;<BR><BR>RemoteException&nbsp;类&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;java.rmi.RemoteException&nbsp;类是在远程方法调用期间由&nbsp;RMI&nbsp;运行时所抛出的异常的超类。为确保使用&nbsp;RMI&nbsp;系统的应用程序的健壮性，远程接口中声明的远程方法在其&nbsp;throws&nbsp;子句中必须指定&nbsp;java.rmi.RemoteException（或它的超类，例如&nbsp;java.io.IOException&nbsp;或&nbsp;java.lang.Exception）。&nbsp;<BR><BR>当远程方法调用由于某种原因失败时，将抛出&nbsp;java.rmi.RemoteException&nbsp;异常。远程方法调用失败的原因包括：&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;通讯失败（远程服务器不可达或拒绝连接；连接被服务器关闭等。）&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;参数或返回值传输或读取时失败&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;协议错误&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;RemoteException&nbsp;类是一个已检验的异常（必须由远程方法的调用程序处理并经编译器检验的异常），而不是&nbsp;RuntimeException。&nbsp;<BR><BR>RemoteObject&nbsp;类及其子类&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;RMI&nbsp;服务器函数由&nbsp;java.rmi.server.RemoteObject&nbsp;及其子类java.rmi.server.RemoteServer、java.rmi.server.UnicastRemoteObject和&nbsp;java.rmi.activation.Activatable&nbsp;提供。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;java.rmi.server.RemoteObject&nbsp;为对远程对象敏感的&nbsp;java.lang.Object方法、hashCode、&nbsp;equals&nbsp;和&nbsp;toString&nbsp;提供实现。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;创建远程对象并将其导出（使它们可为远程客户机利用）所需的方法由类UnicastRemoteObject&nbsp;和&nbsp;Activatable&nbsp;提供。子类可以识别远程引用的语义，例如服务器是简单的远程对象还是可激活的远程对象（调用时将执行的远程对象）。java.rmi.server.UnicastRemoteObject&nbsp;类定义了单体（单路传送）远程对<BR>象，其引用只有在服务器进程活着时才有效。类&nbsp;java.rmi.activation.Activatable&nbsp;是抽象类，它定义的&nbsp;activatable远程对象在其远程方法被调用时开始执行并在必要时自己关闭。&nbsp;<BR><BR>实现远程接口&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;实现远程接口的类的一般规则如下：&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;该类通常扩展&nbsp;java.rmi.server.UnicastRemoteObject，因而将继承类java.rmi.server.RemoteObject&nbsp;和java.rmi.server.RemoteServer&nbsp;提供的远程行为。<BR>&nbsp;&nbsp;&nbsp;&nbsp;该类能实现任意多的远程接口。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;该类能扩展其它远程实现类。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;该类能定义远程接口中不出现的方法，但这些方法只能在本地使用而不能在远程使用。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;例如，下面的类&nbsp;BankAcctImpl&nbsp;实现&nbsp;BankAccount&nbsp;远程接口并扩展java.rmi.server.UnicastRemoteObject&nbsp;类：&nbsp;<BR><BR>package&nbsp;mypackage;&nbsp;<BR><BR>import&nbsp;java.rmi.RemoteException;&nbsp;<BR>import&nbsp;java.rmi.server.UnicastRemoteObject;&nbsp;<BR><BR>public&nbsp;class&nbsp;BankAccountImpl&nbsp;extends&nbsp;UnicastRemoteObject&nbsp;implements&nbsp;<BR>BankAccount&nbsp;<BR><BR>{&nbsp;<BR>private&nbsp;float&nbsp;balance&nbsp;=&nbsp;0.0;&nbsp;<BR><BR>public&nbsp;BankAccountImpl(float&nbsp;initialBalance)&nbsp;<BR>throws&nbsp;RemoteException&nbsp;<BR>{&nbsp;<BR>balance&nbsp;=&nbsp;initialBalance;&nbsp;<BR>}&nbsp;<BR><BR>public&nbsp;void&nbsp;deposit(float&nbsp;amount)&nbsp;throws&nbsp;RemoteException&nbsp;<BR>{&nbsp;<BR>...&nbsp;<BR>}&nbsp;<BR><BR>public&nbsp;void&nbsp;withdraw(float&nbsp;amount)&nbsp;throws&nbsp;OverdrawnException,&nbsp;<BR>RemoteException&nbsp;<BR>{&nbsp;<BR>...&nbsp;<BR>}&nbsp;<BR><BR>public&nbsp;float&nbsp;getBalance()&nbsp;throws&nbsp;RemoteException&nbsp;<BR>{&nbsp;<BR>...&nbsp;<BR>}&nbsp;<BR>}&nbsp;<BR><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;注意：必要时，实现远程接口的类能扩展除java.rmi.server.UnicastRemoteObject&nbsp;类以外的其它一些类。但实现类此时必须承担起一定的责任，即导出对象（由&nbsp;UnicastRemoteObject&nbsp;构造函数负责）和实现从&nbsp;java.lang.Object&nbsp;类继承的&nbsp;hashCode、&nbsp;equals&nbsp;和toString&nbsp;方法的正确远程语义（如果需要）。&nbsp;<BR><BR><BR>远程方法调用中的参数传递&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;传给远程对象的参数或源于它的返回值可以是任意可序列化的&nbsp;Java&nbsp;对象。这包括&nbsp;Java&nbsp;基本类型,&nbsp;远程?Java&nbsp;对象和实现&nbsp;java.io.Serializable&nbsp;接口的非远程&nbsp;Java&nbsp;对象。有关如何使类序列化的详细信息，参见&nbsp;Java“对象序列化规范”。本地得不到的作为参数或返回值的类，可通过&nbsp;RMI&nbsp;系统进行动态下载。&nbsp;<BR><BR>传递非远程对象&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;非远程对象将作为远程方法调用的参数传递或作为远程方法调用的结果返回时，是通过复制传递的；也就是使用&nbsp;Java&nbsp;对象序列化机制将该对象序列化。因此，在远程对象调用过程中，当非远程对象作为参数或返回值传递时，非远程对象的内容在调用远程对象之前将被复制。从远程方法调用返回非远程对象时，将在调用的虚拟机中创建新对象。&nbsp;<BR><BR>传递远程对象&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;当将远程对象作为远程方法调用的参数或返回值传递时，远程对象的&nbsp;stub&nbsp;程序即被传递出去。作为参数传递的远程对象仅能实现远程接口。&nbsp;<BR><BR>引用的完整性&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;如果一个对象的两个引用在单个远程方法调用中以参数形式（或返回值形式）从一个虚拟机传到另一个虚拟机中，并且它们在发送虚拟机中指向同一对象，则两个引用在接收虚拟机中将指向该对象的同一副本。进一步说就是：在单个远程方法调用中，RMI&nbsp;系统将在作为调用参数或返回值传递的对象中保持引用的完整性。&nbsp;<BR><BR>类注解&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;当对象在远程调用中被从一个虚拟机发送到另一个虚拟机中时，RMI&nbsp;系统在调用流中用类的信息&nbsp;(URL)&nbsp;给类描述符加注解，以便该类能在接收器上加载。在远程方法调用期间，调用可随时下载类。&nbsp;<BR><BR>参数传输&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;为将&nbsp;RMI&nbsp;调用的参数序列化到远程调用的目的文件里，需要将该参数写入作为java.io.ObjectOutputStream&nbsp;类的子类的流中。ObjectOutputStream&nbsp;子类将覆盖&nbsp;replaceObject&nbsp;方法，目的是用其相应的&nbsp;stub&nbsp;类取代每个远程对象。对象参数将通过&nbsp;ObjectOutputStream&nbsp;的&nbsp;writeObject&nbsp;方法写入流中。而ObjectOutputStream&nbsp;则通过&nbsp;writeObject&nbsp;方法为每个写入流中的对象（包含所写对象所引用的对象）调用&nbsp;replaceObject&nbsp;方法。RMIObjectOutputStream子类的&nbsp;replaceObject&nbsp;方法返回下列值：&nbsp;<BR>如果传给&nbsp;replaceObject&nbsp;的对象是&nbsp;java.rmi.Remote&nbsp;的实例，则返回远程对象的&nbsp;stub&nbsp;程序。远程对象的&nbsp;stub&nbsp;程序通过对java.rmi.server.RemoteObject.toStub方法的调用而获得。如果传给&nbsp;replaceObject&nbsp;的对象不是&nbsp;java.rmi.Remote&nbsp;的实例，则只返回该对象。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;RMI&nbsp;的&nbsp;ObjectOutputStream&nbsp;子类也实现&nbsp;annotateClass&nbsp;方法，该方法用类的位置注解调用流以便能在接收器中下载该类。有关如何使用&nbsp;annotateClass的详细信息，参见“动态类加载”一节。因为参数只写入一个&nbsp;ObjectOutputStream，所以指向调用程序同一对象的引用将在接收器那里指向该对象的同一副本。在接收器上，参数将被单个ObjectInputStream&nbsp;所读取。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;用于写对象的&nbsp;ObjectOutputStream（类似的还有用于读对象的ObjectInputStream&nbsp;）的所有其它缺省行为将保留在参数传递中。例如，写对象时对&nbsp;writeReplace&nbsp;的调用及读对象时对&nbsp;readResolve&nbsp;的调用就是由&nbsp;RMI的参数编组与解编流完成的。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;与上述&nbsp;RMI&nbsp;参数传递方式类似，返回值（或异常）将被写入ObjectOutputStream的子类并和参数传输的替代行为相同。&nbsp;<BR><BR>定位远程对象&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;我们专门提供了一种简单的引导名字服务器，用于存储对远程对象的已命名引用。使用类&nbsp;java.rmi.Naming&nbsp;的基于&nbsp;URL&nbsp;的方法可以存储远程对象引用。客户机要调用远程对象的方法，则必须首先得到该对象的引用。对远程对象的引用通常是在方法调用中以返回值的形式取得。RMI&nbsp;系统提供一种简单的引导名字服务器，通过它得到给定主机上的远程对象。java.rmi.Naming&nbsp;类提供基于统一资源定位符&nbsp;(URL)&nbsp;的方法，用来绑定、再绑定、解开和列出位于某一主机及端口上的名字-对象对。&nbsp;<BR></TD></TR>
<TR>
<TD colSpan=3 height=15>&nbsp;</TD></TR></TBODY></TABLE><img src ="http://www.blogjava.net/TrampEagle/aggbug/28634.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-01-19 11:33 <a href="http://www.blogjava.net/TrampEagle/articles/28634.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>漫谈EJB (一)</title><link>http://www.blogjava.net/TrampEagle/articles/28633.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Thu, 19 Jan 2006 03:30:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/28633.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/28633.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/28633.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/28633.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/28633.html</trackback:ping><description><![CDATA[<P>引自：<A href="http://www.cnjsp.org/view.jsp?column=2&amp;id=559">http://www.cnjsp.org/view.jsp?column=2&amp;id=559</A><BR><BR>Java语言<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;Java语言最早被称为Oak，它是为了实现嵌入式的消费类电子产品应用而产生的，它的作者是James&nbsp;Gosling。Ed&nbsp;Frank,&nbsp;Patrick&nbsp;Naughton,&nbsp;Jonathan&nbsp;Payne,&nbsp;Chris&nbsp;Warth在随后的几年时间中为Java语言加入了大量的特性，并把Java语言的目标做了一个重新的定位，定位于适合Internet的语言。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;Java语言是一种多用途的语言、并发的语言、以类为基础，面向对象的语言。它的设计尽可能的做到和操作系统是无关的，也就是Java所宣传的那句话：“一次编写，到处运行。”Java的设计参考了C和C++语言，因此熟悉C和C++的程序员对Java语言上手很快，而Java设计的原则是能够利用Java语言快捷的编写应用，所以我们可以发现，在Java语言中，并没有那些C和C++中的复杂的机制。最明显的就是C中被大量使用的指针，由于它的随意性，被Java以引用来代替了。而C++中的操作符重载、模板、泛型的特性也因为使用比较复杂，Java也不予采用。但是目前Java仍然不断的推出新的特性，以满足应用的发展。例如在新推出的JDK1.4中，Java语言就能够支持Assertment机制和Perl语言中最有用的正则表达式机制。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;Java语言主要由以下五种元素组成：标识符、关键字、文字、运算符和分隔符。这五种元素有着不同的语法含义和组成规则，它们互相配合，共同完成Java语言的语意表达。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;1：标识符。变量，类和方法都需要一定的名称，我们将这种名称叫做标识符。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;2：关键字。关键字是Java语言本身使用的标识符，它有其特定的语法含义。所有的Java关键字将不能被用作标识符。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;3：数据类型。Java有着不同的数据类型。比较值得一提的是字符串数据类型，字符串数据类型是用一对双引号括起来的字符序列，字符串数据实际上是由String类所实现，而不是Ｃ语言中所用的字符数组。每一个字符串数据将产生一个String类的新的实例，用户不必对字符串与类这个概念发生关系而感到担心，由于类的特性，你不必担心如何去实现它们，它们会自己照顾好自己，需要说明的是字符串在Java里作为类只是出于安全的考虑。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;4：运算符。任何语言都有自己的运算符，Java语言也不例外，如＋、－、＊、／等都是运算符，运算符的作用是与一定的运算数据组成表达式来完成相应的运算。对不同的数据类型，有着不同的运算符。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;5：分隔符。分隔符用来使编译器确认代码在何处分隔。‘’‘’‘;’‘:’都是Java语言的分隔符。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;学习&nbsp;Java&nbsp;语言很简单，毕竟&nbsp;Java&nbsp;语言也只包含五十多个关键词（keyword）与几十个算符（operator），再加上&nbsp;Java&nbsp;语法（syntax）也很简单，所以一般人可以很快就学会&nbsp;Java&nbsp;语言。危险的是，很多人认为已经完全掌控&nbsp;Java&nbsp;语言，但其实对于内部的运作机制仍不能掌握，这些盲点有时候会让你无法完全掌控&nbsp;Java&nbsp;语言。克服这些盲点的方式是看「The&nbsp;Java&nbsp;Language&nbsp;Specification,&nbsp;2nd&nbsp;Ed.」（没有中文版）来彻底弄懂&nbsp;Java&nbsp;程序语言，并看「Inside&nbsp;the&nbsp;Java&nbsp;Virtual&nbsp;Machine,&nbsp;2nd&nbsp;Ed.」来彻底掌握&nbsp;Java&nbsp;虚拟机器的运作方式。学会了语言，并不代表就可以设计出好的对象导向系统架构。想要成为对象导向的专家，往往需要：(1)&nbsp;多看相关的书，特别是&nbsp;Design&nbsp;Pattern&nbsp;和&nbsp;Refactoring&nbsp;的书。(2)&nbsp;多观摩别人的程序（例如&nbsp;Java&nbsp;API&nbsp;的&nbsp;design&nbsp;与&nbsp;implementation）(3)&nbsp;多写程序。学会&nbsp;Java&nbsp;语言之后，还需要学会一些&nbsp;API&nbsp;才能写出有用的程序。Java&nbsp;的&nbsp;API&nbsp;非常多，必须规划好一个学习路径，才不会在浩瀚的&nbsp;API&nbsp;大海中迷失。必备的&nbsp;API&nbsp;包括了：IO、New&nbsp;IO、Collection&nbsp;Framework、Network、RMI、JAXP...&nbsp;等。至于其它的&nbsp;API，就看你的需求而定，大致上分成：<BR><BR>*&nbsp;GUI&nbsp;类：JavaBean&nbsp;-&gt;&nbsp;Swing&nbsp;-&gt;&nbsp;JavaHelp&nbsp;-&gt;&nbsp;Java2D&nbsp;-&gt;&nbsp;Image&nbsp;IO&nbsp;-&gt;&nbsp;JAI&nbsp;-&gt;&nbsp;Java&nbsp;3D&nbsp;...<BR>*&nbsp;Enterprise&nbsp;类：JDBC&nbsp;-&gt;&nbsp;JDO&nbsp;-&gt;&nbsp;Servlet&nbsp;-&gt;&nbsp;JSP&nbsp;-&gt;&nbsp;EJB&nbsp;-&gt;&nbsp;JMS&nbsp;-&gt;&nbsp;JTA/JTS...<BR>*&nbsp;J2ME&nbsp;类（这一类不是我的专长，无法提供学习顺序建议）<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;Java语言通常都是根据Java虚拟机规范（The&nbsp;Java&nbsp;Virtual&nbsp;Machine&nbsp;Specification）中的定义，编译为字节码指令集和二进制格式。因此我们接下来就讨论Java虚拟机（JVM）<BR><BR>JVM<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;我们已经谈过Java语言的语法类似于C和C++，但是摒弃了C和C++中复杂、疑惑和不安全的特性。Java语言最早是用来构建消费类网络设备的软件的，因此它要支持多主机的架构，并要求能够提供安全的软件组件。为了满足这些需求，编译好的代码就必须能够通过网络来传播，能够在任何客户端上运行，同时还要保证客户端是足够安全的。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;Java虚拟机是Java和Java&nbsp;2&nbsp;平台的基石。它能够保证Java语言和硬件、操作系统无关，保证编译后的代码最小，并保护用户不受恶意程序的攻击。Java虚拟机到底是什么呢。其实它就是一台不实际存在的计算机。和真实的计算机类似，它也有自己的指令集，并可以在运行环境中分配内存区域。使用虚拟机机制来实现编程语言并不是Java的创举，这已经是非常普遍的做法了，最著名的许你就莫过于UCSD&nbsp;Pascal的P-Code机。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;只要浏览器检测到目前所处理的Web文件内容含有一个Java&nbsp;Applet，浏览器将会为这个Java小程序另外开一个JVM，执行这个Java应用小程序。在JVM中执行的Java小程序可以得到充分安全的保护。如同我们上面所说，JVM是一个自给自足的作业环境，就像是一台独立的计算机一样。例如，在JVM运作的Applet，无法存取主机操作系统。优点是：<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;系统中立。Java应用程序可以在任何JVM中运作，不论该系统使用何种硬件、软件。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;2.&nbsp;安全。正因JVM跟操作系统没有任何接触，Java程序很难损害到其它档案或应用程序。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;缺点是，由于在JVM运作的程序独立在操作系统之外，也就无法享受操作系统各项特殊功能。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;Java技术之所以在今天得到了如此广阔的应用，其中它的安全性是不能不提的。不同于其它技术（例如Microsoft的ActiveX）中安全性作为附加设计和补丁，Java从设计之初便考虑到了安全性。因此Java的安全性是在语言层次实现的。Java的安全性由下列三个方面保证：<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;1、&nbsp;语言特性（包括数组的边界检查、类型转换、取消指针型变量）。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;2、&nbsp;资源访问控制（包括本地文件系统访问、Socket连接访问）。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;3、&nbsp;代码数字签名（通过数字签名来确认代码源以及代码是否完整）。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;Java的源代码是先编译成为一种字节码的中间代码，存放这种代码的文件就是.class的文件。真正执行的时候是将class文件装载到JVM（虚拟机）中，然后由JVM解释执行的。所以数组的上下界检查及合法的类型转换是通过JVM得到保证的。Java通过一个类装载器类(ClassLoader)将虚拟机代码文件（即class文件）装载到JVM中，当完成装载后，一个被称做安全管理器（SecurityManager）的类开始运行，例如当一个Applet的class文件被缺省的类装载器装载到JVM中后，JVM会立即为它装载一个SecurityManager的子类AppletSecurity，由这个管理器来验证操作。代码的所有动作（例如文件读写）都要先经过验证，只有被该安全管理器接受的动作才能完成，否则就会抛出SecurityException异常。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;对于JDK1.0，权限被笼统的划分为两大块。一是拥有所有的权限，一个是仅拥有"沙箱\\"（sandBox）权限，这也是普通的Applet所拥有的权限。这时本地文件读写或是与源主机（Orignal&nbsp;Server）以外的主机连接都是被禁止的。这种划分的最大问题就是缺乏灵活性。例如我们希望一个Applet在用户信任的情况下能够对本地文件系统的某个目录进行读写，但并不要通过Socket与其它主机连接。这是JDK1.0的权限划分就不能达到要求。JDK1.1后改进了权限的划分，引入了权限集（PermissionSet）的概念。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;由于我们的文章并不是讨论JVM，因此，我们只是对JVM做一个简单的介绍。如果需要详细了解的，可以参考『The&nbsp;JavaTM&nbsp;TMVirtual&nbsp;Machine&nbsp;Specification』。<BR><BR>客观的看待Java<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;相对于其他编程语音，Java有一个无庸置疑的优点：用户以及编译器第一次不必了解生成可执行代码的特定CPU细节。Java引入了一个编译代码中间层，叫做字节代码，并使用一个虚拟抽象的机器，而不是一个真实的机器。当Java编译器结束了一个源文件的编译后，你所得到的不是可以立即在一个给定平台上运行的代码，而是可以在任何真实的平台上运行的字节代码，唯一的条件就是这个平台要理解和支持Java。这些发展包含着一个文化的变革。作为一个开发人员，你只需要确定Java虚拟机(JVM)提供的抽象层，不同的OS销售商负责执行代码层，从而将中立于平台的字节代码映射到主机平台的机构中。在这种情况下，Java似乎是统一分布式计算机世界的领袖候选人了。“编写一次，永远运行”（并且无论在哪里）就成为Java诱人但却真实的口号。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;但我们平心而论，Java的跨平台并不是一个非常诱人的特性？跨平台理论的发展很好地证明了这一点。我们看到，将Java代码从一个平台移植到另一个平台—Java这个语言最重要和最受吹捧的特点—并不象宣传的那样容易。任何Java平台都有其自己的虚拟机，它可以理解通用的字节代码，并且及时地将其编译为本地代码。矛盾由此产生，不同虚拟机的执行也很不相同，这一点足以使代码的移植比预期耗费多得多的时间，而且基本上不是自动的。在企业用户的角度上来说，也很少会有企业会频繁的更换平台，因此这个特性是否能够带来高价值是很难评价的。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;那么，Java模型的好处在哪里呢？首先，Java是一种先进的、面向对象的语言，包含了预防常见错误的内置功能，并在仅仅一两个对象中携带了许多经常需要用到的功能。与C++相比，Java更易于读写，不容易出错，而且更加美观，但是它速度较慢也不太灵活。想实现在任何软件和硬件平台上都可虚拟移植，Java尽可能少地使用了公分母模型，也就是说放弃了将每个平台开发到极限的能力。第二，虚拟机的概念本身就是可移植和可共用的，因此对于分布式环境来说是理想的。Java对于为非Windows平台开发代码是最好的语言。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;那么对于Windows平台来说，Java又怎么样呢？让Java适应Windows是不可能的，这是由于Sun的许可约束问题。但是Java实在是太吸引人了，Microsoft比谁都能更清楚这一点。Microsoft在以前推出的Visual&nbsp;J++证明了这一点，但是可惜的是，Microsoft又犯了霸权的老毛病，Visual&nbsp;J++并不好用。因此，Microsoft又一次采取了“拿来主义”的手法，很好地利用了Java&nbsp;的众多特性，隆重推出了Windows平台的新锐力量，它就是相当简单但十分强大的面向对象的C#编程语言。C#超过了C++，它天生就包含了.NET框架类库中的所有类，并使语法简单化。说到这里已经有一些离题了，不过Java也不是说在Windows平台上就不能够使用，JDK和大部分的IDE都支持Windows平台。<BR><BR>Java技术的架构－－J2ME、J2SE和J2EE<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;通常我们以&nbsp;JDK（Sun&nbsp;所开发的一套&nbsp;Java&nbsp;开发工具）的版本来定义&nbsp;Java&nbsp;的版本。JDK&nbsp;1.0&nbsp;版于&nbsp;1996&nbsp;年初公开，JDK&nbsp;1.1&nbsp;版于&nbsp;1997&nbsp;年初公开，JDK&nbsp;1.2&nbsp;版于&nbsp;1998&nbsp;年底公开。基于市场行销的考量，Sun&nbsp;在&nbsp;JDK&nbsp;1.2&nbsp;版公开后旋即将&nbsp;Java&nbsp;改名为「Java&nbsp;2」，将&nbsp;JDK&nbsp;改名为「Java&nbsp;2&nbsp;Software&nbsp;Development&nbsp;Kit（以下简称&nbsp;J2SDK）」。J2SDK（原称&nbsp;JDK）1.3&nbsp;于&nbsp;2000&nbsp;年&nbsp;4&nbsp;月公开，此版本仍称做「Java&nbsp;2」。目前&nbsp;J2SDK&nbsp;1.4&nbsp;也已经公开了，大家可以到Sun的官方Java站点上查阅到大量的JDK1.4的信息。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;Java&nbsp;技术根据硬件平台与适用环境的差异，分成几个分支。JDK&nbsp;1.1&nbsp;的时代，适用于一般消费性电子产品等，嵌入式系统的&nbsp;Java&nbsp;平台是&nbsp;PersonalJava&nbsp;与&nbsp;EmbeddedJava，此二者并无明确的界线，大致上来说，运算资源、内存、以及显示装置比较丰富者，使用&nbsp;PersonalJava，例如&nbsp;Set-Top&nbsp;Box、视讯电话&nbsp;...&nbsp;等；反之，资源较有限者使用&nbsp;EmbeddedJava，例如呼叫器、行动电话&nbsp;...&nbsp;等。除了&nbsp;PC&nbsp;使用的&nbsp;Java&nbsp;平台、IA&nbsp;使用的&nbsp;PersonalJava&nbsp;与&nbsp;EmbeddedJava&nbsp;平台之外，JavaCard&nbsp;也是一个&nbsp;Java&nbsp;平台，使用于&nbsp;Smart&nbsp;Card（IC&nbsp;Card）上。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;Java&nbsp;2&nbsp;出现后，推翻了先前的&nbsp;PersonalJava&nbsp;与&nbsp;EmeddedJava&nbsp;的分法，改分成&nbsp;Java&nbsp;2&nbsp;Platform&nbsp;Enterprise&nbsp;Edition（简称&nbsp;J2EE）、Java&nbsp;2&nbsp;Platform&nbsp;Standard&nbsp;Edition（简称&nbsp;J2SE）、Java&nbsp;2&nbsp;Platform&nbsp;Micro&nbsp;Edition（简称&nbsp;J2ME）。J2EE&nbsp;适用于服务器，目前已经成为企业运算、电子商务等领域中相当热门的技术；J2SE&nbsp;适用于一般的计算机；J2ME&nbsp;适用于消费性电子产品。除了这三者之外，JavaCard&nbsp;依然是独立的一套标准。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;目前，Java技术的架构包括三个方面：<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;J2EE(Java&nbsp;2&nbsp;Platform&nbsp;Enterprise&nbsp;Edition&nbsp;)—企业版&nbsp;(J2EE)&nbsp;是为面向以企业为环境而开发应用程序的解决方案。<BR>&nbsp;&nbsp;&nbsp;&nbsp;J2SE（Java&nbsp;2&nbsp;Platform&nbsp;Stand&nbsp;Edition）—标准版&nbsp;(J2SE)&nbsp;为桌面开发和低端商务应用提供了可行的解决方案。<BR>&nbsp;&nbsp;&nbsp;&nbsp;J2ME(Java&nbsp;2&nbsp;Platform&nbsp;Micro&nbsp;Edition&nbsp;)—小型版(J2ME)是致力于消费产品和嵌入式设备的最佳解决方案<BR><BR><BR><BR><BR><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;J2EE<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;J2EE已经成为开发商创建电子商务应用的事实标准。正是认识到J2EE平台作为一种可扩展的、全功能的平台，可以将关键的企业应用扩展到任何Web浏览器上并可适合多种不同的Internet数据流、可连接到几乎任何一种传统数据库和解决方案、使企业经理根据多家企业所提供的产品和技术开发和部署最佳的解决方案进而降低开发网络化应用的费用和复杂性这一巨大优势，很多厂家都表示将对J2EE给予支持，并将J2EE技术作为大型BtoB市场和海量交易处理的安全稳定的端到端平台。J2EE技术的基础就是J2SE标准版，它巩固了标准版中的许多优点。其最终目的就是成为一个能够使企业开发者大幅缩短投放市场时间的体系结构。它为灵活配置各种多层企业应用软件,特别是B2B、B2C等电子商务应用,提供了强大的服务功能。最近又新加了Connector&nbsp;API服务,使企业应用的开发和部署有了一系列成熟的技术。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;J2SE<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;J2SE是Java&nbsp;2平台的标准版,&nbsp;它适用于桌面系统，提供CORBA标准的ORB技术,结合Java的RMI支持分布式互操作环境。它运行在Java虚拟机上。在引入了Java&nbsp;IDL后,&nbsp;J2SE支持IIOP通信。它是高可移植性、异构性的实现环境和健壮平台，也是实现可伸缩性、可移植性、分布式异构互操作应用软件开发的标准平台。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;J2ME<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;J2ME提供了HTTP高级Internet协议，使移动电话能以Client/Server方式直接访问Internet的全部信息，不同的Client访问不同的文件，此外还能访问本地存储区，提供最高效率的无线交流。J2ME是Java&nbsp;2平台的微型版,它分成CDC(connected&nbsp;device&nbsp;configuration)和CLDC(connected&nbsp;limited&nbsp;device&nbsp;configuration)两部分。CDC运行在连接虚拟机上,为手提式计算机一类较复杂的移动设备提供应用平台；CLDC运行在核心虚拟机(KVM)上,它实现MIDP(Mobile&nbsp;Information&nbsp;Device&nbsp;Profile)移动信息设备应用平台，即针对手机之类的设备建立移动计算平台。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;在小型的J2ME（Java&nbsp;2&nbsp;Micro&nbsp;Edition）方面，主要是应用在内存容量小、体积也较小的电子装置上。小至智能卡、行动电话，个人数字助理都是运用J2ME的最佳平台。Java在Palm的应用上，PalmOS&nbsp;4.0内含KJava，Sun也推出针对PalmOS使用的J2ME版本。所以，以既有的Java程序设计知识，就可以在Palm&nbsp;PDA上开发出Palm的各式各样应用系统。Java和Palm这两个标准平台的结合，将是下一波PDA应用的趋势。Java在手机的应用上，Nokia、Motorola、Ericsson&nbsp;都将推出利用J2ME技术的新手机，所以Java程序设计师有更多的平台可供施展。此种结合J2ME及无线通讯技术的无线开放应用平台，将提供行动商务极佳的解决方案。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;在中型的J2SE（Java&nbsp;2&nbsp;Standard&nbsp;Edition）方面，Sun推出一个新的解决方案，称为Java&nbsp;Web&nbsp;Start。原先的Java&nbsp;Applet是在WebBrowser&nbsp;中间开出一块方形区域来执行Java程序，但是这样在执行效能和兼容性上都受限于原有的&nbsp;Web&nbsp;Browser。现在新推出的Java&nbsp;Web&nbsp;Start则是在操作系统上直接执行的Java&nbsp;Application，但是可以在网页上激活。如此一来既可和网页结合，在执行上也更快、更有效率。并且，Sun和IBM都将推出支持64位运算的Java版本，这对一般计算机上执行的客户端Java应用系统的开发将会是一大利器。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;另外在大型的J2EE（Java&nbsp;2&nbsp;Enterprise&nbsp;Edition）应用上，可以说"J2EE"已经成为服务器运算环境的标准。Java&nbsp;Servlets、JSP（Java&nbsp;ServerPages）、EJB（Enterprise&nbsp;JavaBeans）、JavaMail、JDBC、JMS等，都是各家厂商产品开发的重点方向。J2EE兼容的是一般Intel个人计算机（Linux、Windows.....）、麦金塔以及各家高效能高稳定度的UNIX伺服主机，未来必定成为服务器运算市场上的主要选择之一。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;除了以上这三大Java组合之外，Java和XML的整合也是未来的重点。Sun公司已经推出Java处理XML的标准延伸API&nbsp;-&nbsp;Java&nbsp;API&nbsp;for&nbsp;XML&nbsp;Parsing&nbsp;(JAXP)，可以让各家所制作的XML解析器有接口上的标准。所以在Java程序中，只要了解一套API(JAXP)就可以完全处理XML文件，让XML的应用更加方便。Java这个跨平台的开发环境，加上XML这个跨平台的资料格式，此种跨平台优势组合势将成为未来讯息传递及资料交换的主要应用技术，如虎添翼地结合成一个最佳的跨平台解决方案。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;藉由J2SE&nbsp;(Java&nbsp;2&nbsp;Standard&nbsp;Edition)可以开发在PC上的应用软件，藉由J2ME&nbsp;(Java&nbsp;2&nbsp;Micro&nbsp;Edition)&nbsp;可以跨足更广大的家电、智能卡、电子装置等市场，再藉由J2EE&nbsp;(Java&nbsp;2&nbsp;Enterprise&nbsp;Edition&nbsp;)&nbsp;可以整合伺服主机运算环境。Java技术的应用范围几乎已经无所不在，Java技术更可以在网际网络及电子商务各领域中，提供全方位的解决方案。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;随着应用领域的不同，Java&nbsp;有许多&nbsp;API（Application&nbsp;Programming&nbsp;Interface），这些&nbsp;API&nbsp;分成三大类：<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;·&nbsp;Java&nbsp;Core&nbsp;API：由&nbsp;Sun&nbsp;制定的基本&nbsp;API，任何&nbsp;Java&nbsp;平台都必须提供。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;·&nbsp;Java&nbsp;Standard&nbsp;Extension&nbsp;API&nbsp;(javax)：由&nbsp;Sun&nbsp;制定的扩充&nbsp;API，Java&nbsp;平台可以选择性地提供或加装。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;·&nbsp;厂商或组织所提供的&nbsp;API：由各家公司或组织所提供。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;其中&nbsp;Core&nbsp;API&nbsp;和&nbsp;Standard&nbsp;Extension&nbsp;API&nbsp;已经逐渐涵盖了大部份的信息应用领域，例如多媒体、数据库、Web、企业运算、语音、实时系统、网络、电话、影像处理、加解密、GUI、分布式运算&nbsp;......。如果你有某项需求尚未有标准的&nbsp;Java&nbsp;API&nbsp;可遵循，你可以向&nbsp;Sun&nbsp;提出制定新&nbsp;API&nbsp;的请求。经过审核之后，你的要求可能会通过、驳回&nbsp;......&nbsp;等。如果通过，就会开始进入制定&nbsp;API&nbsp;的程序。Java&nbsp;API&nbsp;的制定过程因为公开，且经过许多业界技术领先公司的共同参与，所以相当完善而优异。<BR><BR><BR>EJB的生态环境<BR><BR>在sun公司提供的EJB规范中，我们一个完整的基于EJB的分布式计算结构由六个角色组成，这六个角色可以由不同的开发商提供，每个角色所作的工作必须遵循Sun公司提供的EJB规范，以保证彼此之间的兼容性。<BR><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;EJB组件开发者:&nbsp;开发并销售&nbsp;EJB。<BR>&nbsp;&nbsp;&nbsp;&nbsp;应用组合者:&nbsp;将不同的&nbsp;EJB&nbsp;搭建成应用。<BR>&nbsp;&nbsp;&nbsp;&nbsp;部署者:&nbsp;使用相应工具在运行环境下配置&nbsp;EJB。<BR>&nbsp;&nbsp;&nbsp;&nbsp;EJB&nbsp;服务器提供者:&nbsp;开发并销售&nbsp;EJB&nbsp;服务器&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;EJB&nbsp;容器供应商:&nbsp;开发并销售&nbsp;EJB&nbsp;容器&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;系统管理员:&nbsp;监视运行时情况<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;1、EJB组件开发者(Enterprise&nbsp;Bean&nbsp;Provider)<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;EJB组件开发者负责开发执行商业逻辑规则的EJB组件，开发出的EJB组件打包成ejb-jar文件。EJB组件开发者负责定义EJB的remote和home接口，编写执行商业逻辑的EJB&nbsp;class,提供部署EJB的部署文件(deployment&nbsp;descriptor)。部署文件包含EJB的名字，EJB用到的资源配置，如JDBC等。EJB组件开发者是典型的商业应用开发领域专家。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;EJB组件开发者不需要精通系统级的编程，因此，不需要知道一些系统级的处理细节，如事务、同步、安全、分布式计算等。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;2、应用组合者(Application&nbsp;Assembler)<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;应用组合者负责利用各种EJB组合一个完整的应用系统。应用组合者有时需要提供一些相关的程序，如在一个电子商务系统里，应用组合者需要提供JSP(Java&nbsp;Server&nbsp;Page)程序。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;应用组合者必须掌握所用的EJB的home和remote接口，但不需要知道这些接口的实现。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;3、部署者(Deployer)<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;部署者负责将ejb-jar文件部署到用户的系统环境中。系统环境包含某种EJB&nbsp;Server和EJB&nbsp;Container。部署者必须保证所有由EJB组件开发者在部署文件中声明的资源可用，例如，部署者必须配置好EJB所需的数据库资源。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;部署过程分两步：部署者首先利用EJB&nbsp;Container提供的工具生成一些类和接口，使EJB&nbsp;Container能够利用这些类和接口在运行状态管理EJB。&nbsp;部署者安装EJB组件和其他在上一步生成的类到EJB&nbsp;Container中。&nbsp;部署者是某个EJB运行环境的专家。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;某些情况下，部署者在部署时还需要了解EJB包含的业务方法，以便在部署完成后，写一些简单的程序测试。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;4、EJB&nbsp;服务器提供者(EJB&nbsp;Server&nbsp;Provider)<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;EJB&nbsp;服务器提供者是系统领域的专家，精通分布式交易管理，分布式对象管理及其它系统级的服务。EJB&nbsp;服务器提供者一般由操作系统开发商、中间件开发商或数据库开发商提供。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;在目前的EJB规范中，假定EJB&nbsp;服务器提供者和EJB&nbsp;容器提供者来自同一个开发商，所以，没有定义EJB&nbsp;服务器提供者和EJB容器提供者之间的接口标准。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;5、EJB&nbsp;容器提供者(EJB&nbsp;Container&nbsp;Provider)<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;EJB&nbsp;容器提供者提供以下功能：<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;提供EJB部署工具为部署好的EJB组件提供运行环境&nbsp;。EJB容器负责为EJB提供交易管理，安全管理等服务。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;EJB&nbsp;容器提供者必须是系统级的编程专家，还要具备一些应用领域的经验。EJB&nbsp;容器提供者的工作主要集中在开发一个可伸缩的，具有交易管理功能的集成在EJB&nbsp;服务器中的容器。EJB&nbsp;容器提供者为EJB组件开发者提供了一组标准的、易用的API访问EJB&nbsp;容器，使EJB组件开发者不需要了解EJB服务器中的各种技术细节。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;EJB容器提供者负责提供系统监测工具用来实时监测EJB容器和运行在容器中的EJB组件状态。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;6、系统管理员(System&nbsp;Administrator)<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;系统管理员负责为EJB服务器和容器提供一个企业级的计算和网络环境。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;系统管理员负责利用EJB&nbsp;服务器和容器提供的监测管理工具监测EJB组件的运行情况。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;将责任分离的另一个好处是在代码级上，可以将基于EJBs的系统逻辑的分派给更适合的专家。SUN的EJB规范建议使用几个独立的角色，对于确定运作环境的责任链是非常重要的。举例说，EJB提供者是由商业专家和分析人员扮演的角色，他们确定一个组织内的最佳信息流程。但是仍旧有Second&nbsp;Domain&nbsp;Expert，如应用程序汇编人员，他们集成不同的EJB组件并确保它可以确保满足应用程序的需求。<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;还有两种角色归入到系统级的部分，第一个是配置人员，他们负责实际的安装和配置基于EJB的系统。这需要有设置目录服务和集成现有应用程序的经验。第二个是系统管理员，他们要提供全天的监视和支持，确保应用程序正常运作。尽管系统管理员这个角色不需要是Java编程专家，但是他需要能够应付以下问题：<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;设置Java&nbsp;Virtual&nbsp;Machine&nbsp;(JVM)并关联系统环境参数（如：CLASSPATH）&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;使用Java&nbsp;Archive&nbsp;(jar)命令保存类文件&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;懂得WEB服务器和Servlet的工作原理。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;要能通过监视运行中程序的状态确定优化方法。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;很明显，有些角色是可以交叉的，比如系统管理员和配置人员。尽管配置人员可能是将类文件复制到服务器而系统管理员需要确定配置人员是否复制到了正确的位置。&nbsp;<BR></P><img src ="http://www.blogjava.net/TrampEagle/aggbug/28633.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-01-19 11:30 <a href="http://www.blogjava.net/TrampEagle/articles/28633.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《EJB调用的原理分析》</title><link>http://www.blogjava.net/TrampEagle/articles/27366.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Tue, 10 Jan 2006 05:10:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/27366.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/27366.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/27366.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/27366.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/27366.html</trackback:ping><description><![CDATA[<SPAN class=postbody>引自：<A href="http://forum.javaeye.com/viewtopic.php?t=1036">http://forum.javaeye.com/viewtopic.php?t=1036</A><BR><BR>一个远程对象至少要包括4个class文件：远程对象；远程对象的接口；实现远程接口的对象的stub；对象的skeleton这4个class文件。 <BR><BR>在EJB中则至少要包括10个class： <BR>Bean类，特定App Server的Bean实现类 <BR>Bean的remote接口，特定App Server的remote接口实现类，特定App Server的remote接口的实现类的stub类和skeleton类 <BR>Bean的home接口，特定App Server的home接口实现类，特定App Server的home接口的实现类的stub类和skeleton类 <BR><BR>和RMI不同的是，EJB中这10个class真正需要用户编写的只有3个，分别是Bean类和它的remote接口，home接口，至于其它的7个class到底是怎么生成，被打包在什么地方，或者是否需要更多的类文件，会根据不同的App Server表现出比较大的差异，不能一概而论。 <BR><BR>拿我最熟悉的Weblogic的来说吧，Weblogic的Bean实现类，以及两个接口的Weblogic的实现类是在ejbc的时候被打包到EJB的jar包里面的，这3个class文件可以看到。而home接口和remote接口的Weblogic的实现类的stub类和skeleton类是在EJB被部署到Weblogic的时候，由Weblogic动态生成stub类和Skeleton类的字节码，因此看不到这4个类文件。 <BR><BR>对于一次客户端远程调用EJB，要经过两个远程对象的多次RMI循环。首先是通过JNDI查找Home接口，获得Home接口的实现类，这个过程其实相当复杂，首先是找到Home接口的Weblogic实现类，然后创建一个Home接口的Weblogic实现类的stub类的对象实例，将它序列化传送给客户端（注意stub类的实例是在第1次RMI循环中，由服务器动态发送给客户端的，因此不需要客户端保存Home接口的Weblogic实现类的stub类），最后客户端获得该stub类的对象实例（普通的RMI需要在客户端保存stub类，而EJB不需要，因为服务器会把stub类的对象实例发送给客户端）。 <BR><BR>客户端拿到服务器给它的Home接口的Weblogic实现类的stub类对象实例以后，调用stub类的create方法，(在代码上就是home.create()，但是后台要做很多事情),于是经过第2次RMI循环，在服务器端，Home接口的Weblogic实现类的skeleton类收到stub类的调用信息后，由它再去调用Home接口的Weblogic实现类的create方法。 <BR><BR>在服务端，Home接口的Weblogic实现类的create方法再去调用Bean类的Weblogic实现类的ejbCreate方法，在服务端创建或者分配一个EJB实例，然后将这个EJB实例的远程接口的Weblogic实现类的stub类对象实例序列化发送给客户端。 <BR><BR>客户端收到remote接口的Weblogic实现类的stub类的对象实例，对该对象实例的方法调用（在客户端代码中实际上就是对remote接口的调用），将传送给服务器端remote接口的Weblogic实现类的skeleton类对象，而skeleton类对象再调用相应的remote接口的Weblogic实现类，然后remote接口的Weblogic实现类再去调用Bean类的Weblogic实现类，如此就完成一次EJB对象的远程调用。 <BR><BR>看了一遍帖子，感觉还是没有说太清楚，既然写了帖子，就想彻底把它说清楚。 <BR><BR>先拿普通RMI来说，有4个class，分别是远程对象，对象的接口，对象的stub类和skeleton类。而对象本身和对象的stub类同时都实现了接口类。而我们在客户端代码调用远程对象的时候，虽然在代码中操纵接口，实质上是在操纵stub类，例如： <BR>接口类：Hello <BR>远程对象：Hello_Server <BR>stub类：Hello_Stub <BR>skeleton类：Hello_Skeleton <BR><BR>客户端代码要这样写： <BR>Hello h = new Hello_Stub(); <BR>h.getString(); <BR><BR>我们不会这些写： <BR>Hello_Stub h = new Hello_Stub(); <BR>h.getString(); <BR><BR>因为使用接口适用性更广，就算更换了接口实现类，也不需要更改代码。因此客户端需要Hello.class和Hello_Stub.class这两个文件。但是对于EJB来说，就不需要Hello_Stub.class，因为服务器会发送给它，但是Hello.class文件客户端是省不了的，必须有。表面上我们的客户端代码在操纵Hello，但别忘记了Hello只是一个接口，抽象的，实质上是在操纵Hello_Stub。 <BR><BR>拿Weblogic上的EJB举例子，10个class分别是： <BR>Bean类：HelloBean （用户编写） <BR>Bean类的Weblogic实现类：HelloBean_Impl （EJBC生成） <BR><BR>Home接口：HelloHome （用户编写） <BR>Home接口的Weblogic实现类 HelloBean_HomeImpl（EJBC生成） <BR>Home接口的Weblogic实现类的stub类 HelloBean_HomeImpl_WLStub（部署的时候动态生成字节码） <BR>Home接口的Weblogic实现类的skeleton类 HelloBean_HomeImpl_WLSkeleton（部署的时候动态生成字节码） <BR><BR>Remote接口： Hello （用户编写） <BR>Remote接口的Weblogic实现类 HelloBean_EOImpl（EJBC生成） <BR>Remote接口的Weblogic实现类的stub类 HelloBean_EOImpl_WLStub（部署的时候动态生成字节码） <BR>Remote接口的Weblogic实现类的skeleton类 HelloBean_EOImpl_WLSkeleton（部署的时候动态生成字节码） <BR><BR>客户端只需要Hello.class和HelloHome.class这两个文件。 <BR><BR>HelloHome home = (Home) PortableRemoteObject.narrow(ctx.lookup("Hello"), HelloHome.class); <BR><BR>这一行代码是从JNDI获得Home接口，但是请记住！接口是抽象的，那么home这个对象到底是什么类的对象实例呢？很简单，用toString()输出看一下就明白了，下面一行是输出结果： <BR>HelloBean_HomeImpl_WLStub@18c458 <BR>这表明home这个通过从服务器的JNDI树上查找获得的对象实际上是HelloBean_HomeImpl_WLStub类的一个实例。 <BR>接下来客户端代码： <BR><BR>Hello h = home.create() <BR><BR>同样Hello只是一个抽象的接口，那么h对象是什么东西呢？打印一下： <BR>HelloBean_EOImpl_WLStub@8fa0d1 <BR>原来是HelloBean_EOImpl_WLStub的一个对象实例。 <BR><BR>用这个例子来简述一遍EJB调用过程： <BR><BR>首先客户端JNDI查询，服务端JNDI树上Hello这个名字实际上绑定的对象是HelloBean_HomeImpl_WLStub，所以服务端将创建HelloBean_HomeImpl_WLStub的一个对象实例，序列化返回给客户端。 <BR><BR>于是客户端得到home对象，表面上是得到HelloHome接口的实例，实际上是进行了一次远程调用得到了HelloBean_HomeImpl_WLStub类的对象实例，别忘记了HelloBean_HomeImpl_WLStub也实现了HelloHome接口。 <BR><BR>然后home.create()实质上就是HelloBean_HomeImpl_WLStub.create()，该方法将发送信息给HelloBean_HomeImpl_WLSkeleton，而HelloBean_HomeImpl_WLSkeleton接受到信息后，再去调用HelloBean_HomeImpl的create方法，至此完成第1次完整的RMI循环。 <BR><BR>注意在这次RMI循环过程中，远程对象是HelloBean_HomeImpl，远程对象的接口是HelloHome，对象的stub是HelloBean_HomeImpl_WLStub，对象的skeleton是HelloBean_HomeImpl_WLSkeleton。 <BR><BR>然后HelloBean_HomeImpl再去调用HelloBean_Impl的ejbCreate方法，而HelloBean_Impl的ejbCreate方法将负责创建或者分配一个Bean实例，并且创建一个HelloBean_EOImpl_WLStub的对象实例。 <BR><BR>这一步比较有趣的是，在前一步RMI循环中，远程对象HelloBean_HomeImpl在客户端有一个代理类HelloBean_HomeImpl_WLStub，但在这一步，HelloBean_HomeImpl自己却充当了HelloBean_Impl的代理类，只不过HelloBean_HomeImpl不在客户端，而是在服务端，因此不进行RMI。 <BR><BR>然后HelloBean_EOImpl_WLStub的对象实例序列化返回给客户端，这一步也很有趣，上次RMI过程，主角是HelloBean_HomeImpl和它的代理类HelloBean_HomeImpl_WLStub，但这这一次换成了HelloBean_EOImpl和它的代理类HelloBean_EOImpl_WLStub来玩了。 <BR><BR><BR>Hello h = home.create();h.helloWorld(); <BR><BR>假设Hello接口有一个helloWorld远程方法，那么表面上是在调用Hello接口的helloWorld方法，实际上是在调用HelloBean_EOImpl_WLStub的helloWorld方法。 <BR><BR>然后HelloBean_EOImpl_WLStub的helloWorld方法将发送信息给服务器上的HelloBean_EOImpl_WLSkeleton，而HelloBean_EOImpl_WLSkeleton收到信息以后，再去调用HelloBean_EOImpl的helloWorld方法。至此，完成第2次完整的RMI循环过程。 <BR><BR>在刚才HelloBean_EOImpl是作为远程对象被调用的，它的代理类是HelloBean_EOImpl_WLStub，但现在HelloBean_EOImpl要作为HelloBean_Impl的代理类了。现在HelloBean_EOImpl去调用HelloBean_Impl的helloWorld方法。注意！HelloBean_Impl继承了HelloBean，而HelloBean中的helloWorld方法是我们亲自编写的代码，现在终于调用到了我们编写的代码了！ <BR><BR>至此，一次EJB调用过程终于完成。在整个过程中，服务端主要要调用的类是HelloBean_Impl， HelloBean_HomeImpl，HelloBean_HomeImpl_WLSkeleton，HelloBean_EOImpl，HelloBean_EOImpl_WLSkeleton。客户端主要调用的类是HelloBean_HomeImpl_WLStub，HelloBean_EOImpl_WLStub，这两个类在客户端代码中并不会直接出现，出现在代码中的类是他们的接口HelloHome和Hello，因此客户端需要这两个接口文件，而Stub是服务器传送给他们的。</SPAN><img src ="http://www.blogjava.net/TrampEagle/aggbug/27366.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-01-10 13:10 <a href="http://www.blogjava.net/TrampEagle/articles/27366.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>