代码如下:
package com.unmi;   
    
import java.rmi.*;   
    
/**   
 * 远程接口必须扩展接口java.rmi.Remote   
 */   
public interface HelloInterface extends Remote   
{   
  /**   
  * 远程接口方法必须抛出 java.rmi.RemoteException   
  */   
  public String say() throws RemoteException;   
}   
2. 实现远程接口及远程方法(继承UnicastRemoteObject)Hello.javajava 代码
package com.unmi;   
    
import java.rmi.*;   
import java.rmi.server.*;   
    
/**   
 * 扩展了UnicastRemoteObject类,并实现远程接口 HelloInterface   
 */   
public class Hello extends UnicastRemoteObject implements HelloInterface   
{   
  private String message;   
    
  /**   
  * 必须定义构造方法,即使是默认构造方法,也必须把它明确地写出来,因为它必须抛出出RemoteException异常   
  */   
  public Hello(String msg) throws RemoteException   
  {   
  message = msg;   
  }   
    
  /**   
  * 远程接口方法的实现   
  */   
  public String say() throws RemoteException   
  {   
  System.out.println("Called by HelloClient");   
  return message;   
  }   
}   
3. 启动RMI注册服务,并注册远程对象(HelloServer.java),在spring中配置  <bean id = "rmiServer" class = " com.unmi.Hello" />   <bean id = "rmiService" class = "org.springframework.remoting.rmi.RmiServiceExporter" >        <property name = "serviceName" value = "rmiServer" />        <property name = "service" ref = "rmiServer" />        <property name = "serviceInterface" value = "com.unmi.HelloInterface" />        <property name = "registryPort" value = "1099" /></bean >
4. 客户端查找远程对象,并调用远程方法(HelloClient)java 代码
package com.unmi;   
    
import java.rmi.Naming;   
    
public class HelloClient   
{   
  /**   
  * 查找远程对象并调用远程方法   
  */   
  public static void main(String[] argv)   
  {   
  try   
  {   
  HelloInterface hello = (HelloInterface) Naming.lookup("rmiServer");   
     
    
  //调用远程方法   
  System.out.println(hello.say());   
  }   
  catch (Exception e)   
  {   
  System.out.println("HelloClient exception: " + e);   
  }   
  }   
}  
 这样的本地调用是没有问题的,如果我想在另外的系统中调用rmiServer这个服务,Client端怎么写?Client端的HelloInterface从哪获取?如果我想在hello.say()方法,加上自己定义的类作为参数,Client端怎么写?Client端传入的定义类从哪获取?

解决方案 »

  1.   

    客户端HelloInterface hello = (HelloInterface) Naming.lookup("rmiServer");   这里可以选择服务器的ip地址。给你个简单例子:package guessthecapital;
    import java.rmi.Remote;
    import java.rmi.RemoteException;
    public interface GuessTheCapitalServer extends Remote{
        public boolean register(String name) throws RemoteException;
        public String getCountry(String name) throws RemoteException;
        public String guess(String name,String capital) throws RemoteException;
    }package guessthecapital;
    import java.rmi.RemoteException;
    import java.rmi.server.UnicastRemoteObject;
    import java.rmi.RMISecurityManager;
    import java.rmi.Naming;
    import java.util.ArrayList;
    import java.util.Map;
    import java.util.HashMap;
    import java.util.Calendar;
    public class GuessTheCapitalServerApp extends UnicastRemoteObject implements
            GuessTheCapitalServer{
        private static ArrayList<Map> countryList=new ArrayList();
        private static ArrayList<Map> playerList=new ArrayList();
        public GuessTheCapitalServerApp() throws RemoteException {
            super();
            HashMap map=new HashMap();
            map.put("country","afghanistan");
            map.put("capital","kabul");
            countryList.add(map);        map=new HashMap();
            map.put("country","australia");
            map.put("capital","canberra");
            countryList.add(map);        map=new HashMap();
            map.put("country","cambodia");
            map.put("capital","phnom penh");
            countryList.add(map);        map=new HashMap();
            map.put("country","canada");
            map.put("capital","ottawa");
            countryList.add(map);
            ......
        }
        public boolean register(String player) {
            for(int i=0;i<playerList.size();i++){
                if(playerList.get(i).get("player").equals(player.toLowerCase())){
                    return false;
                }
            }
            Calendar c=Calendar.getInstance();
            int i=c.get(Calendar.MILLISECOND)%29;
            Map map=new HashMap();
            map.put( "player",player.toLowerCase());
            map.put("pos", i);
            playerList.add(map);
            System.out.println("Player "+player.toUpperCase()+" registered with "+(String)countryList.get(i).get("country"));
            return true;
        }
        public String getCountry(String player) {
            for(int i=0;i<playerList.size();i++){
                if(((String)playerList.get(i).get("player")).equals(player.toLowerCase())){
                    int pos=(Integer)playerList.get(i).get("pos");
                    return (String)countryList.get(pos).get("country");
                }
            }
            return "No country";
        }
        public String guess(String player, String capital) {
            for(int i=0;i<playerList.size();i++){
                if(((String)playerList.get(i).get("player")).equals(player.toLowerCase())){
                    int pos=(Integer)playerList.get(i).get("pos");
                    String currCapital=(String)countryList.get(pos).get("capital");
                    if(currCapital.equals(capital.toLowerCase())){
                        System.out.println(player.toUpperCase()+":"+((String)countryList.get(i).get("country")).toUpperCase()
                                +":"+((String)countryList.get(i).get("capital")).toUpperCase());
                        return "CORRECT: The capital of "+((String)countryList.get(i).get("country")).toUpperCase()
                                +" is "+capital.toUpperCase();
                    }
                }
            }
            return "WRONG: Capital or Player incorrect";
        }    public static void main(String args[]){
            System.out.println();
            System.out.println("Initialising GuessTheCapitalServer ...");
            if(System.getSecurityManager()==null){
                System.setSecurityManager(new RMISecurityManager());
            }
            try{
                GuessTheCapitalServer guessTheCapitalServer=new GuessTheCapitalServerApp();
                Naming.rebind("GuessTheCapitalServer", guessTheCapitalServer);
                System.out.println("GuessTheCapitalServer Started");
                System.out.println();
            }catch(Exception e){
                System.out.println("GuessTheCapitalServer err:"+e.getMessage());
            }
        }}package guessthecapital;
    import java.rmi.RMISecurityManager;
    import java.rmi.Naming;
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    public class Main {    public static void main(String args[]) throws Exception {
            if (args.length == 0) {
                System.out.println("error:must input the server,like localhost.");
                return;
            }
            System.setSecurityManager(new RMISecurityManager());
            GuessTheCapitalServer guessTheCapitalServer = (GuessTheCapitalServer) Naming.lookup("//" + args[0] + "/GuessTheCapitalServer");
            BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
            String readLine = "", player = "", inCountry = "", capital = "";
            System.out.println();
            while (!readLine.toLowerCase().equals("q")) {
                System.out.print("Enter player name ('Q' or 'q' to exit):");
                readLine = sin.readLine();
                if (!readLine.toLowerCase().equals("q")) {
                    player = readLine;
                    if (guessTheCapitalServer.register(player)) {
                        System.out.println("Player " + player.toUpperCase() + " registered.");
                    } else {
                        System.out.println("Player has already registered.");
                    }
                    System.out.println();                inCountry = guessTheCapitalServer.getCountry(player);
                    System.out.print("What is the capital of " + inCountry + " ('Q' or 'q' to exit):");
                    readLine = sin.readLine();
                    if (!readLine.toLowerCase().equals("q")) {
                        System.out.println(guessTheCapitalServer.guess(player, readLine));
                        System.out.println();
                    }
                }
            }
            System.out.println();
            System.out.println("Terminated. Exiting...");
        }
    }
    rmi.bat:
    set classpath=%classpath%;f:\student\capitalRMI
    start rmiregistryserver.bat
    set classpath=%classpath%;f:\student\capitalRMI
    java guessthecapital.GuessTheCapitalServerAppclient.bat
    set classpath=%classpath%;f:\student\capitalRMI
    java guessthecapital.Main localhost              --这里localhost可以换成server的ip操作说明:
    编译:cd F:\student\capitalRMIjavac -d . -cp . *.java创建安全策略:
    policytool:
    安全文件:.java.policy
    grant {
      permission java.security.AllPermission;
    };生成stubset classpath=%classpath%;f:\student\capitalRMIrmic guessthecapital.GuessTheCapitalServerApp注册
    start rmiregistry运行
    另外打开cmdset classpath=%classpath%;f:\student\capitalRMIjava guessthecapital.GuessTheCapitalServerApp客户端
    set classpath=%classpath%;f:\student\capitalRMI
    java guessthecapital.Main localhost
      

  2.   

    客户端
    <bean id="ClientrmiService"
            class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
            <property name="serviceInterface">
                <value>com.unmi.HelloInterface</value>
            </property>
            <property name="serviceUrl">
                <value>rmi://10.299.101.***:1099/rmiService</value>
            </property>
            <property name="refreshStubOnConnectFailure">
            <value>true</value></property>
            <property name="lookupStubOnStartup"><value>false</value></property>
        </bean>HelloInterface hello = (HelloInterface) Naming.lookup("ClientrmiService");  
      

  3.   

    对了,同时你还的将你的远程接口类打包jar ,让客户端加载
      

  4.   


    恩,这个我知道,我想知道是怎么实现从网络加载接口类,类似于webService的客户端一样。
      

  5.   

    恩,这个也是一种方法,不过这样的话,只要有第三方调用的话,我都要向他提供接口类的jar包。
    能不能像webService一样,通过访问地址可以自动生成客户端?
      

  6.   

    你肯定要向客户提供你的接口类的jar的,不然怎么写客户端呢。你可以放到一个网页上,让第三方开发的人自己下载。
      

  7.   

    webService只是传递数据,同样要告诉客户端开发的人你的数据格式的
      

  8.   

    恩,提供jar的包的方式是可以的。webService能根据接口地址生成需要调用的类,rmi没有这样的方式吗?
      

  9.   

    rmi做为j2ee最古老基本的11大组件之一,99年就被集成进ejb和各种框架里面去了,其实它的实现过程是很麻烦的,作为网络开发当年可谓风靡一时啊,现在的除了老程序员,已经没几个人知道rmi是干什么的了,首先你得理解它的原理,才知道怎么去网上找资料:
      rmi远程是把对象以二进制流的方式通过scoket协议传输远程供给终端调用,实现不同的JVM中的对象可以相互访问,但是这是有个通讯机制的,就是服务端除了要完成服务的注册以外,还要生成占位程序,也可以叫代理程序,代理程序拷贝至终端,你要调用什么服务,首先由代理提供给你,代理会把你的请求信息封装给远程,远程接收到信息后立即调用相关服务,并把返回的结果对象以二进制流的方式传输给终端,终端收到后再进行反序列化,这就是为什么发布服务的时候某些数据对象必须继承序列化接口的原因,我建议你先好好看看这些基本原理,再动手慢慢写hello world,那个时代流行一个eclipse的rmi插件,叫啥名字我忘了,你搜搜,可以实现快速发布服务和生成占位程序,如果你用过axis等webservice框架的时候一定觉得这些操作和它很像,其实axis等框架中也继承了rmi组件,在java远程调用过程中也是这么干的,你研究rmi精神确实可嘉,但是研究技术要有思路,先知道原理才好下手,祝你好运!
      

  10.   

    rmi确实向楼上说的比较古老了,现在用RMIIIOP代替rmi,作为学习看看rmi还是可以,实际应用就算了......