<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java 中 RMI 的使用

          共 9054字,需瀏覽 19分鐘

           ·

          2021-05-11 12:16


          RMI 介紹

          RMI (Remote Method Invocation) 模型是一種分布式對(duì)象應(yīng)用,使用 RMI 技術(shù)可以使一個(gè) JVM 中的對(duì)象,調(diào)用另一個(gè) JVM 中的對(duì)象方法并獲取調(diào)用結(jié)果。這里的另一個(gè) JVM 可以在同一臺(tái)計(jì)算機(jī)也可以是遠(yuǎn)程計(jì)算機(jī)。因此,RMI 意味著需要一個(gè) Server 端和一個(gè) Client 端。

          Server 端通常會(huì)創(chuàng)建一個(gè)對(duì)象,并使之可以被遠(yuǎn)程訪問。

          • 這個(gè)對(duì)象被稱為遠(yuǎn)程對(duì)象。
          • Server 端需要注冊(cè)這個(gè)對(duì)象可以被 Client 遠(yuǎn)程訪問。

          Client 端調(diào)用可以被遠(yuǎn)程訪問的對(duì)象上的方法,Client 端就可以和 Server 端進(jìn)行通信并相互傳遞信息。

          說到這里,是不是發(fā)現(xiàn)使用 RMI 在構(gòu)建一個(gè)分布式應(yīng)用時(shí)十分方便,它和 RPC 一樣可以實(shí)現(xiàn)分布式應(yīng)用之間的互相通信,甚至和現(xiàn)在的微服務(wù)思想都十分類似。

          RMI 工作原理

          正所謂 “知其然知其所以然”,在開始編寫 RMI 代碼之前,有必要了解一下 RMI 的工作原理,RMI 中 Client 端是和 Server 端是如何通信的呢?

          下圖的可以幫助我們理解RMI 的工作流程。

          RMI Connection

          從圖中可以看到,Client 端有一個(gè)被稱 Stub 的東西,有時(shí)也會(huì)被成為存根,它是 RMI Client  的代理對(duì)象,Stub 的主要功能是請(qǐng)求遠(yuǎn)程方法時(shí)構(gòu)造一個(gè)信息塊,RMI 協(xié)議會(huì)把這個(gè)信息塊發(fā)送給 Server 端。

          這個(gè)信息塊由幾個(gè)部分組成:

          • 遠(yuǎn)程對(duì)象標(biāo)識(shí)符。
          • 調(diào)用的方法描述。
          • 編組后的參數(shù)值(RMI協(xié)議中使用的是對(duì)象序列化)。

          既然 Client 端有一個(gè) Stub 可以構(gòu)造信息快發(fā)送給 Server 端,那么 Server 端必定會(huì)有一個(gè)接收這個(gè)信息快的對(duì)象,稱為 Skeleton

          它主要的工作是:

          • 解析信息塊中的調(diào)用對(duì)象標(biāo)識(shí)符和方法描述,在 Server 端調(diào)用具體的對(duì)象方法。
          • 取得調(diào)用的返回值或者異常值。
          • 把返回值進(jìn)行編組,返回給客戶端 Stub.

          到這里,一次從  Client 端對(duì) Server 端的調(diào)用結(jié)果就可以獲取到了。

          RMI 開發(fā)

          通過上面的介紹,知道了 RMI 的概念以及 RMI 的工作原理,下面介紹 RMI 的開發(fā)流程。

          這里會(huì)通過一個(gè)場(chǎng)景進(jìn)行演示,假設(shè) Client 端需要查詢用戶信息,而用戶信息存在于 Server 端,所以在 Server 端開放了 RMI 協(xié)議接口供客戶端調(diào)用查詢。

          RMI Server

          Server 端主要是構(gòu)建一個(gè)可以被傳輸?shù)念?User,一個(gè)可以被遠(yuǎn)程訪問的類 UserService,同時(shí)這個(gè)對(duì)象要注冊(cè)到 RMI 開放給客戶端使用。

          1. 定義服務(wù)器接口(需要繼承 Remote 類,方法需要拋出 RemoteException)。

            package com.wdbyte.rmi.server;

            import java.rmi.Remote;
            import java.rmi.RemoteException;


            /**
             * RMI Server
             *
             * @author www.wdbyte.com
             * @date 2021/05/08
             */

            public interface UserService extends Remote {

                /**
                 * 查找用戶
                 * 
                 * @param userId
                 * @return
                 * @throws RemoteException
                 */

                User findUser(String userId) throws RemoteException;
            }

            User 對(duì)象在步驟 3 中定義。

          2. 實(shí)現(xiàn)服務(wù)器接口(需要繼承 UnicastRemoteObject 類,實(shí)現(xiàn)定義的接口)。

            package com.wdbyte.rmi.server;

            import java.rmi.RemoteException;
            import java.rmi.server.UnicastRemoteObject;

            /**
             * @author www.wdbyte.com
             * @date 2021/05/08
             */

            public class UserServiceImpl extends UnicastRemoteObject implements UserService {

                protected UserServiceImpl() throws RemoteException {
                }

                @Override
                public User findUser(String userId) throws RemoteException {
                    // 加載在查詢
                     if ("00001".equals(userId)) {
                        User user = new User();
                        user.setName("金庸");
                        user.setAge(100);
                        user.setSkill("寫作");
                        return user;
                    }
                    throw new RemoteException("查無此人");
                }
            }
          3. 定義傳輸?shù)膶?duì)象,傳輸?shù)膶?duì)象需要實(shí)現(xiàn)序列化(Serializable)接口。

            需要傳輸?shù)念愐欢ㄒ獙?shí)現(xiàn)序列化接口,不然傳輸時(shí)會(huì)報(bào)錯(cuò)。IDEA 中如何生成 serialVersionUID,在文章末尾也附上了簡單教程。

            package com.wdbyte.rmi.server;

            import java.io.Serializable;

            /**
             *
             * @author www.wdbyte.com
             * @date 2021/05/08
             */

            public class User implements Serializable {

                private static final long serialVersionUID = 6490921832856589236L;

                private String name;
                private Integer age;
                private String skill;

                public String getName() {
                    return name;
                }

                public void setName(String name) {
                    this.name = name;
                }

                public Integer getAge() {
                    return age;
                }

                public void setAge(Integer age) {
                    this.age = age;
                }

                public String getSkill() {
                    return skill;
                }

                public void setSkill(String skill) {
                    this.skill = skill;
                }
                
                @Override
                public String toString() {
                    return "User{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        ", skill='" + skill + '\'' +
                        '}';
                }
            }
          4. 注冊(cè)( rmiregistry)遠(yuǎn)程對(duì)象,并啟動(dòng)服務(wù)端程序。

            服務(wù)端綁定了 UserService 對(duì)象作為遠(yuǎn)程訪問的對(duì)象,啟動(dòng)時(shí)端口設(shè)置為 1900。

            package com.wdbyte.rmi.server;

            import java.rmi.Naming;
            import java.rmi.registry.LocateRegistry;

            /**
             * RMI Server 端
             *
             * @author https://www.wdbyte.com
             * @date 2021/05/08
             */

            public class RmiServer {

                public static void main(String[] args) {
                    try {
                        UserService userService = new UserServiceImpl();
                        LocateRegistry.createRegistry(1900);
                        Naming.rebind("rmi://localhost:1900/user", userService);
                        System.out.println("start server,port is 1900");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }

          RMI Client

          相比 Server 端,Client 端就簡單的多。直接引入可遠(yuǎn)程訪問和需要傳輸?shù)念悾ㄟ^端口和 Server 端綁定的地址,就可以發(fā)起一次調(diào)用。

          package com.wdbyte.rmi.client;

          import java.rmi.Naming;

          import com.wdbyte.rmi.server.User;
          import com.wdbyte.rmi.server.UserService;

          /**
           * @author https://www.wdbyte.com
           * @date 2021/05/08
           */

          public class RmiClient {
              public static void main(String args[]) {
                  User answer;
                  String userId = "00001";
                  try {
                      // lookup method to find reference of remote object
                      UserService access = (UserService)Naming.lookup("rmi://localhost:1900/user");
                      answer = access.findUser(userId);
                      System.out.println("query:" + userId);
                      System.out.println("result:" + answer);
                  } catch (Exception ae) {
                      System.out.println(ae);
                  }
              }
          }

          RMI  測(cè)試

          啟動(dòng) Server 端。

          start server,port is 1900

          啟動(dòng) Client 端。

          query:00001
          result:User{name='金庸', age=100, skill='寫作'}

          如果 Client 端傳入不存在的 userId。

          java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
          java.rmi.RemoteException: 查無此人

          serialVersionUID 的生成

          IDEA 中生成 serialVersionUID,打開設(shè)置,如下圖所示勾選。

          IDEA 設(shè)置

          選中要生成 serialVersionUID 的類,按智能提示快捷鍵。

          IDEA serialVersionUID

          參考

          [1] https://docs.oracle.com/javase/tutorial/rmi/overview.html


          ---- END ----

          "未讀代碼,一線技術(shù)工具人,認(rèn)認(rèn)真真寫個(gè)文章"

          點(diǎn)個(gè)在看,加油充電~??

          瀏覽 48
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕超碰在线 | 国产性爱电影一区二区三区 | 色逼资源站 | 在线免费看不卡黄色视频 | av天堂资源在线观看 |