Java 远程方法调用 RMI

概述

rmi是一种多个计算机之间利用远程对象互相调用实现双方通信的机制,rmi使得一台计算机上的对象调用另外一台计算机上的对象非常方便。
著名的 EJB 就是基于rmi实现的,可以说 rmi 是java建立 分布式应用 的方便途径和有力武器!

RMI开发步骤

1.建立远程调用接口并声明方法,注意:这是双方通信的接口,需要继承java.rmi.Remote
2.开发远上述程接口的实现类,注意:该实现类还必需继承java.rmi.server.UnicastRemoteObject
3.注册并启动rmi server
4.客户端查找并使用远程服务

示例代码

package rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.List;
public interface PersonService extends Remote {
    public List<Person> getList() throws RemoteException;
}
package rmi.server;
import rmi.Person;
import rmi.PersonService;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.LinkedList;
import java.util.List;
public class PersonServiceImpl extends UnicastRemoteObject implements PersonService {
    public PersonServiceImpl() throws RemoteException {
        super();
    }
    @Override
    public List<Person> getList() throws RemoteException {
        List<Person> personList = new LinkedList<Person>();
        personList.add(new Person("a"));
        personList.add(new Person("b"));
        personList.add(new Person("c"));
        return personList;
    }
}
package rmi.server;
import rmi.PersonService;
import rmi.server.PersonServiceImpl;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
public class RmiServer {
    public static void main(String[] args) throws RemoteException, MalformedURLException, UnknownHostException {
        System.setProperty("java.rmi.server.hostname", "aaa");
//        System.setProperty("java.rmi.server.hostname", "centos");
//        System.setProperty("java.rmi.server.hostname", "localhost");
//        System.setProperty("java.rmi.server.hostname", "127.0.0.1");
        PersonService personService = new PersonServiceImpl();
        //注册通讯端口
//        System.out.println(java.net.InetAddress.getLocalHost());
        LocateRegistry.createRegistry(6600);
        //注册通讯路径
//        Naming.rebind("rmi://127.0.0.1:6600/PersonService", personService);
        Naming.rebind("rmi://localhost:6600/PersonService", personService);
//        Naming.rebind("rmi://centos:6600/PersonService", personService);
//        Naming.rebind("rmi://10.10.4.42:6600/PersonService", personService);
        System.out.println("Service Start!");
    }
}
package rmi.client;
import rmi.Person;
import rmi.PersonService;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.List;
public class RmiClient {
    public static void main(String[] args) throws RemoteException, MalformedURLException, NotBoundException {
//        PersonService personService = (PersonService) Naming.lookup("rmi://10.10.4.42:6600/PersonService");
        PersonService personService = (PersonService) Naming.lookup("rmi://168.1.191.119:6600/PersonService");
        List<Person> personList = personService.getList();
        for (Person person : personList) {
            System.out.println(person);
        }
    }
}

可能的问题

rmi服务在windows上可以被客户端正常查找并使用,但是,当rmi在linux上时候,则客户端可能出现拒绝访问地址127.0.1.1的问题。


原因是由于客户端首先通过socket连接到rmi服务器时候,rmi服务器会向客户端发送一个“rmi服务ip”,此“rmi服务ip”用于客户端查找对应资源,rmi server会通过java.net.InetAddress.getLocalHost取本机ip作为“rmi服务ip”返回给客户端,在windows下取到的是正确的对外ip,而在linux下取到的是127.0.1.1,这样如果客户端拿到的是127.0.1.1就会去客户端本机查找,所以就会出错。
修订方案:rmi server绑定的时候必需要指定自身真实的对外ip,而不是localhost或127.0.0.1,如可以使用“rmi://10.10.191.119:6600/**”进行绑定,
另一种比较好的方式是通过rmi提供的参数-Djava.rmi.server.hostname或系统属性java.rmi.server.hostname设置成本机真实的ip,如
-Djava.rmi.server.hostname=10.10.191.119

System.setProperty("java.rmi.server.hostname", "10.10.191.119");


PS:弄清楚了服务器向客户端传递“rmi服务ip”的原理后就好解决了,
即便是rmi服务器设置:System.setProperty("java.rmi.server.hostname", "aaa");
只要客户端的hosts表中配置了:10.10.191.119  aaa
也是可以的,原理就是rmi server会将java.rmi.server.hostname的值传递给客户端,客户端根据得到的值去查找服务。
如果拿到的是ip地址则直接访问,如果拿到的是字符串主机名则去本机的hosts中查找对应的ip。



你可能感兴趣的:(Java 远程方法调用 RMI)