1、概念
Java RMI 指的是远程方法调用 (Remote Method Invocation)。它是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法。可以用此方法调用的任何对象必须实现该远程接口。
2、简单示例
2.1 示例一(简单RMI)
接口IHello:
package cn.edu.ecust.wzh.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* @author wzh
* 定义一个远程接口,必须继承Remote接口,其中需要远程调用的方法必须抛出RemoteException异常
*/
public interface IHello extends Remote{
public String helloWorld() throws RemoteException;
public String sayHelloToSomeBody(String someBodyName) throws RemoteException;
}
HelloImpl实现:
package cn.edu.ecust.wzh.rmi;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* 接口实现
* @author wzh
* extends UnicastRemoteObject 在普通rmi的时候需要存在,当在spring中集合多个rmi的时候不需要
*/
public class HelloImpl <span style="font-family: 宋体, 'Arial Narrow', arial, serif;">extends UnicastRemoteObject</span><span style="font-family: 宋体, 'Arial Narrow', arial, serif;"> implements IHello{</span>
private static final long serialVersionUID = 1L;
public HelloImpl() throws RemoteException {
}
@Override
public String helloWorld() throws RemoteException {
// TODO Auto-generated method stub
return "Hello World!";
}
@Override
public String sayHelloToSomeBody(String someBodyName) throws RemoteException {
// TODO Auto-generated method stub
return "你好," + someBodyName + "!";
}
}
HelloServer:
package cn.edu.ecust.wzh.rmi;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
/**
* @author wzh
* 创建RMI注册表,启动RMI服务,并将远程对象注册到RMI注册表中
*/
public class HelloServer {
public static void main(String[] args){
try {
//创建一个远程对象
IHello rhello = new HelloImpl();
//本地主机上的远程对象注册表Registry的实例,并指定端口为8888,
//这一步必不可少(Java默认端口是1099),必不可缺的一步,缺少注册表创建,
//则无法绑定对象到远程注册表上
LocateRegistry.createRegistry(8888);
//把远程对象注册到RMI注册服务器上,并命名为RHello
//绑定的URL标准格式为:rmi://host:port/name
//(其中协议名可以省略,下面两种写法都是正确的)
Naming.bind("rmi://192.168.1.123:8888/hello",rhello);
// Naming.bind("//localhost:8888/RHello",rhello);
System.out.println(">>>>>INFO:远程IHello对象绑定成功!");
} catch (RemoteException e) {
System.out.println("创建远程对象发生异常!");
e.printStackTrace();
} catch (AlreadyBoundException e) {
System.out.println("发生重复绑定对象异常!");
e.printStackTrace();
} catch (MalformedURLException e) {
System.out.println("发生URL畸形异常!");
e.printStackTrace();
}
}
}
HelloClient:
package cn.edu.ecust.wzh.rmi;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
/**
* @author wzh
* 客户端测试,在客户端调用远程对象上的远程方法,并返回结果。
*/
public class HelloClient {
public static void main(String args[]){
try {
//在RMI服务注册表中查找名称为RHello的对象,并调用其上的方法
IHello rhello =(IHello) Naming.lookup("rmi://192.168.1.123:8888/hello");
System.out.println(rhello.helloWorld());
System.out.println(rhello.sayHelloToSomeBody("熔岩"));
} catch (NotBoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
2.2 示例二(由spring配置RMI)
可以将多个rmi服务写到一个配置文件中,统一启动~
基于示例一中的HelloImpl和IHello作为其中的一个RMI服务,再写一个IMath和MathImpl的RMI服务
由spring配置多个rmi服务的时候,extends UnicastRemoteObject 在普通rmi的时候需要存在,当在spring中集合多个rmi的时候不需要
IMath接口:
package cn.edu.ecust.wzh.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface IMath extends Remote{
public Integer add(Integer a, Integer b) throws RemoteException;
}
MathImpl:
package cn.edu.ecust.wzh.rmi;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class MathImpl implements IMath{
private static final long serialVersionUID = 1L;
public MathImpl() throws RemoteException {
}
@Override
public Integer add(Integer a, Integer b) throws RemoteException {
return a+b;
}
}
RMI服务配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="rmiClient_hello" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl">
<value>rmi://192.168.1.123:8888/hello</value>
</property>
<property name="serviceInterface">
<value>cn.edu.ecust.wzh.rmi.IHello</value>
</property>
</bean>
<bean id="rmiClient_math" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl">
<value>rmi://192.168.1.123:9999/math</value>
</property>
<property name="serviceInterface">
<value>cn.edu.ecust.wzh.rmi.IMath</value>
</property>
</bean>
</beans>
RMI客户端配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="rmiClient_hello" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl">
<value>rmi://192.168.1.123:8888/hello</value>
</property>
<property name="serviceInterface">
<value>cn.edu.ecust.wzh.rmi.IHello</value>
</property>
</bean>
<bean id="rmiClient_math" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl">
<value>rmi://192.168.1.123:9999/math</value>
</property>
<property name="serviceInterface">
<value>cn.edu.ecust.wzh.rmi.IMath</value>
</property>
</bean>
</beans>
服务端启动:
package cn.edu.ecust.wzh.rmi;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class RmiService {
public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("rmi-server.xml");
System.out.println("RMI服务伴随Spring的启动而启动了.....");
}
}
客户端调用:
package cn.edu.ecust.wzh.rmi;
import java.rmi.RemoteException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class RmiClient {
/**
* @param args
* @throws RemoteException
*/
public static void main(String[] args) throws RemoteException {
// TODO Auto-generated method stub
ApplicationContext ctx = new ClassPathXmlApplicationContext("rmi-client.xml");
IHello rhello = (IHello) ctx.getBean("rmiClient_hello");
System.out.println(rhello.sayHelloToSomeBody("海翼知"));
IMath rmath = (IMath) ctx.getBean("rmiClient_math");
System.out.println(rmath.add(1, 2));
}
}