
Java RMI:Java长途要领挪用,即Java RMI(Java Remote Method Invocation)是Java编程言语里,一种用于完成长途历程挪用的运用顺序编程接口。
它使客户机上运转的顺序可以挪用长途效劳器上的对象。长途要领挪用特征使Java编程职员可以在收集环境中散布操纵。RMI悉数的主旨就是尽量简化长途接口对象的运用。
我们晓得长途历程挪用(Remote Procedure Call, RPC)可以用于一个历程挪用另一个历程(很可能在另一个长途主机上)中的历程,从而供应了历程的散布才能。Java 的 RMI 则在 RPC 的基础上向前又迈进了一步,即供应散布式对象间的通讯。
RMI(Remote Method Invocation)为长途要领挪用,是许可运转在一个Java假造机的对象挪用运转在另一个Java假造机上的对象的要领。
这两个假造机可所以运转在雷同盘算机上的差别历程中,也可所以运转在收集上的差别盘算机中。
【JavaRMI】
一、事情道理
RMI能让一个Java顺序去挪用收集中另一台盘算机的Java对象的要领,那末挪用的效果就像是在本机上挪用一样。浅显的讲:A机械上面有一个class,经由过程长途挪用,B机械挪用这个class 中的要领。
RMI,长途要领挪用(Remote Method Invocation)是Enterprise JavaBeans的支柱,是竖立散布式Java运用顺序的轻易门路。RMI是非常轻易运用的,然则它非常的壮大。
RMI的基础是接口,RMI构架基于一个重要的道理:定义接口和定义接口的细致完成是离开的。下面我们经由过程细致的例子,竖立一个简朴的长途盘算效劳和运用它的客户顺序
二、RMI包含部份:
1、长途效劳的接口定义
2、长途效劳接口的细致完成
3、桩(Stub)和框架(Skeleton)文件
4、一个运转长途效劳的效劳器
5、一个RMI定名效劳,它许可客户端去发明这个长途效劳
6、类文件的供应者(一个HTTP或许FTP效劳器)
7、一个须要这个长途效劳的客户端顺序
三、RMI的用处?
RMI的用处是为散布式Java运用顺序之间的长途通讯供应效劳,供应散布式效劳。
现在重要运用时封装在各个J2EE项目框架中,比方Spring,EJB(Spring和EJB均封装了RMI手艺)
在Spring中完成RMI:
①在效劳器端定义效劳的接口,定义特定的类完成这些接口;
②在效劳器端运用org.springframework.remoting.rmi.RmiServiceExporter类来注册效劳;
③在客户端运用org.springframework.remoting.rmi.RmiProxyFactoryBean来完成长途效劳的代办功用;
④在客户端定义接见与效劳器端效劳接口雷同的类
四、RMI的范围?
RMI现在运用Java长途音讯交流协定JRMP(Java Remote Messaging Protocol)举行通讯。JRMP是专为Java的长途对象制订的协定,因为JRMP是专为Java对象制订的,因而,RMI关于用非Java言语开发的运用体系的支撑不足。
不能与用非Java言语誊写的对象举行通讯(意义是只支撑客户端和效劳器端都是Java顺序的代码的长途挪用)。
五、RMI的运用范围?
因为客户机和效劳器都是运用Java编写的,两者平台兼容性的要求仅仅是两边都运转在版本兼容的Java假造机上。
六、RMI挪用长途要领的参数和返回值
当挪用长途对象上的要领时,客户机除了可以将原始范例的数据作为参数一外,还可以将对象作为参数来通报,与之相对应的是返回值,可以返回原始范例或对象,这些都是经由过程Java的对象序列化(serialization)手艺来完成的。(换而言之:参数或许返回值假如是对象的话必需完成Serializable接口)
七、 RMI运用顺序的基础模子
八、RMI体系构造
桩/框架(Stub/Skeleton)层:客户端的桩和效劳器端的框架;
长途援用(remote reference)层:处置惩罚长途援用行动
传送层(transport):衔接的竖立和治理,以及长途对象的跟踪
九、 RMI类和接口(完成一个简朴RMI须要用到的类)。
(一) Remote接口:是一个不定义要领的标记接口
Public interface Remote{}
在RMI中,长途接口声清楚明了可以从长途Java假造机中挪用的要领集。长途接口满足以下要求:
1、长途接口必需直接或间接扩大Java.rmi.Remote接口,且必需声明为public,除非客户端于长途接口在统一包中
2、在长途接口中的要领在声明时,除了要抛出与运用顺序有关的一场以外,还必需包含RemoteException(或它的超类,IOExcepion或Exception)非常
3、在长途要领声明中,作为参数或返回值声明的长途对象必需声明为长途接口,而非该接口的完成类。
(二) RemoteObject抽象类完成了Remote接口和序列化Serializable接口,它和它的子类供应RMI效劳器函数。
(三) LocateRegistry final()类用于获得特定主机的指导长途对象注册效劳器顺序的援用(即建立stub),或许建立能在特定端口吸收挪用的长途对象注册效劳顺序。
效劳器端:向其他客户机供应长途对象效劳
SomeService servcie=……;//长途对象效劳
1、Registry registry=LocateRegisty.getRegistry();//Registry是个接口,他继续了Remote,此要领返回当地主机在默许注册表端口 1099 上对长途对象 Registry 的援用。
2、getRegistry(int port) 返回当地主机在指定 port 上对长途对象 Registry 的援用;
3、getRegistry(String host) 返回指定 host 在默许注册表端口 1099 上对长途对象 Registry 的援用;
4、getRegistry(String host, int port) 返回指定的 host 和 port 上对长途对象 Registry 的援用
5、registry.bind(“I serve”,service);// bind(String name,Remote obj) 绑定对此注册表中指定 name 的长途援用。name : 与该长途援用相干的称号 obj : 对长途对象(通常是一个 stub)的援用
6、unbind(String name)移除注册表中指定name的绑定。
7、rebind(String name,Remote obj)从新绑定,假如name已存在,然则Remote不一样则替代,假如Remote一样则抛弃现有的绑定
8、lookup(String name) 返回注册表中绑定到指定 name 的长途援用,返回Remote
9、String[] list() 返回在此注册表中绑定的称号的数组。该数组将包含一个此注册表中挪用此要领时绑定的称号快照。
客户机端:向效劳器供应响应的效劳要求。
Registry registry=LocateRegisty.getRegistry();
SomeService servcie=(SomeService)registry.lookup(“I serve”);
Servcie.requestService();
(四) Naming类和Registry类相似。
客户端:
Naming.lookup(String url) url 花样以下"rmi://localhost/"+长途对象援用
效劳器端:
Registry registry=LocateRegistry.createRegistry(int port); Naming.rebind(“service”,service);
(五) RMISecurityManager类
在RMI援用顺序中,假如没有设置平安治理器,则只能从当地类途径加载stub和类,这可以确保运用顺序不受由长途要领挪用所下载的代码损害
在从长途主机下载代码之前必需实行以下代码来装置RMISecurityManager:
System.setSecurityManager(new RMISecurityManager());
十、demo开发
为了编写一个demo,我们分为两部份,一部份是server端的代码,一部份是client端的代码,client端的代码重要是为了运用server端的代码。固然这个代码是非常简朴的,只是为了申明问题,实际的运用会使比较复杂的。
(一) 我们的目标
竖立一个server端的java project,包含长途端的代码,定义接口,定义接口完成,然后在竖立一个client端的java project,经由过程RMI运用远端效劳中的要领。
(二) 我们的代码构造
(三) 长途效劳代码
1. 长途效劳的接口定义
第一步就是竖立和编译效劳接口的Java代码。这个接口定义了一切的供应长途效劳的功用,下面是源顺序:
UserManagerInterface.java
package cn.com.tt.rmiserver.stub; import java.rmi.Remote; import java.rmi.RemoteException; import cn.com.tt.rmiserver.bean.Account; public interface UserManagerInterface extends Remote{ public String getUserName() throws RemoteException; public Account getAdminAccount() throws RemoteException; }
接口必需继续Remote类,每个定义地要领都要抛出RemoteException非常对象。
2. 接口的细致完成
第二步就是关于上面的接口举行完成:
UserManagerImp.java
package cn.com.tt.rmiserver; import java.rmi.RemoteException; import cn.com.tt.rmiserver.stub.UserManagerInterface; import cn.com.tt.rmiserver.bean.Account; public class UserManagerImp implements UserManagerInterface { public UserManagerImp() throws RemoteException { } private static final long serialVersionUID = -3111492742628447261L; public String getUserName() throws RemoteException{ return "TT"; } public Account getAdminAccount() throws RemoteException{ Account account=new Account(); account.setUsername("TT"); account.setPassword("123456"); return account; } }
3. 定义一个bean,完成implements Serializable序列化接口。也就是可以在client和server端举行传输的可序列化对象。
Account.java
package cn.com.tt.rmiserver.bean; import java.io.Serializable; public class Account implements Serializable,Cloneable{ private static final long serialVersionUID = -1858518369668584532L; private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
4. 定义server端的主顺序进口。
Entry.java
package cn.com.tt.rmiserver.entry; import java.rmi.AlreadyBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; import cn.com.tt.rmiserver.UserManagerImp; import cn.com.tt.rmiserver.stub.UserManagerInterface; public class Entry { public static void main(String []args) throws AlreadyBoundException, RemoteException{ UserManagerImp userManager=new UserManagerImp(); UserManagerInterface userManagerI=(UserManagerInterface)UnicastRemoteObject.exportObject(userManager,0); // Bind the remote object's stub in the registry Registry registry = LocateRegistry.createRegistry(2002); registry.rebind("userManager", userManagerI); System.out.println("server is ready"); } }
(四) client端代码
1、把Server端的Account类和接口UserManagerInterface 导出Export成jar包,定名为:RmiServerInterface.jar。导入到client中。
2、项目——右键——Export——java——jar file——next——挑选Account类和接口UserManagerInterface——定名为:RmiServerInterface.jar以下图:
3. 新建一个java Project,导入jar包,编写客户端代码。
4. 代码
ClientEntry.java
package weiblog.rmi; import java.rmi.NotBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import cn.com.tt.rmiserver.stub.UserManagerInterface; public class ClientEntry { public static void main(String []args){ try { Registry registry = LocateRegistry.getRegistry("localhost",2004); UserManagerInterface userManager = (UserManagerInterface)registry.lookup("userManager"); System.out.println("用户名是"+userManager.getAdminAccount().getUsername() +"暗码"+userManager.getAdminAccount().getPassword()); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NotBoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
5. 先运转效劳器端代码, 然后运转客户端代码,就会显现运转效果,客户端可以运转屡次,每次都可以获得效劳器端的对象。假如要再次运转客户端代码就须要变动端口号,假如不变动就会显现端口号被占用。
更多java学问请关注java基础教程栏目。
以上就是Java RMI图文详解(附示例)的细致内容,更多请关注ki4网别的相干文章!