发表于: 2018-01-29 22:20:17
1 829
今天完成的事情:(一定要写非常细致的内容,比如说学会了盒子模型,了解了Margin)
使用原生java RMI完成同JVM下项目的分离.
原生有两种方式:
方式1,使用Naming类.
首先我们需要有一个服务接口,并且继承Remote接口,抛出相应的RemoteException.
package rmi.in;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* @author Arike
* Create_at 2018/1/29 14:43
*/
public interface RmiTest extends Remote {
String getNum() throws RemoteException;
}
然后是服务实现类,需要继承RmiTest并且实现UnicastRemoteObject接口
package rmi.imp;
import rmi.in.RmiTest;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* @author Arike
* Create_at 2018/1/29 14:45
*/
public class RmiTestImpl extends UnicastRemoteObject implements RmiTest {
private static final long serialVersionUID = 1L;
public RmiTestImpl() throws RemoteException {
super();
}
@Override
public String getNum() throws RemoteException {
return String.valueOf(Math.random()*10);
}
}
使用Naming类注册注册表需要自己手动启动rmiregistry工具开启端口,如果是maven项目需要进入到classes文件夹下启动命令行工具,查询列表需要看到本项目的字节码文件.然后执行 rmiregistry (默认是开启1099端口,如果需要修改,执行rmiregistry 端口号)
启动之后可以执行我们写好的服务端类
package rmi.run;
import rmi.imp.RmiTestImpl;
import rmi.in.RmiTest;
import java.rmi.Naming;
/**
* @author Arike
* Create_at 2018/1/29 14:59
*/
public class Start {
public static void main(String[] args) {
RmiTest rmi = null;
try{
rmi = new RmiTestImpl();
Naming.rebind("rmi",rmi);
System.out.println("rmi server is ready");
}catch(Exception e){
e.printStackTrace();
}
}
}
执行之后
可以看到我们的服务属于一直运行状态.
然后去客户端, 客户端需要有一个相同全限定命名的接口,接口中的方法要与服务端相同, 用以调用服务端的远程实现.
客户端类:
package rmi.client;
import rmi.in.RmiTest;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
/**
* @author Arike
* Create_at 2018/1/29 15:35
*/
public class Start {
public static void main(String[] args) {
try {
RmiTest rmi = (RmiTest) Naming.lookup("rmi");
System.out.println(rmi.getNum());
} catch (NotBoundException | MalformedURLException | RemoteException e) {
e.printStackTrace();
}
}
}
直接使用Naming.lookup获取到远程对象(实际是一个中介,并不是远程实现类本身),大致就是下面这么一个思路.
运行试一下.
可以看到已经成功调用服务端实现类的方法.
服务端实现2,使用Registry接口.使用Registry接口就可以不用再自己手动使用rmiregistry工具注册接口了,可以直接在代码中实现.
接口,实现类和Naming方式相同,只有服务实现有区别.
package rmi.run;
import rmi.imp.RmiTestImpl;
import rmi.in.RmiTest;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
/**
* @author Arike
* Create_at 2018/1/29 16:38
*/
public class Start2 {
public static void main(String[] args) {
RmiTest rmi = null;
Registry registry =null;
try{
rmi = new RmiTestImpl();
registry = LocateRegistry.createRegistry(1099);
registry.rebind("rmi",rmi);
System.out.println("RMI服务已启动");
}catch(Exception e){
e.printStackTrace();
}
}
}
启动:
客户端的使用方法和Naming方法一样.
明天计划的事情:(一定要写非常细致的内容)
将远程RMI跑通.
遇到的问题:(遇到什么困难,怎么解决的)
然后关于跨机器,我做了很多demo,尝试了很多不同的方式生成服务端,只要跨IP分离,我尝试了网上的很多的列子都以失败告终.我明天打算好好看一下IBM给的介绍,非要把这个远程分离完成了.
但是通过一天的折腾,还是了解到了关于跨IP的问题出在哪里,有一篇博客中提到其实RMI跨IP实际上是因为跨到了不同的JVM,在不同的java虚拟机里面要访问同一个实现类,就需要将这个实现类的信息跨域发送到需要使用的客户端的JVM中,也就是我刚才那张图里的stub(存根,骨架), 我们在本地JVM其实并没有用到这个东西.
查询的资料都是以前老版本,1.3之前生成这个中间骨架的教程,是使用dos命令行生成,但是在jdk1.8上不好使,各种报错.
收获:(通过今天的学习,学到了什么知识)
java原生的东西其实才是我们运行一切的根本,好好深入了发现还是很有用.
今天在IBM官方给的一些文档中了解到了serializable的一些更深层次的东西.
https://www.ibm.com/developerworks/cn/java/j-lo-serial/
可以学习一下.
评论