java rmi 详解

来源:互联网 发布:zookeeper nginx 整合 编辑:程序博客网 时间:2024/05/18 17:24

在Java中有一种叫rmi的技术

全称叫 remote method invoke (远程方法调用)

首先来说一下rmi和rpc的对比吧。
两个技术都有的共同点都是自己的机器上去掉别的机器上的服务。
不同的地方是rmi是Java语言实现的,rmi要求两端的实现都必须是Java代码。
而rpc则不同,所以rpc可以跨平台,而rmi则稍微差点。

rmi客户端可以根据服务端暴露的接口,就可以去实现调用rmi服务端的代码实现。感觉就像是在调用自己本地的代码一样。但实际上是在调用远程机器上的代码。
首先我们根据Java提供的RMIapi来实现一个简单的rmi服务吧。

直接上代码了

package org.huluo;import java.rmi.Remote;import java.rmi.RemoteException;public interface MyRmiServer extends Remote {    Student  sayHelloRmiServer()  throws RemoteException;}

上面这段代码是rmi服务端的接口代码。它应该要继承Remote这个接口。并且里面的方法声明的时候要抛出RemoteException

我们在来看一看这个rmi服务端的接口实现

package org.huluo;import java.rmi.RemoteException;import java.rmi.server.UnicastRemoteObject;public class MyRmiServerImpl extends UnicastRemoteObject implements MyRmiServer {    protected MyRmiServerImpl() throws RemoteException {    }    public Student sayHelloRmiServer() {        return new Student();    }}

接口的实现应该继承UnicastRemoteObject这个类。
在这里我们给我们的实现类返回一个Student entity。
接下来我们贴出Student entity的代码

package org.huluo;import java.io.Serializable;public class Student  implements Serializable{    private String username = "张三";    private String passwrod = "密码123";    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getPasswrod() {        return passwrod;    }    public void setPasswrod(String passwrod) {        this.passwrod = passwrod;    }    @Override    public String toString() {        return String.format("student entity is construct of 用户名是:%s , 密码是:%s", this.username, this.passwrod);    }}

这里应该要说的是Student 这个entity应该要实现序列化的接口。
这个应该很容易想通的把(不然客户端是如何拿到rmi服务端的数据呢)。

现在进入我们的重头戏了。将我们的rmi服务启动起来。

package org.huluo;import java.net.MalformedURLException;import java.rmi.AlreadyBoundException;import java.rmi.Naming;import java.rmi.RemoteException;import java.rmi.registry.LocateRegistry;public class RmiServer {    public static void main(String[] args) throws RemoteException, AlreadyBoundException, MalformedURLException {        MyRmiServerImpl myRmiServerImpl = new MyRmiServerImpl();        LocateRegistry.createRegistry(9000);        Naming.bind("rmi://localhost:9000/myrmiserver", myRmiServerImpl);        System.out.println("rmi服务启动成功");    }}

我们将我们的rmi服务绑定在 rmi://localhost:9000/myrmiserver这个地址上
这里写图片描述
我们可以看到rmi服务被启动起来了

我们再在这里写一下rmi的客户端去消费服务端的服务吧。

代码很简单哦

package org.huluo;import java.net.MalformedURLException;import java.rmi.Naming;import java.rmi.NotBoundException;import java.rmi.RemoteException;public class RmiClient {    public static void main(String[] args) throws RemoteException, NotBoundException, MalformedURLException {        MyRmiServer myRmiServer = (MyRmiServer) Naming.lookup("rmi://localhost:9000/myrmiserver");        System.out.println(myRmiServer.sayHelloRmiServer());    }}

只需要 我们把绑定的地址对上号就可以了,并且直接调用方法,就像调用本地方法一样。
我们可以看到结果
这里写图片描述

这是rmi原生的写法。但是我们在实际的开发中。总是和Spring在打交道,所以笔者这里就在啰嗦几句关于Spring和rmi一起使用的技巧。其实也是很简单的。

我们先把Spring和rmi集成的配置文件先贴上来吧。

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:context="http://www.springframework.org/schema/context"       xmlns:tx="http://www.springframework.org/schema/tx"       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.xsd       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">    <bean id="rmiServiceExporter" class="org.springframework.remoting.rmi.RmiServiceExporter">        <property name="serviceName" value="mySpringRmiService"/>        <property name="service" ref="studentService"/>        <property name="serviceInterface" value="org.huluo.springrmi.SpringRmiStudentService"/>        <property name="registryPort" value="8080" />        <property name="servicePort" value="9000"/>    </bean>    <bean id="studentService" class="org.huluo.springrmi.SpringRmiStudentServiceImpl"/></beans>

然后再讲我们的接口和实现贴上来。

package org.huluo.springrmi;public interface SpringRmiStudentService {    String getNumber();}
package org.huluo.springrmi;public class SpringRmiStudentServiceImpl implements SpringRmiStudentService {    @Override    public String getNumber() {        return "student服务";    }}

我们最后把rmi服务启动起来

package org.huluo.springrmi;import org.springframework.context.support.ClassPathXmlApplicationContext;public class SpringRmiServer {    public static void main(String[] args) {        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath*:spring/spring-rmi-server.xml");        applicationContext.start();    }}

这里写图片描述
服务就启动起来了。是不是比较方便。不用再继承UnicastObject和实现Remote接口以及声明时手动的抛出RemoteException异常了。

用Spring rmi的客户端来进行消费就更简单了。只需在Spring的配置文件中将rmi服务暴露的接口声明好,再注入进来就行了。

先把Spring的配置文件贴上来

<?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.xsd">    <bean id="studentService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">        <property name="serviceUrl" value="rmi://localhost:8080/mySpringRmiService"/>        <property name="serviceInterface" value="org.huluo.springrmi.SpringRmiStudentService"/>    </bean></beans>
package org.huluo.springrmi;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = "classpath*:spring/spring-rmi-client.xml")public class SpringRmiClient {    @Autowired    private SpringRmiStudentService studentService;    @Test    public void springRmiClient() throws Exception {        System.out.println("来自Spring RMI服务端的结果" + studentService.getNumber());    }}

启动Spring rmi的客户端。

package org.huluo.springrmi;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = "classpath*:spring/spring-rmi-client.xml")public class SpringRmiClient {    @Autowired    private SpringRmiStudentService studentService;    @Test    public void springRmiClient() throws Exception {        System.out.println("来自Spring RMI服务端的结果" + studentService.getNumber());    }}

我们可以看到结果这里写图片描述

至此,就全部讲完啦

0 0