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
);
//注册通讯路径
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路径与接口必须与服务器配置一致
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:注销对象