说明:程序由7个文件组成
请将这7个文件放在d:\rmi目录下面,
然后用记事本打开compile and run.bat, 运行cmd, 逐条执行里面的命令,(若直接点击则不会启动客户端)
================================================
IServer.java RMI 远程服务接口
ServerImpl.java RMI 远程服务实现类
Client.java RMI 本地客户端
RmiUtil.java RMI 工具类
config.properties RMI配置参数
my.policy RMI安全授权
compile and run.bat cmd编译和运行命令
================================================
IServer.java :
package rmi;
/**
* RMI 远程服务接口
*
* @author [email protected]
* @since 1.6
* @version %I%, %G%
*/
public interface IServer extends java.rmi.Remote {
/**
* 响应反馈字符串
*
* @param num 反馈字符串重复的次数
* @return 反馈字符串
*/
public String response(int num) throws java.rmi.RemoteException;
/**
* 动态调用方法
*
* @param method 要调用的方法名(空参)
* @return 反馈字符串
*/
public String request(String method) throws java.rmi.RemoteException;
}
ServerImpl.java :
package rmi;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Map;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.RMIClassLoader;
import java.rmi.registry.*;
import rmi.RmiUtil;
/**
* RMI 远程服务实现类
*
* @author [email protected]
* @since 1.6
* @version %I%, %G%
*/
public class ServerImpl extends UnicastRemoteObject implements IServer {
/**
* 版本序列号
*/
public static final long serialVersionUID = 1L;
/**
* 无参的构造方法
*/
public ServerImpl() throws java.rmi.RemoteException {
super();
}
/**
* 响应反馈字符串
*
* @param num 反馈字符串重复的次数
* @return 反馈字符串
*/
public String response(int num) throws RemoteException {
// 获取配置参数
Map<String, String> map = RmiUtil.getConfig();
String response = "";
for (int i = 0; i < num; i++) {
response += "[" + (i + 1) + "]" + map.get("response") + "\n";
}
return response;
}
/**
* 动态调用方法
*
* @param method 要调用的方法名(空参)
* @return 反馈字符串
*/
public String request(String method) throws RemoteException {
try {
// 获取class
// Class<?> c = Class.forName("rmi.ServerImpl");
Class<?> c = this.getClass();
// 获取method指定的方法
Method m = c.getMethod(method);
// 获取所有 定义了的方法
Method ms[] = c.getDeclaredMethods();
System.out.println("\nThe methods of rmi.ServerImpl :\n ");
for (int i = 0; i < ms.length; i++) {
System.out.println(ms[i].toString());
}
// 动态执行方法
// return (String) m.invoke(c.newInstance());
return (String) m.invoke(this);
} catch (Exception e) {
e.printStackTrace();
return "Error: Cannot Invoke The Method: " + method;
}
}
/**
* 响应反馈字符串
*
* @return 反馈字符串
*/
public String feedback() throws RemoteException {
// 获取配置参数
Map<String, String> map = RmiUtil.getConfig();
try {
// 远程类的字节码codebase
URL base=new URL("http://" + map.get("host") + "/");
// 远程类的全限定名称
String name = "rmi.Client";
// RMI 进行动态类加载
RMIClassLoader.loadClass(base,name);
// 加载远程类字节码后调用函数
Client.remoteCall();
} catch (Exception e) {
e.printStackTrace();
}
return map.get("request");
}
/**
* 主函数
*
* @param args 主函数参数
*/
public static void main(String[] args) {
// 设置RMI的安全策略
RmiUtil.setSecurityManager();
try {
// 获取配置参数
Map<String, String> map = RmiUtil.getConfig();
// RMI服务对象
ServerImpl obj = new ServerImpl();
// 注册端口,并返回Registry对象
Registry reg = RmiUtil.createRegistry(
Integer.parseInt(map.get("port"))
);
// 绑定服务对象
RmiUtil.rebind(reg, map.get("name"), obj);
System.out.println("RmiServer Running...");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Client.java:
package rmi;
import rmi.RmiUtil;
import java.util.Map;
/**
* RMI 本地客户端
*
* @author [email protected]
* @since 1.6
* @version %I%, %G%
*/
public class Client {
/**
* 加载远程类字节码后调用函数
*/
public static void remoteCall(){
System.out.println("Remote Calling...");
}
/**
* 主函数
*
* @param args 主函数参数
*/
public static void main(String args[]) {
// 设置rmi安全策略
RmiUtil.setSecurityManager();
try {
// 获取配置参数
Map<String, String> map = RmiUtil.getConfig();
// rmi服务主机名
String host = map.get("host");
// rmi服务端口
String port = map.get("port");
// rmi服务名
String name = map.get("name");
// 反馈字符串重复的次数
int num = Integer.parseInt(map.get("num"));
// 要动态调用的方法名
String method = map.get("method");
// rmi服务url地址
String url = "rmi://" + host + ":" + port + "/" + name;
// 通过RMI服务url地址,获取RMI服务对象
IServer obj = (IServer) RmiUtil.lookup(url);
// 响应反馈字符串,重复num次
String response = obj.response(num);
// 动态调用method方法
String request = obj.request(method);
System.out.println("RmiClient Running...");
System.out.println("url: " + url);
System.out.println(response);
System.out.println(request);
} catch (Exception e) {
e.printStackTrace();
}
}
}
RmiUtil.java :
package rmi;
import java.rmi.*;
import java.util.Map;
import java.util.HashMap;
import java.rmi.registry.*;
import java.io.*;
import java.util.Properties;
/**
* RMI 工具类
*
* @author [email protected]
* @since 1.6
* @version %I%, %G%
*/
public final class RmiUtil {
/**
* 是否第一次打印出配置参数
* <p>
* <code>true</code> 第一次打印<br>
* <code>false</code> 非第一次打印(略过打印)<br>
*/
public static boolean isFirstPrint = false;
/**
* 注册RMI端口,并返回Registr对象
*
* @param port RMI端口
* @return Registr对象
*/
public static Registry createRegistry(int port) throws RemoteException {
Registry reg = null;
try {
// 如果该端口未被注册,则抛异常
reg = LocateRegistry.getRegistry(port);
// 获取该端口注册的rmi对象
reg.list();
} catch (RemoteException e) {
try {
// 捕获异常,端口注册
reg = LocateRegistry.createRegistry(port);
} catch (RemoteException e2) {
e2.printStackTrace();
}
}
return reg;
}
/**
* 通过Registry对象, 绑定RMI服务
*
* @param reg Registry对象
* @param name RMI服务名
* @param obj RMI服务对象
*/
public static void rebind(Registry reg, String name, Remote obj)
throws Exception {
try {
reg.rebind(name, obj);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 直接通过Naming绑定RMI服务
*
* @param name RMI服务名
* @param obj RMI服务对象
*/
public static void rebind(String name, Remote obj) throws Exception {
try {
Naming.rebind(name, obj);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 通过RMI服务url地址,获取RMI服务对象
*
* @param url RMI服务url地址
* @return RMI服务对象
*/
public static Remote lookup(String url) throws Exception {
try {
return Naming.lookup(url);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 配置RMI安全策略
*/
public static void setSecurityManager() {
System.setSecurityManager(new RMISecurityManager());
}
/**
* 从config.properties获取配置参数
*
* @return 配置参数
*/
public static Map<String, String> getConfig() {
Map<String, String> map = null;
try {
// RmiUtil类的上级目录的绝对地址
String path = RmiUtil.class.getResource("").toString();
// config.properties的绝对地址
path += "config.properties";
// windows下去掉file:/
path = path.replace("file:/", "");
// windows下将/替换为\
path = path.replace("/", "\\");
// 拿到config.properties的InputStream
InputStream in = new BufferedInputStream(new FileInputStream(path));
Properties p = new Properties();
// 读取config.properties内容
p.load(in);
// 读取config.properties的显示字符集
String encode = p.getProperty("encode");
map = new HashMap<String, String>();
// 逐个将配置参数转换为指定的字符集
map.put("encode", new String(
p.getProperty("encode").getBytes("ISO8859-1"), encode)
);
map.put("name", new String(
p.getProperty("name").getBytes("ISO8859-1"), encode)
);
map.put("host", new String(
p.getProperty("host").getBytes("ISO8859-1"), encode)
);
map.put("port", new String(
p.getProperty("port").getBytes("ISO8859-1"), encode)
);
map.put("response", new String(
p.getProperty("response").getBytes("ISO8859-1"), encode)
);
map.put("request", new String(
p.getProperty("request").getBytes("ISO8859-1"), encode)
);
map.put("num", new String(
p.getProperty("num").getBytes("ISO8859-1"), encode)
);
map.put("method", new String(
p.getProperty("method").getBytes("ISO8859-1"), encode)
);
// 只有在第一次调用才打印配置参数
if (!isFirstPrint) {
isFirstPrint = true;
System.out.println();
System.out.println("============= config datas start ================");
System.out.println("config path: " + path);
System.out.println("encode: " + map.get("encode"));
System.out.println("name: " + map.get("name"));
System.out.println("host: " + map.get("host"));
System.out.println("port: " + map.get("port"));
System.out.println("response: " + map.get("response"));
System.out.println("request: " + map.get("request"));
System.out.println("num: " + map.get("num"));
System.out.println("method: " + map.get("method"));
System.out.println("============= config datas end ================");
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
return map;
}
}
config.properties:
# RMI配置参数
# 配置文件的显示字符集
encode=gbk
# 远程RMI绑定的服务名
name=RmiServer
# 远程RMI的主机名
host=localhost
# 远程RMI的端口
port=8765
# 反馈字符串1
response=你好,rmi反馈成功
# 反馈字符串2
request=方法调用成功
# 反馈字符串重复的次数
num=10
# 要动态调用的方法名
method=feedback
my.policy :
grant{
permission java.security.AllPermission;
};
compile and run.bat :
d:
cd d:\
cd rmi
java -d .. *.java
cd ../
rmic -d . rmi.ServerImpl
start rmiregistry
java -Djava.security.policy=d:\rmi\my.policy rmi.ServerImpl
java -Djava.security.policy=d:\rmi\my.policy rmi.Client