远程方法调用(RMI)

RMI(Remote Method Invocation)远程方法调用是一种计算机之间利用远程对象互相调用实现双方通讯的一种通讯机制。使用这种机制,某一台计算机上的对象可以调用另外 一台计算机上的对象来获取远程数据。RMI是Enterprise JavaBeans的支柱,是建立分布式Java应用程序的方便途径。在过去,TCP/IP套接字通讯是远程通讯的主要手段,但此开发方式没有使用面向对 象的方式实现开发,在开发一个如此的通讯机制时往往令程序员感觉到乏味,对此RPC(Remote Procedure Call)应运而生,它使程序员更容易地调用远程程序,但在面对复杂的信息传讯时,RPC依然未能很好的支持,而且RPC未能做到面向对象调用的开发模 式。针对RPC服务遗留的问题,RMI出现在世人面前,它被设计成一种面向对象的通讯方式,允许程序员使用远程对象来实现通信,并且支持多线程的服务,这 是一次远程通讯的革命,为远程通信开辟新的里程碑。

RMI的开发步骤

1、先创建远程接口及声明远程方法,注意,这是实现双方通讯的接口,需要继承 Remote

2、开发一个类来实现远程接口及远程方法,值得注意的是实现类需要继承 UnicastRemoteObject

3、启动远程对象

4、客户端查找远程对象,并调用远程方法

如果需要在双方之间传递一个自定义对象,则该对象应该实现 Serializable

入门实例:

1、建立一个model层,作为远程传输的对象,需要实现Serializable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import  java.io.Serializable;
//注意对象必须继承Serializable
public  class  PersonEntity  implements  Serializable {
     private  int  id;
     private  String name;
     private  int  age;
    public  void  setId( int  id) {
       this .id = id;
    }
    public  int  getId() {
       return  id;
    }
    public  void  setName(String name) {
       this .name = name;
    }
    public  String getName() {
       return  name;
    }
    public  void  setAge( int  age) {
       this .age = age;
    }
    public  int  getAge() {
       return  age;
    }
}

2、创建远程接口,需要继承 Remote,且方法需要抛出 RemoteException异常

1
2
3
4
5
6
7
8
import  java.rmi.Remote;
import  java.rmi.RemoteException;
import  java.util.List;
//此为远程对象调用的接口,必须继承Remote类
public  interface  PersonService  extends  Remote {
    //需要远程调用的方法必须抛出RemoteException异常
     public  List<PersonEntity> GetList()  throws  RemoteException;
}

3、实现远程接口,需要继承 UnicastRemoteObject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import  java.rmi.RemoteException;
import  java.rmi.server.UnicastRemoteObject;
import  java.util.LinkedList;
import  java.util.List;
//此为远程对象的实现类,须继承UnicastRemoteObject
public  class  PersonServiceImpl  extends  UnicastRemoteObject  implements  PersonService {
     /*
      * 因为UnicastRemoteObject的构造方法抛出了RemoteException异常,
      * 因此这里默认的构造方法必须写,且必须声明抛出RemoteException异常
      */
    public  PersonServiceImpl()  throws  RemoteException {
       super ();
    }
    @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;
    }
}

4、注册服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import  java.rmi.Naming;
import  java.rmi.registry.LocateRegistry;
public  class  Program{
    public  static  void  main(String[] args) {
       // TODO Auto-generated method stub
         try  {
          PersonService personService= new  PersonServiceImpl();
          //注册通讯端口
          LocateRegistry.createRegistry( 6600 );
          //注册通讯路径
          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();
       }
    }
}

5、编写客户端程序,调用远程服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import  java.rmi.Naming;
import  java.util.List;
public  class  ProgramClient {
     public  static  void  main(String[] args){
        try {
           //调用远程对象,注意RMI路径与接口必须与服务器配置一致
           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();
        }
     }
}

Naming的几个常见方法:

bind:注册对象,把对象与一个名字绑定,如果该名字已经与其它对象绑定,则抛出NameAreadyBoundException

rebind:注册对象,如果该名字已经与其他对象绑定,则覆盖原先的对象

lookup:查找对象,返回名字所绑定的对象

unbind:注销对象











评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值