java rmi 详解

在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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
web报表工具 请移步:http://download.csdn.net/source/2881508 不多说,除了RMI的学习外,gui对新手入门也是个不错的学习 /* *此类适合在本地注册的RMI服务器,避免了使用了多个DOS的写法,只需要简单的给使用 *本类提供的方法即可。 */ package common.rmiserver; import java.rmi.Naming; import java.rmi.NotBoundException; import java.rmi.Remote; import java.rmi.registry.Registry; import java.rmi.registry.LocateRegistry; //import java.rmi.RMISecurityManager; import java.rmi.RemoteException; import java.net.MalformedURLException; import java.rmi.server.UnicastRemoteObject; import common.zip.ZipClientSocketFactory; import common.zip.ZipServerSocketFactory; public final class RMIServer { private Registry registry = null; // @jve:decl-index=0: private String serverName = "RMIServer"; private String serverPath = "localhost"; private int port = 1099; private Remote serverInterface = null; private Boolean isStart = false; private AllFace dataAllFace = null; private int dataPort = 0;// 数据端口,0表示端口由RMI服务器动态生成. private Remote stub; public RMIServer() { } /* * 使用默认端口,默认服务器名称,服务路径构造函数 use the default port,server name and the url */ public RMIServer(Remote obj) { this.serverInterface = obj; } /* * 使用默认端口,服务路径构造函数 use the default port and server url */ public RMIServer(String servername, Remote obj) { this.serverName = servername; this.serverInterface = obj; } /* * 服务器为默认值的构造函数 use the default url */ public RMIServer(String servername, int port, Remote obj) { this.port = port; this.serverName = servername; this.serverInterface = obj; } /* * 适合1.4范围的版本,当然也适合5.0的版本 */ public Boolean setStart() throws RemoteException, MalformedURLException, NotImplementInterfaceException { if (registry == null) registry = LocateRegistry.createRegistry(port); if (serverInterface == null) { throw new NotImplementInterfaceException( "not found the reote interface method!!"); } Naming.rebind("rmi://"+serverPath + ":" + port + "/" + serverName, serverInterface); isStart = true; return isStart; } /* * jdk5.0以后的写法,在使用之前使用setXxx方法给对象赋值 */ public Boolean start() throws RemoteException, MalformedURLException, NotImplementInterfaceException { if(stub==null) stub = (Remote) UnicastRemoteObject.exportObject(dataAllFace, dataPort);// 0表示端口随机生成. if (registry == null) registry = LocateRegistry.createRegistry(port, new ZipClientSocketFactory(), new ZipServerSocketFactory()); setProperty(serverPath); //绑定IP registry.rebind(serverName, stub); isStart = true; return isStart; } /* * 如果有多个ip,则使用这个方法绑定指定的IP */ public void setProperty(String ip) { System.setProperty("java.rmi.server.hostname", ip); } /* * close the server */ public void close() throws RemoteException, MalformedURLException, NotBoundException { //UnicastRemoteObject.unexportObject(dataAllFace, true); Naming.unbind("rmi://"+serverPath + ":" + port + "/" + serverName); isStart = false; } /* * set server name,if not set the name,the service will use the default name * "RMIServer" */ public void setServerName(String serverName) { this.serverName = serverName; } /* * set the server URL,default localhost "rmi://localhost" */ public void setServerPath(String serverPath) { this.serverPath = serverPath; } /* * set the server port default port is 1099. */ public void setPort(int port) { this.port = port; } /* * set then remote implement method */ public void setServerInterface(Remote serverInterface) { this.serverInterface = serverInterface; } /* * set the server Security */ public void setSecurityManager() { /* if (System.getSecurityManager() == null) { try { // java -Djava.security.policy=policy.txt // common.rmiserver.RMIServer System.setSecurityManager(new RMISecurityManager());// 暂时不要安全设置, } catch (java.rmi.RMISecurityException exc) { throw exc; } }*/ } /* * set the remote method */ public void setDataAllFace(AllFace dataAllFace) { this.dataAllFace = dataAllFace; } /* * set the remote dataport */ public void setDataPort(int dataPort) { this.dataPort = dataPort; } // ----------------------------------------------- /* * return the server URL */ public String getServerPatth() { return serverPath; } /* * return remote method */ public Remote getserverInterface() { return serverInterface; } /* * return the server name */ public String getServerName() { return serverName; } /* * return the server use port */ public int getPort() { return port; } /* * return the server then action state */ public Boolean isStart() { return isStart; } /* * return remote method */ public AllFace getDataAllFace() { return dataAllFace; } /* * return remote dataport */ public int getDataPort() { return dataPort; } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值