}
@Override
public User getUserByName(String name) throws RemoteException{
return new User(name, 654321);
}
}
这里我们构造了一个User实体,为了能实现远程传输,所以这里我们将其进行序列化:
```java
public class User implements Serializable {
private static final long serialVersionUID = 42L;
private String name;
private String passWord;
public String getName(){
return this.name;
}
public String getPassWord(){
return this.passWord;
}
public void setName(String name){
this.name = name;
}
public void setPassWord(String passWord){
this.passWord = passWord;
}
public User(String name, String passWord) {
this.name = name;
this.passWord = passWord;
}
}
需要注意的一点是,如果jdk版本低于1.5,需要手动运行rmic命令生成实现类的Stub对象,而1.5开始使用动态代理技术,已经可以自动生成Stub对象了,做完这些就可以启动服务端了:
UserHandler userHandler = null;
try {
userHandler = new UserHandlerImpl();
Naming.rebind("user", userHandler);//将当前的实例与名称为user绑定,后面客户端调用查找对应的名称
System.out.println(" RMI 服务端启动成功");
} catch (Exception e) {
System.err.println(" RMI 服务端启动失败");
e.printStackTrace();
}
构建RMI注册表
其实所谓注册表就是保存了RMI服务端启动与绑定的名称的进程,由于jdk已经把RMI代码集成到了JDK中,RMI的注册表其实不需要写任何代码,在JDK的bin目录下已经存在一个叫rmiregistry.exe的程序,不过我们需要在当前的class类路径下启动注册表(所以需要注意JAVA_HOME环境变量一定要配置成功) ,来到class类路径下,输入命令:
rmiregistry 9999
即可指定rmi的注册表在9999端口中运行,如果不指定端口,默认使用1099,当然不想让RMI的注册表在前台显示,也可以输入后台运行命令:
start rmiregistry
构建RMI客户端
前面服务端和注册表都已经运行起来了,接下来我们需要的就是客户端发起访问的请求了,需要注意的是,User实例类和UserHandler接口在客户端代码中也有一份(企业开发过程中会依赖同一份代码),所以这里的客户端调用代码如下:
try {
UserHandler handler = (UserHandler) Naming.lookup("user");//这里使用的user是服务端启动的时候绑定的名称
String passWord = handler.getUserPassWord();
String name = handler.getUserName(1);
System.out.println("name: " + name);
System.out.println("passWord: " + passWord);
System.out.println("user: " + handler.getUserByName("pdc"));
} catch (Exception e) {
e.printStackTrace();
}
这样就可以获取到服务端的远程对象的信息了,当然这里有两点需要注意:
1.这里的UserHandler实体类和服务端的UserHandler接口所在的包名需要一致,即使用的限定全类名需要一致,否则会报如下的错误:
2.我们这里获取的User实例属于引用类型,需要注意的是获取到的User实例对象也必须和服务端的包名一致,即限定全类名相同,否则,handler.getUserByName("pdc")方法调用的结果会报错,如下所示:
自定义启动RMI注册表
在本篇的结尾,我们来个彩蛋,还记得上面RMI的注册表吗?前面我们是通过JDK的exe程序启动的,那么我们能不能自己开发或者自己启动RMI注册表呢?其实是可以的,在java.rmi.registry包中有个Registry接口,并且该接口有个默认的实现类LocateRegistry,其实JDK源码中Naming类就是使用的LocateRegistry实现的注册和调用,那么我们来看看LocateRegistry的方法:
createRegistry(int port)
createRegistry(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf)
getRegistry()
getRegistry(int port)
getRegistry(String host)
getRegistry(String host, int port)
getRegistry(String host, int port, RMIClientSocketFactory csf)
可以看到这里有两个创建注册表的方法,一个只有端口,开启的默认是本机的注册表,另外一个是可以输入ip,端口,以及一些连接策略的自定义注册表,还有几个获取注册表的方法,很明显这里提供了注册表的创建和调用的方法,同样的我们之前的服务端代码只要稍微改动一下,如下:
UserHandler userHandler = null;
Registry registry = LocateRegistry.createRegistry(9999);;
try {
userHandler = new UserHandlerImpl();
registry.rebind("user", userHandler);//将当前的实例与名称为user绑定,后面客户端调用查找对应的名称
System.out.println(" RMI 服务端启动成功");
} catch (Exception e) {
System.err.println(" RMI 服务端启动失败");
e.printStackTrace();
}
很明显申明一下注册表,并且使用注册表替换Naming来绑定服务实例即可,客户端亦是如此,修改后的代码如下:
try {
Registry registry=LocateRegistry.getRegistry("127.0.0.1",9999);
UserHandler handler = (UserHandler) registry.lookup("user");//这里使用的user是服务端启动的时候绑定的名称
String passWord = handler.getUserPassWord();
String name = handler.getUserName(1);
System.out.println("name: " + name);
System.out.println("passWord: " + passWord);
System.out.println("user: " + handler.getUserByName("pdc"));
} catch (Exception e) {
e.printStackTrace();
}
这样就完成了和之前一样的服务发布与调用过程了
今日福利(点击下方文字超链接获取)
如果你的技术提升遇到瓶颈了,或者缺高级Android进阶视频学习提升自己,这有大量大厂面试题为你面试做准备!
点击Android 学习,面试文档,视频收集大整理获取
结尾
这不止是一份面试清单,更是一种”被期望的责任“,因为有无数个待面试者,希望从这篇文章中,找出通往期望公司的”钥匙“,所以上面每道选题都是结合我自身的经验于千万个面试题中经过艰辛的两周,一个题一个题筛选出来再次对好答案和格式做出来的,面试的答案也是再三斟酌,深怕误人子弟是小,影响他人仕途才是大过,也希望您能把这篇文章分享给更多的朋友,让他帮助更多的人,帮助他人,快乐自己,最后,感谢您的阅读。
由于细节内容实在太多啦,在这里我花了两周的时间把这些答案整理成一份文档了,在这里只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!