Chinaunix首页 | 论坛 | 博客
  • 博客访问: 16502606
  • 博文数量: 5645
  • 博客积分: 9880
  • 博客等级: 中将
  • 技术积分: 68081
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-28 13:35
文章分类

全部博文(5645)

文章存档

2008年(5645)

我的朋友

分类:

2008-04-28 21:13:43

下载本文示例代码
P> 使用bean的句柄:   句柄是用来引用enterprise bean的另一种方法。句柄相当于bean的一个较长的指针。你可以从remote接口获得句柄。一旦你拥有了句柄,就可以将它写入到文件或其它的持久存贮器里面。便于以后可以重新得到句柄,用它来重新建立enterprise bean的引用。   但是,你只能用remote接口的句柄来重新建立bean的引用。你不能用句柄来创建bean本身。如果另一个进程删除了bean,或者系统崩溃或关闭,删除了bean的实例,则当应用程序试图用句柄重新建立对bean的引用时会抛出异常。   当你不确定bean的实例是否依然存在的时候,你可以不用remote接口的句柄。而是保存bean的home接口的句柄,在以后要用的时候再通过调用create方法或finder方法重新创建bean对象。   在客户创建了bean的实例以后,就能够用getHandle()方法来获得实例的句柄。一旦拥有的句柄,就能够将它写到文件里面去。在以后的时间,客户可以读这个文件,将读出来的对象转化为句柄类型。然后,就可以在句柄上调用的getEJBObject方法来获得bean的引用。最后再将getEJBObject方法返回的值转化为合适的类型。 使用句柄来引用一个Bean Import java.io; Import javax.ejb.Handle; …… Cart cart; …… cart = home.create(cartHolderName,creditcartNumber,expirationDate); //在cart对象上调用getHander方法来获得它的句柄。 CartHander=cart.getHandler(); //将hander写到文件中去。 FileOutputStream f = new FileOutputStream(“carthandle.ser”); ObjectOutputStream o = new ObjectOutputStream(f); o.writeObject(myHandle); o.flush(); o.close(); …… //在以后的某个时间,可以从文件中读出handle FileInputStream fi = new FileInputStream(“carthandle.ser”); ObjectInputSteam oi = new ObjectInputStream(fi); //从文件中读出对象并将它转化为Hander类型。 CartHanle = (Handle)oi.readObject(); Oi.close; …… //使用handle来引用bean的实例 try{ Object ref = context.lookup(“cart”); Cart cart1 = (Cart)javax.rmi.PortableRemoteObject.narrow(ref,Cart.class); …… }catch(RemoteException e){ …… } ……   当用完会话bean的句柄以后,客户将使用javax.ejb.EJBHome.remove(Handle handle)方法来删除句柄。 二、管理事务:   客户程序能够管理它自己的事务,而不是让enterprise bean或者是容器来管理。客户管理自己事务的时,就好象会话bean管理它自己的事务一样。   当客户管理自己的事务的时候,需要自己来描述事务的分界线。这也就是说,它必须明确的开始一个事务和终止(提交或回滚)一个事务。   客户使用javax.transaction.UserTransaction接口来管理它自己的事务。它必须首先用JNDI来获得UserTransaction接口的引用。一旦有了UserTranscation的上下文,就可以用UserTransaction.begin()方法来开始一个事务(后面用UserTranscation.commit()方法提交或Usertransction.rollback()方法回滚这个事务)。这之间客户做有关的查询和更新操作。   如下代码演示了客户如何实现管理它自己的事务。客户管理的属于协议的那部分用粗体显示: 客户管理事务: import javax.naming.initialContext; import javax.transcation.UserTransaction; …… public class clientTransaction{ public static void main(String[] argv){ UserTranscation ut=null; InitialContext initContext = new InitialContext(); …… ut = (UserTransaction)initContext.lookup(“java:comp/UserTranscation”); //开始一个事务 ut.begin(); //做事务工作。 …… ut.commit(); //or ut.rollback(); } } 三、获得enterprise bean的信息:   enterprise bean的信息是一个指向metadata引用。客户使用enterprise bean的home接口的getMetaData()方法能够获得bean的metadata信息。   GetMetaData()方法经常被开发环境和build工具所使用,因为它们需要知道enterprise bean的相关信息,例如哪些链接到一起的bean已经被安装。脚本客户也需要获得bean的metadata信息。   一旦客户重新得到home接口的引用。就能够在home接口上调用getEJBMetaData()方法。然后,客户就可以通过调用EJBMetaData接口上的方法来取得如下信息。   用EJBMetaData.getEJBHome()方法获得bean的EJBHome接口。   用EJBMetaData.getHomeInterfaecClass()方法来获得home接口类的对象。包括其接口,类,域和方法。   用EJBMetaData.getRemoteInterfaceClass()方法来获得remote接口类的对象。包括所有的类信息。   用EJBMetaData.getPrimaryKeyClass()方法来获得bean的主键类对象。   不管是会话bean还是实体bean。可用EJBMetaData.isSession()方法来判断。   用EJBMetaData.isStatelessSession()来判断会话bean是否有状态还是无状态的。 四、JNDI的支持:   EJB规范定义了定位home接口的API。JNDI是在其它的服务(CORBA的命名服务,LDAP/X.500,flat files,目录服务)上面实现的。下图解释了不同的实现选择。典型的,EJB服务提供者选择一个特定的JNDI实现。   这个技术实现了JNDI底层的与客户无关性。客户只需要使用JNDI的API就可以了。 五、EJB到CORBA的映射:   EJB和CORBA之间有许多的联系。有三点很重要:   用ORB实现EJB容器/服务。   将原有系统放到EJB中间层的综合能力。   从非java组件的客户,访问EJB的能力。   EJB规范目前只涉及到这三个方面。   CORBA是实现EJB下层组织的很适合而且很自然的平台。CORBA提供了所有的EJB规范与CORBA核心规范或者与CORBA核心服务之间的相关的东西。 持分布式:CORBA核心和CORBA命名服务 支持事务:CORBA对象的事务服务 支持安全:CORBA的安全规范,包括IIOP-over-SSL   另外:CORBA允许非JAVA组件与应用程序的结合。这些组件可以是原来的系统或程序,将它们插入到不同的客户中去。后端系统能够很容易的用OTS和任何能够与IDL映射的程序设计语言结合在一起。这需要容器提供OTS和IIOP的APIs。   EJB规范允许非JAVA客户访问enterprise bean,也提供了EJB到CORBA的映射。EJB/CORBA映射的目的是:   支持用任何CORBA支持的程序设计语言编写的客户端和基于CORBA的EJB服务上的enterprise bean的结合。   使客户程序在相同的事务处理中与CORBA对象或者enterprise bean相结合。   支持在涉及到不同代理商提供的多个客户端在基于CORBA的EJB服务器上运行时的分布式事务。   映射是基于java-to-IDL映射的。其规范包括了如下几个方面:分布式关系的映射,命名约定的映射,事务处理的映射,安全的映射。下面的部分,我们将解释每一个映射。因为映射用了新的IDL特性,这些特性在OMG的Object-by-Value规范中介绍。与其它语言的结合需要与CORBA2.3ORB规范兼容。 分布式的映射:   enterprise bean有两个可以远程访问的接口:remote接口和home接口。IDL规范中有这样的JAVA/IDL到这些接口的映射。EJB规范中定义的基类也是以同样的方式映射到IDL中的。   例如:让我们看看下面的IDL接口,这是ATM那个例子。是一个enterprise 会话bean。有一个方法在accounts之间转帐。也可以抛出资金不足的异常。通过JAVA/IDL映射其home接口和remote接口。我们得到如下的IDL接口: Module transaction{ Module ejb{ Valuetype InsufficientFundsException: ::java::lang::Exception{}; Exception InsufficientFundsEx{ ::transcation::ejb::InsufficientFundsException value; }; interface Atm: ::javax::ejb::EJBObject{ void transfer(in string arg[], in string arg1, in float arg2) raise(::transaction::ejb::InsufficientFundsEx); }; interface AtmHome: ::javax.:ejb::EJBHome{ ::transaction::ejb::Atm create{} raise(::javax::ejb::CreateEx); }; }; }; 命名映射:   基于CORBA的EJB运行时环境如果要想让所有的CORBA客户都能够访问enterprise bean,就必须使用CORBA命名服务来发布enterprise bean的home接口。运行时能够直接使用CORBA的命名服务,或者通过JNDI及其到CORBA命名服务的标准映射来间接的使用。   JNDI命名用一个字符串表示成如下形式:“directory1/directory2/…/directotyN/objectName”。CORBA的命名服务将名字定义成一系列的名字组件: Typedef string Istring; Struct NameComponet{ Istring id; Istring kind; }; typedef sequence $#@60;NameCompoent$#@62; Name;   每一个由”/”分开的JNDI字符串名字都被映射成一个名字组件。最左边的组件就是CORBA命名服务名字的第一个入口。 JNDI字符串名字与一些命名上下文有关。我们把这样的上下文叫做JNDI根部上下文。JNDI根部上下文相当于CORBA的命名服务的初始化上下文。CORBA命名服务的名字与CORBA的初始化上下文有关。 通过在ORB的虚拟对象上面调用resolv_initial_reference(“NameService”),CORBA应用程序能够得到初始的CORBA命名服务的上下文。CORBA命名服务并没有指定如何组织命名上下文,这样,根上下文的概念就不起作用了。ORB的初始化通过resolve_initial_reference()来决定上下文。 例如:一个C 的客户端能够定位我们的ATM会话bean的home接口。这个ATM bean已经用JNDI字符串“transaction/corbaEjb/atm”注册。首先,我们得到初始的命名上下文。 oject_ptr obj = orb-$#@62;resolve_initial_references(“NameService”); NameContext initialNameContext = NameingContext.narrow(obj); if (initialNameingContext == NULL) { cerr $#@60;$#@60;”Could not initial naming context” $#@60;$#@60;endl; exit(1); } 然后,我们产生了一个CORBA命名服务的名字并且根据上面所说的对它进行初始化。 Name name = new Name(1); name[0].id=”atm”; name[0].kind=””; 现在我们解决了初始化命名服务的名字问题。假定我们成功的进行了初始化,我们也有了enterprise bean名字域上的上下文。我们将CORBA对象范围缩小到所需要的类型,并且,确信这样的缩小是成功的。 Object_ptr obj=initialNamingContext-$#@62;resolve(name); AtmSessionHome_ptr atmSessionHome = AtmSessionHome.narrow(obj); if (atmSessionHome == NULL){ cerr$#@60;$#@60;”Could not narrow to ATMSessionHome” $#@60;$#@60;endl; exit(1); } 事务处理的映射: 基于CORBA的enterprise bean运行时环境需要使CORBA的客户端参加到涉及enterprise bean的事务处理中来,就必须使用CORBA的OTS(Object Transaction Service)来进行事务控制。 当enterprise bean配置好之后,能够根据不同的事务服务方针进行安装。方针是定义在配置描述器中的。 事务性的enterprise bean有如下的定义规则:CORBA客户通过IDL接口产生的stub来调用enterprise bean的remote接口和home接口。如果涉及到事务处理,它使用CORBA OTS提供的接口。 例如:一个C 的客户能够调用ATM会话bean: try{ … //obtain transaction current Object_ptr obj = orb-$#@62;resolve_initial_reference(“Current”); Current current = Current.narrow(obj); if(current==NULL){ cerr$#@60;$#@60;”Could not resolve current ”$#@60;$#@60;endl; exit(1); } //execute transaction try{ current-$#@62;begin(); atmSession-$#@62;transfer(“checking”,”saving”,100.00); current-$#@62;commit(0); }catch(…){ current-$#@62;rollback(); } }catch(…){ …… } 安全的映射: EJB规范的安全方面主要考虑的是控制enterprise bean的访问权限。CORBA规定了一些方法来定义标识符,包括如下的方面: Plain IIOP(简单的IIOP方式):CORBA的主要接口在1998年早期并没有被接受。主要的接口用来确定客户的标识。但是,CORBA安全服务的作者却实现了不同的途径:GIOP。GIOP规范包括了一个叫服务上下文的组件,其实是一个元素为值对的数组。其标识符是CORBA的long型的,值是十进制的序列。服务上下文的入口可以用来标识调用者。 Secure IIOP(可靠的IIOP方式):CORBA的安全规范为身份定义了一个不透明的数据类型。身份的实际类型是由所选择的安全机制所决定的。例如:GSS Kerberos,SPKM,或者CSI-ECMA。 IIOP over SSL:SSL(加密套接字协议层)用X.509来来证明服务器或者是客户的身份。当服务器需要客户的身份验证的时候,服务器使用这个证书作为客户的身份验证。 P> 使用bean的句柄:   句柄是用来引用enterprise bean的另一种方法。句柄相当于bean的一个较长的指针。你可以从remote接口获得句柄。一旦你拥有了句柄,就可以将它写入到文件或其它的持久存贮器里面。便于以后可以重新得到句柄,用它来重新建立enterprise bean的引用。   但是,你只能用remote接口的句柄来重新建立bean的引用。你不能用句柄来创建bean本身。如果另一个进程删除了bean,或者系统崩溃或关闭,删除了bean的实例,则当应用程序试图用句柄重新建立对bean的引用时会抛出异常。   当你不确定bean的实例是否依然存在的时候,你可以不用remote接口的句柄。而是保存bean的home接口的句柄,在以后要用的时候再通过调用create方法或finder方法重新创建bean对象。   在客户创建了bean的实例以后,就能够用getHandle()方法来获得实例的句柄。一旦拥有的句柄,就能够将它写到文件里面去。在以后的时间,客户可以读这个文件,将读出来的对象转化为句柄类型。然后,就可以在句柄上调用的getEJBObject方法来获得bean的引用。最后再将getEJBObject方法返回的值转化为合适的类型。 使用句柄来引用一个Bean Import java.io; Import javax.ejb.Handle; …… Cart cart; …… cart = home.create(cartHolderName,creditcartNumber,expirationDate); //在cart对象上调用getHander方法来获得它的句柄。 CartHander=cart.getHandler(); //将hander写到文件中去。 FileOutputStream f = new FileOutputStream(“carthandle.ser”); ObjectOutputStream o = new ObjectOutputStream(f); o.writeObject(myHandle); o.flush(); o.close(); …… //在以后的某个时间,可以从文件中读出handle FileInputStream fi = new FileInputStream(“carthandle.ser”); ObjectInputSteam oi = new ObjectInputStream(fi); //从文件中读出对象并将它转化为Hander类型。 CartHanle = (Handle)oi.readObject(); Oi.close; …… //使用handle来引用bean的实例 try{ Object ref = context.lookup(“cart”); Cart cart1 = (Cart)javax.rmi.PortableRemoteObject.narrow(ref,Cart.class); …… }catch(RemoteException e){ …… } ……   当用完会话bean的句柄以后,客户将使用javax.ejb.EJBHome.remove(Handle handle)方法来删除句柄。 二、管理事务:   客户程序能够管理它自己的事务,而不是让enterprise bean或者是容器来管理。客户管理自己事务的时,就好象会话bean管理它自己的事务一样。   当客户管理自己的事务的时候,需要自己来描述事务的分界线。这也就是说,它必须明确的开始一个事务和终止(提交或回滚)一个事务。   客户使用javax.transaction.UserTransaction接口来管理它自己的事务。它必须首先用JNDI来获得UserTransaction接口的引用。一旦有了UserTranscation的上下文,就可以用UserTransaction.begin()方法来开始一个事务(后面用UserTranscation.commit()方法提交或Usertransction.rollback()方法回滚这个事务)。这之间客户做有关的查询和更新操作。   如下代码演示了客户如何实现管理它自己的事务。客户管理的属于协议的那部分用粗体显示: 客户管理事务: import javax.naming.initialContext; import javax.transcation.UserTransaction; …… public class clientTransaction{ public static void main(String[] argv){ UserTranscation ut=null; InitialContext initContext = new InitialContext(); …… ut = (UserTransaction)initContext.lookup(“java:comp/UserTranscation”); //开始一个事务 ut.begin(); //做事务工作。 …… ut.commit(); //or ut.rollback(); } } 三、获得enterprise bean的信息:   enterprise bean的信息是一个指向metadata引用。客户使用enterprise bean的home接口的getMetaData()方法能够获得bean的metadata信息。   GetMetaData()方法经常被开发环境和build工具所使用,因为它们需要知道enterprise bean的相关信息,例如哪些链接到一起的bean已经被安装。脚本客户也需要获得bean的metadata信息。   一旦客户重新得到home接口的引用。就能够在home接口上调用getEJBMetaData()方法。然后,客户就可以通过调用EJBMetaData接口上的方法来取得如下信息。   用EJBMetaData.getEJBHome()方法获得bean的EJBHome接口。   用EJBMetaData.getHomeInterfaecClass()方法来获得home接口类的对象。包括其接口,类,域和方法。   用EJBMetaData.getRemoteInterfaceClass()方法来获得remote接口类的对象。包括所有的类信息。   用EJBMetaData.getPrimaryKeyClass()方法来获得bean的主键类对象。   不管是会话bean还是实体bean。可用EJBMetaData.isSession()方法来判断。   用EJBMetaData.isStatelessSession()来判断会话bean是否有状态还是无状态的。 四、JNDI的支持:   EJB规范定义了定位home接口的API。JNDI是在其它的服务(CORBA的命名服务,LDAP/X.500,flat files,目录服务)上面实现的。下图解释了不同的实现选择。典型的,EJB服务提供者选择一个特定的JNDI实现。   这个技术实现了JNDI底层的与客户无关性。客户只需要使用JNDI的API就可以了。 五、EJB到CORBA的映射:   EJB和CORBA之间有许多的联系。有三点很重要:   用ORB实现EJB容器/服务。   将原有系统放到EJB中间层的综合能力。   从非java组件的客户,访问EJB的能力。   EJB规范目前只涉及到这三个方面。   CORBA是实现EJB下层组织的很适合而且很自然的平台。CORBA提供了所有的EJB规范与CORBA核心规范或者与CORBA核心服务之间的相关的东西。 持分布式:CORBA核心和CORBA命名服务 支持事务:CORBA对象的事务服务 支持安全:CORBA的安全规范,包括IIOP-over-SSL   另外:CORBA允许非JAVA组件与应用程序的结合。这些组件可以是原来的系统或程序,将它们插入到不同的客户中去。后端系统能够很容易的用OTS和任何能够与IDL映射的程序设计语言结合在一起。这需要容器提供OTS和IIOP的APIs。   EJB规范允许非JAVA客户访问enterprise bean,也提供了EJB到CORBA的映射。EJB/CORBA映射的目的是:   支持用任何CORBA支持的程序设计语言编写的客户端和基于CORBA的EJB服务上的enterprise bean的结合。   使客户程序在相同的事务处理中与CORBA对象或者enterprise bean相结合。   支持在涉及到不同代理商提供的多个客户端在基于CORBA的EJB服务器上运行时的分布式事务。   映射是基于java-to-IDL映射的。其规范包括了如下几个方面:分布式关系的映射,命名约定的映射,事务处理的映射,安全的映射。下面的部分,我们将解释每一个映射。因为映射用了新的IDL特性,这些特性在OMG的Object-by-Value规范中介绍。与其它语言的结合需要与CORBA2.3ORB规范兼容。 分布式的映射:   enterprise bean有两个可以远程访问的接口:remote接口和home接口。IDL规范中有这样的JAVA/IDL到这些接口的映射。EJB规范中定义的基类也是以同样的方式映射到IDL中的。   例如:让我们看看下面的IDL接口,这是ATM那个例子。是一个enterprise 会话bean。有一个方法在accounts之间转帐。也可以抛出资金不足的异常。通过JAVA/IDL映射其home接口和remote接口。我们得到如下的IDL接口: Module transaction{ Module ejb{ Valuetype InsufficientFundsException: ::java::lang::Exception{}; Exception InsufficientFundsEx{ ::transcation::ejb::InsufficientFundsException value; }; interface Atm: ::javax::ejb::EJBObject{ void transfer(in string arg[], in string arg1, in float arg2) raise(::transaction::ejb::InsufficientFundsEx); }; interface AtmHome: ::javax.:ejb::EJBHome{ ::transaction::ejb::Atm create{} raise(::javax::ejb::CreateEx); }; }; }; 命名映射:   基于CORBA的EJB运行时环境如果要想让所有的CORBA客户都能够访问enterprise bean,就必须使用CORBA命名服务来发布enterprise bean的home接口。运行时能够直接使用CORBA的命名服务,或者通过JNDI及其到CORBA命名服务的标准映射来间接的使用。   JNDI命名用一个字符串表示成如下形式:“directory1/directory2/…/directotyN/objectName”。CORBA的命名服务将名字定义成一系列的名字组件: Typedef string Istring; Struct NameComponet{ Istring id; Istring kind; }; typedef sequence $#@60;NameCompoent$#@62; Name;   每一个由”/”分开的JNDI字符串名字都被映射成一个名字组件。最左边的组件就是CORBA命名服务名字的第一个入口。 JNDI字符串名字与一些命名上下文有关。我们把这样的上下文叫做JNDI根部上下文。JNDI根部上下文相当于CORBA的命名服务的初始化上下文。CORBA命名服务的名字与CORBA的初始化上下文有关。 通过在ORB的虚拟对象上面调用resolv_initial_reference(“NameService”),CORBA应用程序能够得到初始的CORBA命名服务的上下文。CORBA命名服务并没有指定如何组织命名上下文,这样,根上下文的概念就不起作用了。ORB的初始化通过resolve_initial_reference()来决定上下文。 例如:一个C 的客户端能够定位我们的ATM会话bean的home接口。这个ATM bean已经用JNDI字符串“transaction/corbaEjb/atm”注册。首先,我们得到初始的命名上下文。 oject_ptr obj = orb-$#@62;resolve_initial_references(“NameService”); NameContext initialNameContext = NameingContext.narrow(obj); if (initialNameingContext == NULL) { cerr $#@60;$#@60;”Could not initial naming context” $#@60;$#@60;endl; exit(1); } 然后,我们产生了一个CORBA命名服务的名字并且根据上面所说的对它进行初始化。 Name name = new Name(1); name[0].id=”atm”; name[0].kind=””; 现在我们解决了初始化命名服务的名字问题。假定我们成功的进行了初始化,我们也有了enterprise bean名字域上的上下文。我们将CORBA对象范围缩小到所需要的类型,并且,确信这样的缩小是成功的。 Object_ptr obj=initialNamingContext-$#@62;resolve(name); AtmSessionHome_ptr atmSessionHome = AtmSessionHome.narrow(obj); if (atmSessionHome == NULL){ cerr$#@60;$#@60;”Could not narrow to ATMSessionHome” $#@60;$#@60;endl; exit(1); } 事务处理的映射: 基于CORBA的enterprise bean运行时环境需要使CORBA的客户端参加到涉及enterprise bean的事务处理中来,就必须使用CORBA的OTS(Object Transaction Service)来进行事务控制。 当enterprise bean配置好之后,能够根据不同的事务服务方针进行安装。方针是定义在配置描述器中的。 事务性的enterprise bean有如下的定义规则:CORBA客户通过IDL接口产生的stub来调用enterprise bean的remote接口和home接口。如果涉及到事务处理,它使用CORBA OTS提供的接口。 例如:一个C 的客户能够调用ATM会话bean: try{ … //obtain transaction current Object_ptr obj = orb-$#@62;resolve_initial_reference(“Current”); Current current = Current.narrow(obj); if(current==NULL){ cerr$#@60;$#@60;”Could not resolve current ”$#@60;$#@60;endl; exit(1); } //execute transaction try{ current-$#@62;begin(); atmSession-$#@62;transfer(“checking”,”saving”,100.00); current-$#@62;commit(0); }catch(…){ current-$#@62;rollback(); } }catch(…){ …… } 安全的映射: EJB规范的安全方面主要考虑的是控制enterprise bean的访问权限。CORBA规定了一些方法来定义标识符,包括如下的方面: Plain IIOP(简单的IIOP方式):CORBA的主要接口在1998年早期并没有被接受。主要的接口用来确定客户的标识。但是,CORBA安全服务的作者却实现了不同的途径:GIOP。GIOP规范包括了一个叫服务上下文的组件,其实是一个元素为值对的数组。其标识符是CORBA的long型的,值是十进制的序列。服务上下文的入口可以用来标识调用者。 Secure IIOP(可靠的IIOP方式):CORBA的安全规范为身份定义了一个不透明的数据类型。身份的实际类型是由所选择的安全机制所决定的。例如:GSS Kerberos,SPKM,或者CSI-ECMA。 IIOP over SSL:SSL(加密套接字协议层)用X.509来来证明服务器或者是客户的身份。当服务器需要客户的身份验证的时候,服务器使用这个证书作为客户的身份验证。 下载本文示例代码


编写Enterprise bean的客户端(下)编写Enterprise bean的客户端(下)编写Enterprise bean的客户端(下)编写Enterprise bean的客户端(下)编写Enterprise bean的客户端(下)编写Enterprise bean的客户端(下)编写Enterprise bean的客户端(下)编写Enterprise bean的客户端(下)编写Enterprise bean的客户端(下)编写Enterprise bean的客户端(下)编写Enterprise bean的客户端(下)编写Enterprise bean的客户端(下)编写Enterprise bean的客户端(下)编写Enterprise bean的客户端(下)编写Enterprise bean的客户端(下)
阅读(83) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~