此异常主要是客户端的包路径与服务端的包路径不一致,改成一致就ok了。
这是因为在编译class文件的时候,这个class文件内部已经包含了package com.cn;这样的内容,如果在部署的时候,不严格按照这个目录部署的话,服务器就会找不到。
发表于: 2018-02-08 15:29:49
2 821
今天完成的事情
1.今天被一个问题gank了,非常神奇的问题,搞了一上午也没解决。。过程就不说了,很神奇,很玄学的一个问题。
2.开始学习rmi
首先rmi是什么:
Java RMI 指的是远程方法调用 (Remote Method Invocation)。它是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法。可以用此方法调用的任何对象必须实现该远程接口。
这个说的也很清晰,就是远程调用。
然后开始照着教程来写了一个Demo:在我已有的task3项目中新建一个RMI目录:
这个直接是项目结构了,接下来是各个类的内容:
首先是接口
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* 定义一个远程接口,必须继承Remote接口,其中需要远程调用的方法必须抛出RemoteException异常
*/
public interface IHello extends Remote {
/**
* 简单的返回“Hello World!"字样
* @return 返回“Hello World!"字样
* @throws java.rmi.RemoteException
*/
public String helloWorld() throws RemoteException;
/**
* 一个简单的业务方法,根据传入的人名返回相应的问候语
* @param someBodyName 人名
* @return 返回相应的问候语
* @throws java.rmi.RemoteException
*/
public String sayHelloToSomeBody(String someBodyName) throws RemoteException;
}
注释都写的很清楚,我就不描述了
然后是接口的实现:
这块儿的小疑问就是这个构造方法不是很清楚为什么要写。
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* 远程的接口的实现
*/
public class HelloImpl extends UnicastRemoteObject implements IHello {
/**
* 因为UnicastRemoteObject的构造方法抛出了RemoteException异常,因此这里默认的构造方法必须写,必须声明抛出RemoteException异常
*
* @throws RemoteException
*/
public HelloImpl() throws RemoteException {
}
/**
* 简单的返回“Hello World!"字样
*
* @return 返回“Hello World!"字样
* @throws java.rmi.RemoteException
*/
public String helloWorld() throws RemoteException {
return "Hello World!";
}
/**
* 一个简单的业务方法,根据传入的人名返回相应的问候语
*
* @param someBodyName 人名
* @return 返回相应的问候语
* @throws java.rmi.RemoteException
*/
public String sayHelloToSomeBody(String someBodyName) throws RemoteException {
return "你好," + someBodyName + "!";
}
}
然后是创建Server类:
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
/**
* 创建RMI注册表,启动RMI服务,并将远程对象注册到RMI注册表中。
*/
public class HelloServer {
public static void main(String args[]) {
try {
//创建一个远程对象
IHello rhello = new HelloImpl();
//本地主机上的远程对象注册表Registry的实例,并指定端口为8888,这一步必不可少(Java默认端口是1099),必不可缺的一步,缺少注册表创建,则无法绑定对象到远程注册表上
LocateRegistry.createRegistry(8888);
//把远程对象注册到RMI注册服务器上,并命名为RHello
//绑定的URL标准格式为:rmi://host:port/name(其中协议名可以省略,下面两种写法都是正确的)
Naming.bind("rmi://localhost:8888/RHello",rhello);
// Naming.bind("//localhost:8888/RHello",rhello);
System.out.println(">>>>>INFO:远程IHello对象绑定成功!");
} catch (RemoteException e) {
System.out.println("创建远程对象发生异常!");
e.printStackTrace();
} catch (AlreadyBoundException e) {
System.out.println("发生重复绑定对象异常!");
e.printStackTrace();
} catch (MalformedURLException e) {
System.out.println("发生URL畸形异常!");
e.printStackTrace();
}
}
}
然后是客户端测试:
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
/**
* 客户端测试,在客户端调用远程对象上的远程方法,并返回结果。
*/
public class HelloClient {
public static void main(String args[]){
try {
//在RMI服务注册表中查找名称为RHello的对象,并调用其上的方法
IHello rhello =(IHello) Naming.lookup("rmi://localhost:8888/RHello");
System.out.println(rhello.helloWorld());
System.out.println(rhello.sayHelloToSomeBody("熔岩"));
} catch (NotBoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
接下来就是使用这些了,要先注册才能使用,于是先运行Server类
接下来再运行Client类:
ok,对不对
如果不注册的话就是这样:
接下来突发奇想,既然是远程调用,那么我在其他项目中整一个Client类跑跑?
然后我就这样做了,结果碰到了问题
于是我在task4中加上了接口,实现类以及客户端测试类,结果碰到了问题:
一直报错找不到我的接口类,这就很困扰,于是去百度了一下,找到了一篇博客,解决了我的问题:
https://www.cnblogs.com/leiyf/p/5564360.html
此异常主要是客户端的包路径与服务端的包路径不一致,改成一致就ok了。
这是因为在编译class文件的时候,这个class文件内部已经包含了package com.cn;这样的内容,如果在部署的时候,不严格按照这个目录部署的话,服务器就会找不到。
于是我想了想,然后将task4的包名啥的改成了和task3一样的:
,然后测试方法里面名字改成这是task4,运行效果:
可以发现是实现了远程调用的。哦哈哈
3.有点膨胀,直接去搞了节点一,惨败。。。
死活是空,进不去方法,好难受啊,无奈请教师兄,师兄说我的理解出现了问题,于是复原项目,重新开始。。
因为在新的项目中又service和impl,我怀疑会不会我这种结果根本没用到rmi?
于是开始验证一次,在服务端新建两个impl对象,一个发送出去,一个不发送:
IHello rhello = new HelloImpl();
IHello hh = new HelloImpl();
System.out.println(rhello);
System.out.println(hh);
//本地主机上的远程对象注册表Registry的实例,并指定端口为8888,这一步必不可少(Java默认端口是1099),必不可缺的一步,缺少注册表创建,则无法绑定对象到远程注册表上
LocateRegistry.createRegistry(8888);
//把远程对象注册到RMI注册服务器上,并命名为RHello
//绑定的URL标准格式为:rmi://host:port/name(其中协议名可以省略,下面两种写法都是正确的)
Naming.bind("rmi://localhost:8888/RHello",rhello);
就这样打印输出的哈希值:
然后是在rmi调用那也进行同样操作:
IHello hh = new HelloImpl();
IHello rhello =(IHello) Naming.lookup("rmi://localhost:8888/RHello");
System.out.println(rhello);
System.out.println(hh);
然后打印输出的哈希值:
这样的话就可以知道,是取到值了的。也就是说用到了rmi。
今天遇到的问题
在项目整合rmi的时候,发生故障,很难受,而且早晨的问题也很神奇
今天的收获
知道了rmi的一点点知识
明天计划的事情
明天争取在项目中实现rmi吧
评论