什么是RMI?
RMI:远程方法调用(Remote Method Invocation)。
如何建立RMI服务?
建立服务端:
Eclips新建Java Project,自定义名称,例如笔者项目名称:rmi-server。
第1步. 首先建立两个基本的请求对象与响应对象,分别为:BaseIn.java
和BaseOut.java
。
BaseIn.java
package api;
import java.io.Serializable;
/**
*
* 基本入参对象基类
*
*/
public class BaseIn implements Serializable {
private static final long serialVersionUID = 1L;
// 入参对象
private Object params;
// 调用类型
private String invokeType;
public BaseIn() {
}
public BaseIn(Object params, String invokeType) {
super();
this.params = params;
this.invokeType = invokeType;
}
public Object getParams() {
return params;
}
public void setParams(Object params) {
this.params = params;
}
public String getInvokeType() {
return invokeType;
}
public void setInvokeType(String invokeType) {
this.invokeType = invokeType;
}
}
BaseOut.java
package api;
import java.io.Serializable;
/**
*
* 基本返回对象基类
*
*/
public class BaseOut implements Serializable {
private static final long serialVersionUID = 1L;
// 调用类型
private String invokeType;
// 交易状态
private boolean status;
// 业务消息
private String msg;
public BaseOut() {
}
public BaseOut(String invokeType, boolean status, String msg) {
super();
this.invokeType = invokeType;
this.status = status;
this.msg = msg;
}
public String getInvokeType() {
return invokeType;
}
public void setInvokeType(String invokeType) {
this.invokeType = invokeType;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
第2步. 然后定义一个Rmi请求的数据解析器接口与实现,分别为:IRmiApi.java
和RmiApiImpl.java
。
IRmiApi.java 继承 java.rmi.Remote
package api;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
*
* RMI服务功能接口定义
*
*/
public interface IRmiApi extends Remote {
/**
* 方法处理响应器
*
* @param baseIn
* @return
* @throws RemoteException
*/
T handler(BaseIn baseIn) throws RemoteException;
}
RmiApiImpl.java 继承 java.rmi.server.UnicastRemoteObject 并且要有构造方法
package api;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class RmiApiImpl extends UnicastRemoteObject implements IRmiApi {
private static final long serialVersionUID = -1L;
protected RmiApiImpl() throws RemoteException {
super();
}
@SuppressWarnings("unchecked")
@Override
public T handler(BaseIn baseIn) throws RemoteException {
// 定义响应对象
T response = null;
// 处理NullPoint
if (baseIn == null) {
return response;
}
System.out.println("接收到请求:" + baseIn.getInvokeType());
// 具体处理流程
if ("EXIT".equals(baseIn.getInvokeType())) {
System.out.println("接收到服务退出指令...");
System.out.println("服务停止成功!!!");
System.exit(0);
} else if ("getMyInfo".equals(baseIn.getInvokeType())) {
response = (T) new BaseOut(baseIn.getInvokeType(), true,
"获取我的消息-交易成功");
} else {
System.out.println("未知请求【" + baseIn.getInvokeType() + "】");
}
System.out.println("请求【" + baseIn.getInvokeType() + "】结束!");
return response;
}
}
第3步. 以上即完成了整体结构的实现,现在编写RMI服务启动入口(StartRmi.java
)。
StartRmi.java 启动服务入口
package api;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
public class StartRmi {
public static void main(String[] args) {
try {
System.out.println("RMI服务启动中...");
// 实例化服务解析类
IRmiApi api = new RmiApiImpl();
// 注册端口
LocateRegistry.createRegistry(9090);
// 服务地址: rmi://ip:port/serverName
String url = "rmi://127.0.0.1:9090/rmi";
// 绑定服务解析器
Naming.bind(url, api);
System.out.println("启动完毕:" + url);
} catch (RemoteException e) {
e.printStackTrace();
} catch (MalformedURLException | AlreadyBoundException e) {
e.printStackTrace();
}
}
}
现在即可启动查看效果:
控制台输出:
RMI服务启动中...
启动完毕:rmi://127.0.0.1:9090/rmi
第4步. 启动完毕,已经完成大部分实现。但是怎么停止呢?编写停止功能(StopRmi.java
)
StopRmi.java
package api;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.UnmarshalException;
public class StopRmi {
public static void main(String[] args) {
String url = "rmi://127.0.0.1:9090/rmi";
IRmiApi api;
try {
api = (IRmiApi) Naming.lookup(url);
api.handler(new BaseIn(null, "EXIT"));
} catch (UnmarshalException e) {
String errMsg = e.getMessage();
if (errMsg != null && errMsg.indexOf("Connection reset") != -1) {
System.out.println("停止RMI服务成功!!!");
} else {
e.printStackTrace();
}
} catch (MalformedURLException | RemoteException | NotBoundException e) {
e.printStackTrace();
}
}
}
运行测试:
控制台输出:
[Console StopRmi ]:
停止RMI服务成功!!!
[Console StartRmi]:
RMI服务启动中...
启动完毕:rmi://127.0.0.1:9090/rmi
接收到请求:EXIT
接收到服务退出指令...
服务停止成功!!!
到此,整个RMI服务端测试完毕!
如何建立客户
建立客户端:
Eclips新建Java Project,自定义名称,例如笔者项目名称:rmi-client。
第1步. 复制server端 BaseIn.java
和 BaseOut.java
,并且保证包路径一致!!!
- rmi-client
- src
- api
* BaseIn.java
* BaseOut.java
第2步. 复制server端IRmiApi.java
,并且保证包路径一致!!!
- rmi-client
- src
- api
* BaseIn.java
* BaseOut.java
* IRmiApi.java
第3步. 建立请求发送器。
ApiClient.java
package app;
import java.rmi.Naming;
import api.BaseIn;
import api.BaseOut;
import api.IRmiApi;
public class ApiClient {
private static final String DEFAUTL_SERVER_URL = "rmi://127.0.0.1:9090/rmi";
private static IRmiApi server = null;
private ApiClient() {
}
private static void connet() throws Exception {
if (server == null) {
server = (IRmiApi) Naming.lookup(DEFAUTL_SERVER_URL);
}
}
/**
* 请求器
*
* @param baseIn
* @return
*/
public static T sendRequest(BaseIn baseIn) {
try {
connet();
return server.handler(baseIn);
} catch (Exception e) {
String errMsg = e.getMessage();
if (errMsg != null && errMsg.indexOf("Connection reset") != -1) {
System.out.println("停止RMI服务成功!!!");
} else {
e.printStackTrace();
}
}
return null;
}
}
测试Test.java
package app;
import api.BaseIn;
import api.BaseOut;
public class Test {
public static void main(String[] args) {
// 调用业务服务
BaseOut result = ApiClient.sendRequest(new BaseIn(null, "getMyInfo"));
System.out.println(result);
// 停止服务
BaseOut off = ApiClient.sendRequest(new BaseIn(null, "EXIT"));
System.out.println(off);
}
}
重写BaseOut.java
toString 方便打印:
@Override
public String toString() {
return "BaseOut [invokeType=" + invokeType + ", status=" + status
+ ", msg=" + msg + "]";
}
控制台输出
[Console rmi-client ]:
BaseOut [invokeType=getMyInfo, status=true, msg=获取我的消息-交易成功]
停止RMI服务成功!!!
null
[Console rmi-server]:
RMI服务启动中...
启动完毕:rmi://127.0.0.1:9090/rmi
接收到请求:getMyInfo
请求【getMyInfo】结束!
接收到请求:EXIT
接收到服务退出指令...
服务停止成功!!!
至此,RMI服务搭建完成!!!
拓展练习
运行jar包调用服务:
服务端:rmi-server.jar
获取地址:http://ovt5bckd8.bkt.clouddn.com/rmi-server.jar
客户端:rmi-client.jar
获取地址:http://ovt5bckd8.bkt.clouddn.com/rmi-client.jar
运行示例:
[rmi-server.jar]
D:\>java -jar rmi-server.jar
RMI服务启动中...
启动完毕:rmi://127.0.0.1:9090/rmi
接收到请求:getMyInfo
请求【getMyInfo】结束!
接收到请求:EXIT
接收到服务退出指令...
服务停止成功!!!
D:\>
[rmi-client.jar]
D:\>java -jar rmi-client.jar
BaseOut [invokeType=getMyInfo, status=true, msg=获取我的消息-交易成功]
停止RMI服务成功!!!
null
D:\>