发表于: 2016-09-13 00:00:04

2 2201


今天完成的事情:刚刚已经将近写完了日报,不小心退出了,以前都是保存的,但这次并没有,不想说什么了。

每写一段提交,在修改。

今天学习了rmi。总结一下。

1、首先一句话了解一下什么是RMI

RMI:远程方法调用(Remote Method Invocation)。能够让在某个java虚拟机上的对象像调用本地对象一样调用另一个java 虚拟机中的对象上的方法。

本质RMI的本质就是实现在不同JVM之间的调用,它的实现方法就是在两个JVM中各开一个StubSkeleton,二者通过socket通信来实现参数和返回值的传递。

局限性RMI对服务器的IP地址和端口依赖很紧密,但是在开发的时候不知道将来的服务器IP和端口如何,但是客户端程序依赖这个IP和端口。这也是RMI的局限性之一。这个问题有两种解决途径:一是通过DNS来解决,二是通过封装将IP暴露到程序代码之外。RMI的局限性之二是RMI是Java语言的远程调用,两端的程序语言必须是Java实现,对于不同语言间的通讯可以考虑用Web Service或者公用对象请求代理体系(CORBA)来实现。


2rmi图形简介


3RMI远程调用步骤:

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等





返回列表 返回列表
评论

    分享到