使用回调函数的RMI简单实例

时间:2021-06-20 05:35:17

工程结构

  • src
    • client
      • TestClient.java
    • entity
      • PersonEntity.java
    • registry
      • ServerRegistry.java
    • service
      • PersonService.java
      • PersonServiceImpl.java
      • PrintPersonService.java
      • PrintPersonServiceImpl.java

实现

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列表