RMI推荐博客:
1.定义接口,继承Remote。在Java中,只要一个类extends了java.rmi.Remote接口,即可成为存在于服务器端的远程对象,供客户端访问并提供一定的服务。JavaDoc描述:Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口。任何远程对象都必须直接或间接实现此接口。只有在“远程接口”(扩展 java.rmi.Remote 的接口)中指定的这些方法才可远程使用。
注意:extends了Remote接口的类或者其他接口中的方法若是声明抛出了RemoteException异常,则表明该方法可被客户端远程访问调用。
public interface PersonService extends Remote{
//远程调用的接口
public List<PersonEntity> GetList() throws RemoteException;
}
2.远程对象必须实现java.rmi.server.UniCastRemoteObject类,这样才能保证客户端访问获得远程对象时,该远程对象将会把自身的一个拷贝以Socket的形式传输给客户端,此时客户端所获得的这个拷贝称为“存根”,而服务器端本身已存在的远程对象则称之为“骨架”。其实此时的存根是客户端的一个代理,用于与服务器端的通信,而骨架也可认为是服务器端的一个代理,用于接收客户端的请求之后调用远程方法来响应客户端的请求。
/*
* 接口的实现类,UnicastRemoteObject用于导出的远程对象和获得与该远程对象通信的存根。
*/
public class PersonServiceImpl extends UnicastRemoteObject implements PersonService {
private static final long serialVersionUID = 4881868462165416802L;
public PersonServiceImpl() throws RemoteException {
super();
// TODO Auto-generated constructor stub
}
@Override
public List<PersonEntity> GetList() throws RemoteException {
// TODO Auto-generated method stub
System.out.println("Get Person Start!");
List<PersonEntity> personList = new LinkedList<PersonEntity>();
PersonEntity person1 = new PersonEntity();
person1.setAge(25);
person1.setId(0);
person1.setName("Leslie");
personList.add(person1);
PersonEntity person2 = new PersonEntity();
person2.setAge(25);
person2.setId(1);
person2.setName("Rose");
personList.add(person2);
return personList;
}
}
3.
/*
* 服务端,(注册服务,供客户端调用)
*/
public class Program {
public static void main(String[] args) {
try {
//继承Remote的远程对象
PersonService personService = new PersonServiceImpl();
//注册通讯端口
LocateRegistry.createRegistry(6600);
//注册通讯路径
// 参数1.String—使用 URL 格式(不含 scheme 组件) 参数2.Remote—obj将与名称关联的新远程对象
Naming.rebind("rmi://127.0.0.1:6600/PersonService", personService);
System.out.println("Service Start!");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
4.客户端
/*
* 客户端,调用服务
*/
public class Program {
public static void main(String[] args) {
try {
/*调用远程对象,注意RMI路径与接口必须与服务器配置一致
* lookup:返回与指定 name 关联的远程对象的引用
* 参数name: 使用 URL 格式(不含 scheme 组件)的名称
*/
PersonService personService = (PersonService) Naming.lookup("rmi://127.0.0.1:6600/PersonService");
List<PersonEntity> personList = personService.GetList();
for (PersonEntity person : personList) {
System.out.println("ID:" + person.getId() + " Age:" + person.getAge() + " Name:" + person.getName());
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
保存几张运行原理的图: