RMI例子

1.分布式应用程序需要?

	(1)查找远程对象。

	(2)通过远程对象通信

	(3)调入被当作参数或返回值的对象的类的字节码

2.java分布式对象模型中的术语?

	(1)remote object:指这个对象的方法可以被另一个JRE调用,潜在的含义是JRE不在同一主机上。

	(2)remote method invocation(RMI):在remote object中调用remote interface中规定方法的动作。

3.用户定义remote interface的要求?

	(1)必须直接或间接继承java.rmi.Remote接口。

		例外情况:可以继承non-remote interface。

			

			public interface Alpha{

				public void test() throws java.rmi.RemoteException;

			}



			public interface beta extends Alpha, Remote{

			}

	(2)声明在remote或者父接口中的方法发须满足以下要求:

		<1>声明的方法必须抛出java.rmi.RemoteException,或该异常的父类,例如:java.io.IOException,java.lang.Exception。也可以抛出用户自定义异常,但是该异常必须继承java.rmi.RemoteException。

		<2>声明方法中被声明为参数或返回值必须是一个接口类型,而不是接口的实现类。

4.实现remote interface?

	(1)该类通常继承java.rmi.server.UnicastRemoteObject,因此也会继承java.rmi.server.RemoteObject,java.rmi.server.RemoteServer。

	(2)该类可以实现多个remote interface

	(3)该类可以继承另一个remote interface实现类

	(4)该类可以定义remote interface中未提供的方法,但是这些方法是只能本地来用而不能用来做远程调用的方法。

5.RMI中传递的参数?

	参数或返回值可以是实现serializable的任意对象。例如:简单类型,远程对象,实现java.io.Serializable接口的对象。

	(1)传递non-remote对象

		调用的jre,是传递过来的对象副本,创建一个新的对象。

	(2)传递remote对象

		传递的是remote对象的存根

	(3)引用完整性

		当一个对象的两个应用同时传递到另一个JRE,RMI系统维护引用完整性。

	(4)类注释

		RMI系统为类描述在调用流中用类的信息(例如:URL)来做注释,以便类可以在接收放被调用。

	(5)参数传递

		在远程方法调用中的参数是被写入到一个流,这个流是ObjectOutputStream的子类,用来序列化远程方法调用中定义的参数。ObjectOutputStream的子类重载replaceObject()方法,用输出的远程对象的通讯桩实例来替换远程对象。对象参数是被写入到流通过ObjectOutputStream的writeObject()方法。ObjectOutputStream为个对象先调用replaceObject,再经由writeObject方法将其写入到流。

6.ObjectOutputStream的RMI子类中的replaceObject返回?

	(1)如果对象是java.rmi.Remote对象实例且是被输出在RMI运行时,返回远程对象的桩。如果对象是java.rmi.Remote对象实例且不是被RMI运行时输出,返回远程本身。远程对象桩,可以通过java.rmi.server.RemoteObject.toStub()方法。

	(2)如果不是java.rmi.Remote对象,则被简单的返回。

7.Stubs(桩) and Skeletons(骨架)?

	RMI在远程对象间使用标准通信机制(RPC也采用)stubs和skeletons。

	(1)远程对象的stub?

		可以看作是远程对象的本地代表或代理。调用者调用local stub的方法,stub负责完成远程对象的调用。

	(2)stub的方法被调用后?

		<1>初始化于包含远程对象的虚拟机的连接

		<2>整理(写或传递)远程对象的参数

		<3>等待方法返回的结果

		<4>整理(读)返回值或返回的表达式

		<5>向调用者返回值 

	(3)skeleton?

		负责分发调用到实际的远程对象实现上。在Java2 platform,skeleton可以没有。

	(4)skeleton接收到方法调用后?

		<1>整理(读)远程方法的参数

		<2>调用远程对象实现的方法

		<3>整理(写或传递)返回结果给调用者

	注:stub和skeleton是由rmic编译生成。

8.java.rmi.Naming?

	<1>每个方法都有一个公共的参数,该参数是一个String类型的URL,格式为://host(default host:localhost):port(default port:1099)/name 

9.java.rmi.server.UnicastRemoteObject?

	(1)如果远程对象是用UnicastRemoteObject.exportObject(Remote)方法输出,被调用的stub class(由rmic工具生成)实例是由以下顺序生成。

		<1>确定根类

			1)远程对象类直接实现了扩展remote接口的接口

			2)如果远程对象的父类,实现了扩展remote接口的接口的类,则是根类;否则,依次向上查找 

		<2>被载入的stub的名字是,根类加上"_Stub"后缀。

		<3>stub class根据名字被载入使用根类的class loader。stub class必须继承RemoteStub,必须有一个公共的构造函数,该函数接收一个RemoteRef类型的参数。

		<4>stub实例用RemoteRef来构造。

	(2)输出remote object另外的方式?

		<1>如果远程对象的stub载入失败或java.rmi.server.ignoreStubClasses是被设置为true。代理是被以下发生构造。

			1)代理是被remote object类的class loader定义。

			2)代理实现remote object类实际的所有的接口。

			3)代理调用处理器是一个RemoteRef构建的RemoteObjectInvocationHandler实例。

			4)如果代理不能创建,则抛出StubNotFoundException异常。

	(3)UnicastRemoteObject实现了包含以下特征的远程服务对象

		<1>远程对象通过TCP transport通讯。

		<2>客户端和服务器端之间通过stream protocol通信,调用、方法、返回值。
例子:
远程对象接口文件
RmiHelloRemoteInterface.java

import java.rmi.*;



public interface RmiHelloRemoteInterface extends Remote{

	

	public String helloRemoteObj(String client) throws RemoteException;	

}
远程对象文件
RmiHelloRemoteObject.java
import java.rmi.server.*;

import java.rmi.*;



public class RmiHelloRemoteObject extends UnicastRemoteObject implements RmiHelloRemoteInterface{

	

	public RmiHelloRemoteObject() throws RemoteException{

		super();

	}	

	

	public String helloRemoteObj(String client) throws RemoteException{

		

		return "Hello world, " + client;

	}
}
服务端程序
import java.io.*;

import java.rmi.*;

import java.rmi.server.*;

import sun.applet.*;

import java.rmi.registry.LocateRegistry;



public class RmiHelloServer{

	

	public RmiHelloServer(){

	}	

	

	public static void main(String[] args){

		

		//创建并安装安全管理

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

			System.setSecurityManager(new RMISecurityManager());

		}

		

		try{

			//创建远程对象

			RmiHelloRemoteObject obj = new RmiHelloRemoteObject();

			//启动注册表

			LocateRegistry.createRegistry(3000);

			//将名称绑定到对象

			Naming.bind("//localhost:3000/helloObj", obj);

			System.out.println("RMI服务器正在运行... ...");

		}catch(Exception e){

			e.printStackTrace();

		}

	}

	

}
//客户端程序

import java.rmi.*;

import java.rmi.server.*;



public class RmiHelloClient{



	public RmiHelloClient(){

	}	

	

	public static void main(String[] args){

		//创建并安装安全管理器

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

			System.setSecurityManager(new RMISecurityManager());

		}

		

		try{

			RmiHelloRemoteInterface client = (RmiHelloRemoteInterface)Naming.lookup("rmi://localhost:3000/helloObj");

			System.out.println(client.helloRemoteObj("everyone!"));

		}catch(Exception e){

			e.printStackTrace();

		}

		System.exit(0);

	}

	

}
//安全管理文件

//将以下信息创建一个文件,文件名任取,运行服务端和客户时,要用到,用于授权。

//grant codeBase "file:/D:/test_ws/RMI/" {permission java.net.SocketPermission "*:1000-9999", "accept, connect, listen, resolve";};		
执行程序 (1)编译以上文件 (2)通过rmic创建stub rmic RmiHelloRemoteObject (3)运行java -Djava.security.policy=test.policy RmiHelloServer (4)运行java -Djava.security.policy=test.policy RmiHelloClient

你可能感兴趣的:(java,应用服务器,虚拟机,Security,sun)