发表于: 2016-09-13 00:00:04
2 2201
今天完成的事情:刚刚已经将近写完了日报,不小心退出了,以前都是保存的,但这次并没有,不想说什么了。
每写一段提交,在修改。
今天学习了rmi。总结一下。
1、首先一句话了解一下什么是RMI:
RMI:远程方法调用(Remote Method Invocation)。能够让在某个java虚拟机上的对象像调用本地对象一样调用另一个java 虚拟机中的对象上的方法。
本质:RMI的本质就是实现在不同JVM之间的调用,它的实现方法就是在两个JVM中各开一个Stub和Skeleton,二者通过socket通信来实现参数和返回值的传递。
局限性:RMI对服务器的IP地址和端口依赖很紧密,但是在开发的时候不知道将来的服务器IP和端口如何,但是客户端程序依赖这个IP和端口。这也是RMI的局限性之一。这个问题有两种解决途径:一是通过DNS来解决,二是通过封装将IP暴露到程序代码之外。RMI的局限性之二是RMI是Java语言的远程调用,两端的程序语言必须是Java实现,对于不同语言间的通讯可以考虑用Web Service或者公用对象请求代理体系(CORBA)来实现。
2、rmi图形简介:
3、RMI远程调用步骤:
1、 生成一个远程接口 2、 实现远程对象(服务器端程序)3、 生成占位程序和骨干网(服务器端程序)
4、 编写服务器程序 5、 编写客户程序 6、 注册远程对象 7、 启动远程对象
demo1
1、定义一个远程接口,必须继承Remote接口,需要远程调用的方法必须抛出RemoteException异常
public interface IHello extends Remote {
public String helloWorld() throws RemoteException;
public String sayHelloToSomeBody(String someBodyName) throws RemoteException;
}
2、接口的实现类
public class HelloImpl extends UnicastRemoteObject implements IHello {
//因为UnicastRemoteObject的构造方法抛出了RemoteException异常,因此这里默认的构造方法必须写,
//必须声明抛出RemoteException异常
public HelloImpl() throws RemoteException {
}
public String helloWorld() throws RemoteException {
return "Hello World!";
}
public String sayHelloToSomeBody(String someBodyName) throws RemoteException {
return "你好," + someBodyName + "!";
}
}
3、创建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();
}
}
}
4、客户端测试,在客户端调用远程对象上的远程方法,并返回结果。
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();
}
}
先启动servce
======INFO:远程IHello对象绑定成功!
在启动客户端
Hello World!
你好,会飞的煤气罐!
demo2
在Eclipse里面创建一个server 端的project。然后,创建一个接口,这个接口是你要向client端开放的方法定义。它叫做:UserManagerInterface,而且必须继承Remote接口。
public interface UserManagerInterface extends Remote{
public String getUserName() throws RemoteException;
public Account getAdminAccount() throws RemoteException;
}
为了证明RMI中,“面向对象”或者是“无缝传递JAVA Object”是何等简单,我们需要定义一个Account类,该类是一个Bean,必须实现implements Serializable序列化接口。这是一个可以在client和server传输的可序列化对象。
public class Account implements Serializable,Cloneable{
private String username;
private String password;
============set/get方法===========================================
/需要实现你已经开放的接口
public class UserManagerImpl implements UserManagerInterface {
public UserManagerImpl() throws RemoteException {
}
public String getUserName() throws RemoteException {
return "cuimingyang";
}
public Account getAdminAccount() throws RemoteException {
Account account=new Account();
account.setUsername("cuimy");
account.setPassword("123456");
return account;
}
}
定义一个主程序入口,注册你已经实现的RMI接口,包括开放端口等。其实很简单:
把我们的接口名称,命名为“userManager”,方便client进行调用
public class Entry {
public static void main(String []args) throws AlreadyBoundException, RemoteException{
UserManagerImpl userManager=new UserManagerImpl();
UserManagerInterface userManagerI=(UserManagerInterface)UnicastRemoteObject.exportObject(userManager,0);
// Bind the remote object's stub in the registry
Registry registry = LocateRegistry.createRegistry(2001);
registry.rebind("userManager", userManagerI);
System.out.println("server is ready");
}
}
Server端的代码已经全部写完,但是还要把bean类(Account)和接口类(UserMangerInterface)打包成jar,以便可以在下面导入进client端的项目中。
导入我们的接口jar以后,可以开始编写一个client端的主程序,并调用server端的方法。
public class Entry2 {
public static void main(String[] args) {
try {
Registry registry = LocateRegistry.getRegistry("localhost",2001);
UserManagerInterface userManager = (UserManagerInterface) registry.lookup("userManager");
System.out.println(""+userManager.getAdminAccount().getUsername()
+userManager.getAdminAccount().getPassword());
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
}
}
先启动servce
server is ready
在启动客户端
cuimy123456
Spring与RMI集成实现远程访问
使用Spring对RMI的支持,可以非常容易地构建你的分布式应用。在服务端,可以通过Spring的org.springframework.remoting.rmi.RmiServiceExporter可以暴露你的服务;在客户端,通过org.springframework.remoting.rmi.RmiProxyFactoryBean可以使用服务端暴露的服务,非常方便。这种C/S模型的访问方式,可以屏蔽掉RMI本身的复杂性,如服务端Skeleton和客户端Stub等的处理细节,这些对于服务开发和服务使用的人员来说,都是透明的,无需过度关注,集中精力开发你的商业逻辑。
服务端发布服务
我们定义了服务接口,服务端实现该服务接口来完成其复杂的逻辑,客户端可以通过该接口调用服务端暴露的服务
public interface AccountService {
int queryBalance(String mobileNo);
String shoopingPayment(String mobileNo, byte protocol);
}
服务实现
public class MobileAccountServiceImpl implements AccountService {
private static final Logger LOG = Logger.getLogger(MobileAccountServiceImpl.class);
public int queryBalance(String mobileNo) {
if (mobileNo != null)
return 100;
return 0;
}
public String shoopingPayment(String mobileNo, byte protocol)
String str = "Your mobile number is "+ mobileNo + ", protocol type is " + protocol;
LOG.info("Message is: " + str.toString());
return str;
}
}
服务端发布服务,供客户端进行(远程方法)调用,Spring配置server.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="serviceExporter" class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="serviceName" value="MobileAccountService" />
<property name="service" ref="accountService" />
<property name="serviceInterface" value="com.cuimy.service.AccountService" />
<property name="registryPort" value="8087" />
<property name="servicePort" value="8088" />
</bean>
<bean id="accountService" class="com.cuimy.service.serviceimpl.MobileAccountServiceImpl" />
</beans>
上面配置,指定了暴露的服务的名称,通过serviceName属性注入到RmiServiceExporter中,服务名称为MobileAccountService,客户端通过该服务名称就能够进行调用。
下面启动服务端,发布服务
public class RmiServer {
public static void main(String[] args) throws InterruptedException {
new ClassPathXmlApplicationContext("server.xml");
客户端调用服务
客户端配置client.xml如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="mobileAccountService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://localhost:8087/MobileAccountService" />
<property name="serviceInterface"
value="com.cuimy.service.AccountService"/>
</bean></beans>
配置中,将一个serviceUrl和serviceInterface注入给RmiProxyFactoryBean,即可进行远程方法调用。
public class RmiClient {
private static final Logger LOG = Logger.getLogger(RmiClient.class);
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("client.xml");
System.out.println("client启动了");
AccountService accountService = (AccountService) ctx.getBean("mobileAccountService");
String result = accountService.shoopingPayment("13800138000", (byte) 5);
LOG.info(result);
System.out.println(result);
}
}
服务端启动:
service已经启动!!!
客户端启动
client启动了
Your mobile number is 13800138000, protocol type is 5
============================================================================
聚合
如果我们想一次构建多个项目模块,那我们就需要对多个项目模块进行聚合
<modules>
<module>模块一</module>
<module>模块二</module>
<module>模块三</module>
</modules>
例如:对项目的Hello、HelloFriend、MakeFriends这三个模块进行聚合
<modules>
<module>../Hello</module>
<module>../HelloFriend</module>
<module>../MakeFriends</module>
</modules>
继承
继承为了消除重复,我们把很多相同的配置提取出来,例如:grouptId,version等
评论