概述
rmi是一种多个计算机之间利用远程对象互相调用实现双方通信的机制,rmi使得一台计算机上的对象调用另外一台计算机上的对象非常方便。著名的 EJB 就是基于rmi实现的,可以说 rmi 是java建立 分布式应用 的方便途径和有力武器!
RMI开发步骤
1.建立远程调用接口并声明方法,注意:这是双方通信的接口,需要继承java.rmi.Remote2.开发远上述程接口的实现类,注意:该实现类还必需继承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。