在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());
}
}
我们可以看到结果
至此,就全部讲完啦