`

CORBA与RMI的比较 及 实例

    博客分类:
  • rmi
阅读更多

Java远程方法调用(RMI)机制和公用对象请求代理体系(CORBA)是最重要和使用最广泛的两种分布式对象系统。每个系统都有其特点和短处。它们在行业中被用于从电子交易到保健医疗的各个领域。一个项目如果要从这两种分布式机制中选用一个,往往难以抉择。本文概括地介绍了RMICORBA,更重要的是,它将介绍如何开发一个有用的应用程序,用于从远程主机下载文件。然后它将:

  • 简要介绍分布式对象系统
  • 简要介绍RMICORBA
  • 让你对在RMICORBA中开发应用程序所涉及的工作有个初步印象
  • 演示如何使用RMICORBA,从远程主机传送文件
  • RMICORBA进行简单比较

客户机/服务器模型

客户机/服务器模型是分布式计算的一种形式,在这种形式中,一个程序(客户机)与另一个程序(服务器)通讯以便交换信息。在这种模型中,客户机和服务器通常都说同样的语言--也就是说客户机和服务器能理解同一个协议--这样它们才能通讯。

虽然客户机/服务器模型的实现方式多种多样,但典型做法是使用底层套接字。使用套接字开发客户机/服务器系统意味着,我们必须设计一个协议,也就是客户机和服务器都认识的一组命令集,通过这些命令它们就能通讯了。举例来说, HTTP协议中提供了一个名为GET的方法,所有Web服务器都必须实现这个方法,所Web客户机(浏览器)都必须使用这个方法,才能获取文档。

分布式对象模型

基于分布式对象的系统是一组对象的集合,这些对象以一种明确定义封装的接口把服务的请求者(客户机)和服务的提供者(服务器)分隔开。换言之,客户机从服务的实现中分离出来,变成数据的呈现和可执行代码。这就是基于分布式对象的模型与纯粹的客户机/服务器模型的主要区别之一。

在基于分布式对象的模型中,客户机向对象发送消息,然后对象解释该消息以便决定要执行什么服务。这项服务,也就是方法,可以选择是让对象还是让代理来执行。Java远程方法调用(RMI)和公用对象请求代理体系(CORBA)就是这种模型的例子。

RMI

RMI是一个分布式对象系统,它使你能够轻松地开发出分布式Java应用程序。RMI中开发分布式应用程序比用套接字开发要简单,因为不需要做设计协议这种很容易出错的工作。在RMI中,开发者会有一种错觉,似乎是从本地类文件调用的本地方法,其实参数传送给了远程目标,目标解释参数后再把结果发回给调用方。

RMI应用程序初步

使用RMI开发分布式应用程序包括以下步骤:

  1. 定义一个远程接口
  2. 实现这个远程接口
  3. 开发服务器
  4. 开发客户机
  5. 生成存根和基干,启动RMI注册表、服务器和客户机

下面我们将通过开发一个文件传输程序来实践这些步骤。

范例:文件传输程序

这个应用程序允许客户机从远程主机上传送(即下载)任何类型的文件(纯文本或二进制文件)。第一步是定义一个远程接口,这个接口规定了服务器所提供方法的信号,客户机将调用这些方法。

定义一个远程接口

用于文件下载应用程序的远程接口如代码范例1所示。接口 FileInterface提供了一个方法downloadFile,这个方法接受String参数(文件名),将文件的数据以字节数组的形式返回。

代码范例1 1: FileInterface.java

import java.rmi.Remote;

import java.rmi.RemoteException;

public interface FileInterface extends Remote {

public byte[] downloadFile(String fileName) throws

RemoteException;

}

请注意FileInterface的以下特征:

  • 它必须声明为public,这样客户机才能加载实现远程接口的远程对象。
  • 它必须扩展为Remote接口,以满足使该对象成为远程对象的要求。
  • 这个接口中的每种方法都必须投出一个java.rmi.RemoteException

实现远程接口

下一步是实现接口FileInterface。实现的范例见代码范例2请注意,除了实现FileInterface之外,还把FileImpl 类扩展为UnicastRemoteObject。这表示FileImpl将用于创建一个单独的、不可复制的远程对象,它使用RMI缺省的基于TCP的传送通道进行通讯。

代码范例2: FileImpl.java

import java.io.*;

import java.rmi.*;

import java.rmi.server.UnicastRemoteObject;

public class FileImpl extends UnicastRemoteObject

implements FileInterface {

private String name;

public FileImpl(String s) throws RemoteException{

super();

name = s;

}

public byte[] downloadFile(String fileName){

try {

File file = new File(fileName);

byte buffer[] = new byte[(int)file.length()];

BufferedInputStream input = new

BufferedInputStream(new FileInputStream(fileName));

input.read(buffer,0,buffer.length);

input.close();

return(buffer);

} catch(Exception e){

System.out.println("FileImpl: "+e.getMessage());

e.printStackTrace();

return(null);

}

}

}

开发服务器

第三个步骤是开发服务器。服务器需要做三件事:

  1. 创建RMISecurityManager的一个实例并安装它
  2. 创建远程对象(在本例中是FileImpl)的一个实例
  3. RMI注册表中登记这个创建的对象。实现的范例见代码范例3

代码范例 3: FileServer.java

import java.io.*;

import java.rmi.*;

public class FileServer {

public static void main(String argv[]) {

if(System.getSecurityManager() == null) {

System.setSecurityManager(new RMISecurityManager());

}

try {

FileInterface fi = new FileImpl("FileServer");

Naming.rebind("//127.0.0.1/FileServer", fi);

} catch(Exception e) {

System.out.println("FileServer: "+e.getMessage());

e.printStackTrace();

}

}

}

语句Naming.rebind("//127.0.0.1/FileServer", fi)假定RMI 注册表在缺省的端口号1099上运行。

但是,如果RMI注册表在其他端口号上运行, 就必须在这一句中指定端口号。例如,如果RMI注册表在端口4500

上运行,那么 这一句就变成:

Naming.rebind("//127.0.0.1:4500/FileServer", fi)

另外,在这里要着重指出,我们假定rmi注册表和服务器是在同一台电脑上运行。如果不是这样,只需修改rebind方法中的地址即可。

开发客户机

下一步是开发客户机。客户机可以远程调用远程接口FileInterface)中指定的任何方法。但是为了能这么做,客户机首先必须从RMI注册表中获得指向该远程对象的引用。获得引用之后就可以调downloadFile方法了。客户机的实现请见代码范例4。在这个实现中,客户机从命令行接收两个参数:

第一个参数是要下载文件的名称,第二个参数是要下载的文件所在主机的地址,也就是运行文件服务器的那台电脑的地址。

代码范例4: FileClient.java

import java.io.*;

import java.rmi.*;

public class FileClient{

public static void main(String argv[]) {

if(argv.length != 2) {

System.out.println("Usage: java FileClient fileName machineName");

System.exit(0);

}

try {

String name = "//" + argv[1] + "/FileServer";

FileInterface fi = (FileInterface) Naming.lookup(name);

byte[] filedata = fi.downloadFile(argv[0]);

File file = new File(argv[0]);

BufferedOutputStream output = new

BufferedOutputStream(new FileOutputStream(file.getName()));

output.write(filedata,0,filedata.length);

output.flush();

output.close();

} catch(Exception e) {

System.err.println("FileServer exception: "+ e.getMessage());

e.printStackTrace();

}

}

}

运行应用程序

为了运行应用程序,我们需要生成存根和基干,编译服务器和客户机,启动 RMI注册表,最后是启动服务器和客户机。

为了生成存根和基干,请使用rmic编译器:

prompt> rmic FileImpl

这将生成两个文件:FileImpl_Stub.class FileImpl_Skel.class。存根是一个客户机代理,基干是一个服务器基干。

下一步是编译服务器和客户机。用javac编译器来做这件事。但是请注意:如果服务器和客户机是在两台不同的机器上开发的,为了编译客户机,需要把接口FileInterface)复制一份。

最后,启动RMI注册表并运行服务器和客户机。为了在缺省的端口号上启动 RMI注册表,请在Windows中使用命令rmiregistry start rmiregistry。为了在其他端口号上启动RMI注册表,可以提供该端口号作为RMI注册表的一个参数:

prompt> rmiregistry portNumber

运行RMI注册表之后,就可以启动服务器FileServer了。但是,因为在服务器应用程序中正在使用RMI安全管理员,所以需要一个安全方针来与之相配。下面是一个安全方针范例:

grant {

permission java.security.AllPermission "", "";

};

注意: 这只是一个方针的例子。它允许任何人做任何事情。对于关键性事务应用程序,你需要指定更严格的安全方针。

现在,为了启动服务器,需要把除了客户机类FileClient.class)之外的所有类(包括存根和基干)复制一份。请使用以下命令启动服务器,假定安全方针位于文件policy.txt中:

prompt> java -Djava.security.policy=policy.txt FileServer

为了在另一台机器上启动客户机,需要复制远程接口FileInterface.class)和存根FileImpl_Stub.class)。请使用以下命令启动客户机:

prompt> java FileClient fileName machineName

其中fileNamefileName是要下载的文件,machineName 是该文件所在的机器(运行文件服务器的那台机器)。如果一切顺利,那么客户机就存在了,下载完的文件保存在本地的机器上。


要运行前面介绍的客户机,需要复制接口和存根。更适当的方法是使用RMI动态类加载。这种做法不需要复制接口和存根。取而代之的做法是,可以把接口和存根放在共享的目录里供服务器和客户机使用,在需要存根或者基干的时候,RMI类加载器就会自动下载它。举例来说,用以下命令运行客户机: java -Djava.rmi.server.codebase=http://hostname/locationOfClasses FileClient fileName machineName有关这种方法的更多信息,请参见使用 RMI加载动态代码。


CORBA

公用对象请求代理体系(即CORBA)是由对象管理组织(OMG)开发的一项工业标准,用于帮助分布式对象编程。要注意的重要一点是,CORBA只是一项规范。 CORBA的实现称为ORB(对象请求代理)。从市场上可以找到几个CORBA的实现,比如VisiBrokerORBIX,等等。JavaIDL是另一个实现,它是JDK1.3或更高版本的核心软件包之一。

CORBA被设计成与平台和语言无关。因此,CORBA对象可以运行于任何平台之上,位于网络的任何位置,还可以用任何语言编写,只要该语言具有Interface Definition LanguageIDL,接口定义语言)的映射。

RMI类似,CORBA对象是用接口规定的。但是CORBA中的接口在IDL中指定。虽然IDLC++相似,但请注意,IDL并不是一种编程语言。有关CORBA的详细介绍,请参见用 Java进行分布式编程:11章(CORBA概述)

CORBA应用程序初步

开发CORBA应用程序包括许多步骤。它们是:

1.    IDL中定义一个接口

2.    IDL接口映射到Java中(自动完成)

3.    实现这个接口

4.    开发服务器

5.    开发客户机

6.    运行命名服务、服务器和客户机。

我们现在要开发一个基于CORBA的文件传送程序,以此来解释各个步骤,这个程序类似于本文前面开发的那个RMI应用程序。在这里将使用JavaIDL,它是 JDK1.3+的核心软件包之一。

定义接口

在定义CORBA接口时,请考虑服务器将支持的操作类型。在文件传输应用程序中,客户机将调用一个方法来下载文件。代码范例5显示了FileInterface 的接口。Data是使用typedef关键字引入的新类型。 IDL中的sequence类似于数组,区别在于序列没有固定的大小。 octet是一个8-bit数,等价于Java中的类型byte

请注意,downloadFile方法接收一个类型为string ,声明为in的参数。IDL定义了三种参数传送模式:in (从客户机输入到服务器),out(从服务器输出到客户机), inout(输入输出都可用)。

代码范例 5: FileInterface.idl

interface FileInterface {

typedef sequence<octet> Data;

Data downloadFile(in string fileName);

};

定义好IDL接口之后,就可以编译它了。JDK 1.3+附带了idlj 编译器,用于把IDL定义映射为Java的声明和语句。

idlj编译器可以通过选项来指定是生成客户机存根、服务器基干,还是二者都生成。-f选项用于指定要生成什么。 side可以是client, server或者 all,用于指定客户机存根和服务器基干。在这个例子中,因为应用程序将在两台单独的机器上运行,所以在服务器端使用-fserver 选项,而在客户机端使用-fclient选项。

现在编译FileInterface.idl,生成服务器端基干。请使用命令:

prompt> idlj -fserver FileInterface.idl

这条命令将产生几个文件,比如基干,持有者和辅助器类,等等。其中生成的一个重要文件是_FileInterfaceImplBase,它是实现接口的类的子类。

实现接口

下面我们提供了downloadFile方法的一个实现。这个实现称为仆人,正如你从代码范例6中看到的那样,类FileServant扩展了 _FileInterfaceImplBase类,以便把这个仆人指定为一个CORBA 对象。

代码范例 6: FileServant.java

import java.io.*;

 

public class FileServant extends _FileInterfaceImplBase {

public byte[] downloadFile(String fileName){

File file = new File(fileName);

byte buffer[] = new byte[(int)file.length()];

try {

BufferedInputStream input = new

BufferedInputStream(new FileInputStream(fileName));

input.read(buffer,0,buffer.length);

input.close();

} catch(Exception e) {

System.out.println("FileServant Error: "+e.getMessage());

e.printStackTrace();

}

return(buffer);

}

}

开发服务器

下一步是开发CORBA服务器。代码范例7中的FileServer类实现了一个CORBA服务器,它做了这么一些事情:

1.    初始化ORB

2.    创建一个FileServant对象

3.    CORBA命名服务(COS命名)中登记该对象

4.    输出一条状态消息

5.    等待客户机的请求到来

代码范例 7: FileServer.java

import java.io.*;

import org.omg.CosNaming.*;

import org.omg.CosNaming.NamingContextPackage.*;

import org.omg.CORBA.*;

public class FileServer {

public static void main(String args[]) {

try{

// create and initialize the ORB

ORB orb = ORB.init(args, null);

// create the servant and register it with the ORB

FileServant fileRef = new FileServant();

orb.connect(fileRef);

// get the root naming context

org.omg.CORBA.Object objRef =

orb.resolve_initial_references("NameService");

NamingContext ncRef = NamingContextHelper.narrow(objRef);

// Bind the object reference in naming

NameComponent nc = new NameComponent("FileTransfer", " ");

NameComponent path[] = {nc};

ncRef.rebind(path, fileRef);

System.out.println("Server started....");

// Wait for invocations from clients

java.lang.Object sync = new java.lang.Object();

synchronized(sync){

sync.wait();

}

} catch(Exception e) {

System.err.println("ERROR: " + e.getMessage());

e.printStackTrace(System.out);

}

}

}

FileServer有了一个ORB之后,就可以注册CORBA服务。它使用 COS命名服务进行注册,该服务由OMG制订,

Java IDL实现。从获取指向命名服务根的引用开始。这将返回一个普通CORBA对象。为了把这个对象用作一个

NamingContext对象,必须把它缩短(也就是强制转换)为适当类型,用下列语句实现:

NamingContext ncRef = NamingContextHelper.narrow(objRef);

ncRef对象现在变成了 org.omg.CosNaming.NamingContext你可以使用rebind 方法,用这个对象在命名服务中注册一项CORBA服务。

开发客户机

下一步是开发客户机。代码范例8中演示了一个实现。获得指向命名服务的引用之后,就可以用它来访问命名服务和查找其他服务(例如FileTransferFileTransfer服务时,将调用downloadFile 方法。

代码范例 8: FileClient

import java.io.*;

import java.util.*;

import org.omg.CosNaming.*;

import org.omg.CORBA.*;

public class FileClient {

public static void main(String argv[]) {

try {

// create and initialize the ORB

ORB orb = ORB.init(argv, null);

// get the root naming context

org.omg.CORBA.Object objRef =

orb.resolve_initial_references("NameService");

NamingContext ncRef = NamingContextHelper.narrow(objRef);

NameComponent nc = new NameComponent("FileTransfer", " ");     

// Resolve the object reference in naming

NameComponent path[] = {nc};

FileInterfaceOperations fileRef =

FileInterfaceHelper.narrow(ncRef.resolve(path));

if(argv.length < 1) {

System.out.println("Usage: java FileClient filename");

}

// save the file

File file = new File(argv[0]);

byte data[] = fileRef.downloadFile(argv[0]);

BufferedOutputStream output = new

BufferedOutputStream(new FileOutputStream(argv[0]));

output.write(data, 0, data.length);

output.flush();

output.close();

} catch(Exception e) {

System.out.println("FileClient Error: " + e.getMessage());

e.printStackTrace();

}

}

}

运行应用程序

最后一步是运行应用程序。这其中包括几个子步骤:

1.    运行CORBA命名服务。这可以使用命令tnameserv缺省情况下,该服务在端口900上运行。如果不能在这个端口运行命名服务,你可以在其他端口上启动它。例如,要在端口2500上启动命名服务,请使用以下命令:

prompt> tnameserv -ORBinitialPort 2500

 

2.    启动服务器。如下所示,假定命名服务是在缺省的端口号上运行:

prompt> java FileServer

如果命名服务运行于其他端口之上,比如2500,则需要使用 ORBInitialPort选项来指定端口,如下所示:

prompt> java FileServer -ORBInitialPort 2500

3.    生成用于客户机的存根。在可以运行客户机之前,先要生成客户机的存根。为此需要复制FileInterface.idl文件,并使用idlj译器来编译它,在编译前指定希望生成的结果是客户机端存根,如下所示:

prompt> idlj -fclient FileInterface.idl

 

4.    运行客户机假定命名服务在端口2500上运行,那么现在就可以使用以下命令来运行客户机了。 

prompt> java FileClient hello.txt -ORBInitialPort 2500 

其中hello.txt是我们要从服务器下载的文件。


注意: 如果要在另一台主机上运行命名服务,请使用 -ORBInitialHost/CODE>选项,指定它在哪台主机上运行。例如,如果 要在名为gosling的主机的端口号4500上运行命名服务,则使用 以下命令启动客户机:

prompt> java FileClient hello.txt -ORBInitialHost gosling -ORBInitialPort 4500


另一种做法是,在代码级使用属性指定这些选项。所以除了像下面这样初始化 ORB

ORB orb = ORB.init(argv, null);

还可以通过指定CORBA服务器所在机器(名为gosling)和命名服务的端口号( 2500)来进行初始化,如下所示:

 

Properties props = new Properties();

props.put("org.omg.CORBA.ORBInitialHost", "gosling"); 

props.put("orb.omg.CORBA.ORBInitialPort", "2500"); 

ORB orb = ORB.init(args, props); 

练习

在文件传输应用程序中,客户机必须预先知道要下载的文件的名称(RMI CORBA中都是如此)。可是并未提供列出服务器上可用文件的方法。作为练习,你也许希望改进这个应用程序,添加一个列出服务器上可用文件的方法。另外,你可能不想使用命令行客户机,而开发一个基于GUI的客户机。在客户机启动时,它调用服务器上的一个方法,获得文件列表,然后弹出一个菜单,显示可用的文件,用户可以从中选择一个或多个要下载的文件,如图1所示。

 

CORBARMI的比较

从编码的角度看,很明显RMI更易于使用,因为Java开发者不需要熟悉接口定义语言(IDL)。但是总的说来,CORBA在以下方面与RMI有所不同:

·         CORBA接口用IDL定义,RMI接口用Java定义。RMI-IIOP允许你用Java定义所有接口(请参见 RMI-IIOP)。

·         CORBA支持inout参数,而RMI不支持,因为本地对象是通过复制传送的,远程对象是通过引用传送的。

·         CORBA被特意设计成与语言不相关。举例来说,这意味着可以用Java编写一些对象,用C++编写其他对象,而它们仍然可以协同工作。所以,作为不同编程语言间的桥梁,CORBA是一种理想机制。与此不同,RMI为一种单独的语言设计,所有对象都可用Java编写。但是请注意,用RMI-IIOP有可能达到协同工作的能力。

·         CORBA对象不能进行碎片收集。正如我们前面说的,CORBA与语言无关,某些语言(比如C++)不支持碎片收集。可以认为这是项缺点,因为CORBA对象一旦创建,就一直存在,直至被除去为止,而决定何时除去一个对象的工作量可不小。与此相反,RMI对象会自动收集碎片。

结论

开发基于分布式对象的应用程序可以在Java中用RMIJavaIDLCORBA的一个实现)完成。这两种技术的用法类似,第一步都是定义对象的接口。但是与RMI Java定义接口不同,CORBA接口是用接口定义语言(IDL)定义的。可是这就多了一层复杂度,开发者需要熟悉IDL,同样重要的是,还要熟悉它到Java的映射。

在这两种分布式机制中如何选择,取决于当前项目及其需求。我希望此文能为你开发基于分布式对象的应用程序提供足够的信息,为帮助你选择分布式机制提供足够的指导。

 

分享到:
评论

相关推荐

    Java中的EJB编程实例代码

    内容有:简单的EJB、无状态SessionBean、有状态SessionBean、BMP位图实例、cmp实例、Message-Driven Bean、JNDI的使用、112各种EJB之间的调用、B-S结构EJB、 C-S结构EJB、UML建模与J2EE开发、RMI and RMI-...

    Java中Enterprise JavaBeans(EJB)编程实例代码.rar

    内容有:简单的EJB、无状态SessionBean、有状态SessionBean、BMP位图实例、cmp实例、Message-Driven Bean、JNDI的使用、112各种EJB之间的调用、B-S结构EJB、 C-S结构EJB、UML建模与J2EE开发、RMI and RMI-...

    h_JAVA 2应用编程150例.rar

    实例121 EJB与CORBA的交互 430 实例122 基于EJB的真实世界模型 433 实例123 EJB的商业应用——定购单 447 第11章 Java 2 Platform Micro Edition编程 475 实例124 插入和替换表单元素 476 实例125 使用线程与定时 ...

    J2EE专业项目实例开发(2)

    本书是学习J2EE编程的优秀参考书,主要包括以下内容:第一部分概述了有关J2EE编程的重要概念,如applet的创建、布局管理器和事件处理、异常处理和线程、存储数据和创建网络应用程序、RMI和CORBA;第二部分介绍J2EE的...

    J2EE专业项目实例开发(3)

    本书是学习J2EE编程的优秀参考书,主要包括以下内容:第一部分概述了有关J2EE编程的重要概念,如applet的创建、布局管理器和事件处理、异常处理和线程、存储数据和创建网络应用程序、RMI和CORBA;第二部分介绍J2EE的...

    J2EE专业项目实例开发(1)

    本书是学习J2EE编程的优秀参考书,主要包括以下内容:第一部分概述了有关J2EE编程的重要概念,如applet的创建、布局管理器和事件处理、异常处理和线程、存储数据和创建网络应用程序、RMI和CORBA;第二部分介绍J2EE的...

    J2EE专业项目实例开发(4)

    本书是学习J2EE编程的优秀参考书,主要包括以下内容:第一部分概述了有关J2EE编程的重要概念,如applet的创建、布局管理器和事件处理、异常处理和线程、存储数据和创建网络应用程序、RMI和CORBA;第二部分介绍J2EE的...

    J2EE应用开发详解

    236 第14章 CORBA 237 14.1 CORBA的需求 237 14.2 CORBA的架构 237 14.2.1 IDL 239 14.2.2 ORB 240 14.2.3 IIOP 241 14.2.4 BOA 241 14.3 CORBA服务 241 14.4 创建CORBA应用 243 14.5 CORBA与RMI 246 14.5.1 CORBA和...

    java应用软件程序设计

    405 实例115 与时间有关的函数 407 实例116 EJB与UML的对应关系 412 实例117 C/S结构的RMI-IIOP应用 414 实例118 使用JTA与JTS 417 实例119 Request-Reply模式的JMS应用 421 实例120 使用Java IDL...

    java网络编程_part2

    数据报通信、对象的序列化与反序列化、Java反射机制、RMI框架、JDBC API、JavaMail API、MVC设计模式、安全网络通信、CORBA和Web服务。另 外,本书还涵盖了Sun公司的SCJD(Sun Certified Java Developer)认证

    java高手真经 光盘源码

    javarmi.zip 24.RMI编程(HelloWorld例、计算器实例) javacorba.zip 25.Corba编程(HelloWorld例、计算器实例) 第6部分(4个程序包) javareflection.zip 26.Java反射机制与动态代理 javageneric.zip 27.Java...

    Java高手真经(编程基础卷)光盘全部源码 免积分

    javarmi.zip 24.RMI编程(HelloWorld例、计算器实例) javacorba.zip 25.Corba编程(HelloWorld例、计算器实例) 第6部分(4个程序包) javareflection.zip 26.Java反射机制与动态代理 javageneric.zip 27.Java...

    Java高手真经(编程基础卷)光盘全部源码

    javarmi.zip 24.RMI编程(HelloWorld例、计算器实例) javacorba.zip 25.Corba编程(HelloWorld例、计算器实例) 第6部分(4个程序包) javareflection.zip 26.Java反射机制与动态代理 javageneric.zip 27.Java泛型...

    高级java2大学教程 源代码

    讨论了分布式编程,其中包括RMI、Jini、Jiro、JMX、CORBA以及JavaSpace的相关概念;介绍了有关网络服务的内容,并通过实例讲解了servlet和JSP的应用,然后列举了与其他Web服务相关的技术,例如WML、SOAP等。本书还...

    JSP高级编程(全)

    5.2 DTD 的书写及实例 5.3 CSS 与XSL 及其实例 5.4 XHTML 简介 5.5 WML 简介 5.6 本章小结 第6 章 JSP 与XML 联合开发技术 6.1 XML 与JSP 技术联合 6.2 在JSP 中应用XML 6.3 javax.servlet.jsp.tagext 包介绍 6.4 ...

Global site tag (gtag.js) - Google Analytics