工程结构
- src
- client
- TestClient.java
- entity
- PersonEntity.java
- registry
- ServerRegistry.java
- service
- PersonService.java
- PersonServiceImpl.java
- PrintPersonService.java
- PrintPersonServiceImpl.java
- client
实现
1. 创建数据Bean
该bean用于在客户端与服务端之间传输数据。需要实现Serializable接口用于类对象的序列化与反序列化。
package entity;
import java.io.Serializable;
public class PersonEntity implements Serializable{
private static final long serialVersionUID = -6086743965334139076L;
private String name;
private int age;
public PersonEntity(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2. 创建服务端远程服务接口
注意:远程方法必须抛出RemoteException。
此方法用于实现服务端响应客户端查询人口列表。
package service;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface PersonService extends Remote{
public void getPersons(PrintPersonService printService) throws RemoteException;
}
3. 实现服务端远程服务
服务端实现远程接口,供客户端调用。
注意: 需要继承构造函数的实现。
package service;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;
import entity.PersonEntity;
public class PersonServiceImpl extends UnicastRemoteObject implements PersonService{
private static final long serialVersionUID = 621297838434573682L;
public PersonServiceImpl() throws RemoteException {
super();
// TODO Auto-generated constructor stub
}
/** * 接收客户端的远程接口实例PrintPersonService */
public void getPersons(PrintPersonService printService)
throws RemoteException {
System.out.println("Server thread get person");
try {
Thread.currentThread();
Thread.sleep(3000); //此处沉睡3秒用于模拟执行所需时间
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
List<PersonEntity> persons = new ArrayList<PersonEntity>();
persons.add(new PersonEntity("Bob", 11));
persons.add(new PersonEntity("Rose", 12));
printService.printPerson(persons); //执行客户端的回调函数
}
}
4. Server注册、发布远程接口
该类中的main方法用于启动服务端远程服务
package registry;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import service.PersonService;
import service.PersonServiceImpl;
public class ServiceRegistry {
public static void main(String[] args) {//服务端程序入口
try {
PersonService personService = new PersonServiceImpl();
LocateRegistry.createRegistry(32479);
Naming.bind("rmi://127.0.0.1:32479/PersonService", personService);
System.out.println("Service started...");
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (AlreadyBoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
5. Client远程接口
客户端的回调函数也需要以远程接口的方式实现,供服务端调用。在调用回调函数的过程中,客户端与服务端的角色反转。
package service;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.List;
import entity.PersonEntity;
public interface PrintPersonService extends Remote{
public void printPerson(List<PersonEntity> persons) throws RemoteException;
}
package service;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.List;
import entity.PersonEntity;
public class PrintPersonServiceImpl extends UnicastRemoteObject implements PrintPersonService{
private static final long serialVersionUID = 5471018647833463871L;
public PrintPersonServiceImpl() throws RemoteException {
super();
// TODO Auto-generated constructor stub
}
public void printPerson(List<PersonEntity> persons) {
System.out.println("Client thread print person!");
for (PersonEntity person : persons) {
System.out.println(person.getName()+" "+person.getAge());
}
}
}
6. Client调用服务端远程接口
package client;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import service.PersonService;
import service.PrintPersonServiceImpl;
public class TestClient {
public static void main(String[] args) {//客户端程序入口
try {
PersonService personService = (PersonService)Naming.lookup("rmi://127.0.0.1:32479/PersonService");
personService.getPersons(new PrintPersonServiceImpl());//客户端调用服务端的远程函数,并将回调函数的远程接口实例传递给服务端,供服务端调用
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NotBoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行
先运行服务端,后运行客户端,可观察到在客户端启动3秒之后,客户端标准输出Terminal输出了Person列表