远程调用,Java—RMI和Spring—RMIfangs
Java RMI 指的是远程方法调用 (Remote Method Invocation)。它是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法。JVM 可以位于相同或不同计算机上,在多个 JVM 中,一个 JVM 可以调用存储在其它 JVM 的对象的方法。
RMI 是 Java 编程语言里,一种用于实现远程过程调用的应用程序编程接口,它是客户机上运行的程序可以调用远程服务器上的对象,远程方法调用特性使 Java 编程人员能够在网络环境中分布操作。RMI 全部的宗旨就是尽可能简化远程接口对象的使用。
Java RMI 极大地依赖于接口,在需要创建一个远程对象的时候,程序员通过传递一个接口来隐藏底层的实现细节,客户端得到的远程对象句柄正好与本地的根代码连接,由后者负责透过网络通信。这样一来,程序员只需关心如何通过自己的接口句柄发送消息。
Spring 的优势除了 IOC 和 AOP 外,还提供了简易的服务抽象。如远程 rmi 调用。 远程方法调用,即 Java RMI(javaRemote Method Invocation)。 RMI 底层封装了 Socket 反射机制。java 语言当中分布式的基础!!!实现 java 之间的互相访问。RMI 本质就是使用代理类来封装 Socket 的通信细节!!RMI 的 API 帮助我们创建一个代理类及其内容!!使用这个代理类实例就可以远程通信。
具体代码实现如下:
服务器端:
1).Remote 接口:每一个要暴露出去的 java 类,都需要实现 Remote 接口,并且所有的方法必须抛出RemoteException
2).UnicastRemoteObject 类:服务端程序的实现方案之一就是继承这个类,无参构造器也要抛出 RemoteException
3).LocateRegistry 类创建能在特定接口接受调用远程对象注册服务程序。
第一个类:接口定义:
1.定义远程接口,必须继承Remote接口,
2其中所有需要远程调用的方法都必须抛出RemoteException异常
第二个类:接口具体实现服务类:
1、继承 UnicastRemoteObject
2、提供 无参构造 对外声明 RemoteException
第三个类:测试类
1、 注册端口:生成远程对象注册表Registry的实例,并指定端口为8888(默认端口是1099)
2、对外发布rmi服务:把远程对象注册到RMI注册服务器上,并命名
客户端与服务端必须声明相同接口
客户端:
第一个类:接口定义(与服务器接口一致)
1.接口继承 Remote
2.对外服务方法声明 RemoteException 异常
第二个类:客户端查找并调用远程服务
1、查找对为发布的rmi:在RMI服务注册表中查找被命名的的对象,并调用其上的方法
创建java项目
服务器端:
1、定义接口HelloImpl
package com.mage.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
*
* 1接口继承Remote
* 2方法必须抛出RemoteException异常
* (每一个要暴露出去的 java 类,都需要实现 Remote 接口,并且所有的方法必须抛出RemoteException)
* @author Marry
*
*/
public interface HelloImpl extends Remote {
public String sayHello(String msg) throws RemoteException;
}
2、定义实体类
package com.mage.rmi;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* 1服务器类继承UnicastRemoteObject,并实现HelloImpl接口
* 2实现接口中的方法,提供无参构造器
* @author Marry
*
*/
public class Service01 extends UnicastRemoteObject implements HelloImpl{
private static final long serialVersionUID = 1L;
protected Service01() throws RemoteException {}
@Override
public String sayHello(String msg) throws RemoteException {
return "服务器接到消息:"+msg;
}
}
3、服务器测试类
package com.mage.rmi;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
/**
* 1注册端口
* 2对外发布rmi服务
* @author Marry
*
*/
public class Test {
public static void main(String[] args)
throws RemoteException, MalformedURLException, AlreadyBoundException {
//注册端口
LocateRegistry.createRegistry(1220);
//对外发布服务
Naming.bind("rmi://localhost:1220/hello", new Service01());
}
}
注意:客户端与服务端必须声明相同接口
客户端
1、定义接口类
package com.mage.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
*
* 1接口继承Remote
* 2方法必须抛出RemoteException异常
* (每一个要暴露出去的 java 类,都需要实现 Remote 接口,并且所有的方法必须抛出RemoteException)
* @author Marry
*
*/
public interface HelloImpl extends Remote {
public String sayHello(String msg) throws RemoteException;
}
2、客户端测试类
package com.mage.rmi;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
/**
*
* 1接收服务器发布的rmi服务
* @author Marry
*
*/
public class Test {
public static void main(String[] args) throws MalformedURLException, RemoteException, NotBoundException
{
HelloImpl helloImpl =(HelloImpl) Naming.lookup("rmi://localhost:1220/hello");
//向服务器发送信息
System.out.println(helloImpl.sayHello("你这个小兔崽子"));
}
}
运行结果:
注意事项:
1、客户端和服务端创建的接口必须相同,客户端需要通过相同的接口去调用服务端的方法
2、客户端和服务端的端口号以及传过来的参数必须相同,"rmi://localhost:1220/hello"
1、使用spring_RMI实现远程调用不需要继承接口和指定的类,也不需要抛出异常,需要配置xml文件
服务器端:
1:定义一个接口,创建要实现的方法
2:实现上面的接口,重写接口中的方法
3:配置XML文件
4:测试类,获取xml文件
客户端:
1:定义一个接口,创建要实现的方法
2:配置xml文件
3:测试类:获取xml文件,获取接口bean,通过接口bean调用方法
创建一个Maven.project项目,两个子类Maven.modle(一个客户端,一个服务端)
服务器端:
1、配置pom.xml文件
org.springframework
spring-context
4.1.6.RELEASE
2、创建接口类
package com.mage.rmi;
import java.rmi.RemoteException;
import org.springframework.stereotype.Component;
@Component
public interface ChatImpl {
public String sayHello(String msg);
}
3、实现接口类
package com.mage.rmi;
import org.springframework.stereotype.Service;
@Service
public class HelloService implements ChatImpl{
@Override
public String sayHello(String msg) {
System.out.println("服务器接收消息是"+msg);
return "服务器:"+msg;
}
}
4、配置spring.xml文件
5、服务器测试类
package com.mage.rmi;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
//加载spring.xml文件
new ClassPathXmlApplicationContext("spring.xml");
}
}
注意:客户端和服务端的接口必须相同
客户端:
1、配置pom.xml文件
org.springframework
spring-context
4.1.6.RELEASE
2、创建接口类
package com.mage.rmi;
import java.rmi.RemoteException;
public interface ChatImpl {
public String sayHello(String msg);
}
3、配置spring.xml文件
4、 定义一个拿到接口的类,通过接口调用方法
package com.mage.rmi;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class HelloService {
@Resource
private ChatImpl chatImpl;
public void test() {
System.out.println(chatImpl.sayHello("小垃圾"));
}
}
5、客户端测试类
package com.mage.rmi;
import java.rmi.RemoteException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) throws RemoteException {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
HelloService hello = applicationContext.getBean(HelloService.class);
hello.test();
}
}
运行结果:
注意事项:
1、客户端和服务端创建的接口必须相同,客户端需要通过相同的接口去调用服务端的方法
2、客户端和服务端的端口号以及传过来的参数必须相同,"rmi://localhost:1220/hello"
3、通过接口属性去调用到实现类的方法