<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    2012年12月26日

    簡(jiǎn)單的遠(yuǎn)程調(diào)用實(shí)現(xiàn)

    最近看到一個(gè)遠(yuǎn)程調(diào)用的簡(jiǎn)單實(shí)現(xiàn),于是加上自己的理解分享給大家。
    遠(yuǎn)程調(diào)用是典型的CS模型,Server端提供服務(wù),客戶端調(diào)用得到結(jié)果

    先看服務(wù)端提供服務(wù)的方法
     1 /**
     2      * 提供服務(wù)
     3      *
     4      * @param service 服務(wù)實(shí)現(xiàn)
     5      * @param port    端口(可以雙發(fā)約定)
     6      * @throws Exception
     7      */
     8     public static void provide(final Object service, final int port) throws Exception {
     9         //參數(shù)檢查
    10         if (service == null) {
    11             throw new IllegalArgumentException("The service can't be null!");
    12         }
    13         if (port > 65535) {
    14             throw new IllegalArgumentException("The host can't greater than 65535!");
    15         }
    16         //開(kāi)啟一個(gè)ServerSocket接收請(qǐng)求
    17         ServerSocket serverSocket = new ServerSocket(port);
    18         //死循環(huán)等待請(qǐng)求
    19         while (true) {
    20             //接受到請(qǐng)求,獲取socket
    21             final Socket socket = serverSocket.accept();
    22             try {
    23                 //開(kāi)啟一個(gè)線程處理
    24                 new Thread(new Runnable() {
    25                     @Override
    26                     public void run() {
    27                         try {
    28                             try {
    29                                 //重socket中獲取輸入流
    30                                 ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
    31                                 try {
    32                                     //獲取方法名
    33                                     String methodName = ois.readUTF();
    34                                     //獲取方法參數(shù)數(shù)組
    35                                     Class[] methodParameterTypes = (Class[]) ois.readObject();
    36                                     //獲取參數(shù)值數(shù)組
    37                                     Object[] arguments = (Object[]) ois.readObject();
    38                                     //根據(jù)方法名和方法參數(shù)獲取方法(根據(jù)方法名和方法參數(shù)可以唯一定位到一個(gè)方法)
    39                                     Method method = service.getClass().getMethod(methodName, methodParameterTypes);
    40                                     if (method == null) {
    41                                         throw new NoSuchMethodException();
    42                                     }
    43                                     //執(zhí)行方法
    44                                     Object result = method.invoke(service, arguments);
    45                                     System.out.println("Method:" + methodName + ";Arguments:" + arguments + "  invoke!");
    46                                     //獲取socket輸出流
    47                                     ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
    48                                     try {
    49                                         //輸出結(jié)果
    50                                         oos.writeObject(result);
    51                                     } finally {
    52                                         oos.close();
    53                                     }
    54                                 } finally {
    55                                     ois.close();
    56                                 }
    57                             } finally {
    58                                 socket.close();
    59                             }
    60                         } catch (Exception e) {
    61                             //記個(gè)日志啥的
    62                             e.printStackTrace();
    63                         }
    64                     }
    65                 }).start();
    66             } catch (Exception e) {
    67                 //記個(gè)日志啥的
    68                 e.printStackTrace();
    69             }
    70         }
    71     }

    然后是消費(fèi)的方法

    **
         * 消費(fèi)服務(wù)
         *
         * @param clazz 接口類
         * @param host  發(fā)布服務(wù)機(jī)器的host
         * @param port  發(fā)布服務(wù)機(jī)器的port
         * @return
         */
        public static Object consume(final Class clazz, final String host, final int port) {
            //參數(shù)檢查
            if (clazz == null) {
                throw new IllegalArgumentException("The clazz can't be null!");
            }
            if (host == null || host.isEmpty()) {
                throw new IllegalArgumentException("The host can't be null or empty!");
            }
            if (port > 65535) {
                throw new IllegalArgumentException("The host can't greater than 65535!");
            }
            //生成代理,每次調(diào)用方法其實(shí)是調(diào)用遠(yuǎn)程的服務(wù)
            Object proxy = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {
                    //建立socket鏈接
                    Socket socket = new Socket(host, port);
                    try {
                        //獲取輸出流
                        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                        try {
                            String methodName = method.getName();
                            Class[] methodParameterTypes = method.getParameterTypes();
                            //輸出要調(diào)用的方法名
                            oos.writeUTF(methodName);
                            //輸出要調(diào)用的方法參數(shù)列表
                            oos.writeObject(methodParameterTypes);
                            //輸出要調(diào)用的方法參數(shù)
                            oos.writeObject(arguments);
                            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                            try {
                                //獲取結(jié)果
                                Object result = ois.readObject();
                                //可能返回的對(duì)象是異常
                                if (result instanceof Throwable) {
                                    throw (Throwable) result;
                                }
                                return result;
                            } finally {
                                ois.close();
                            }
                        } finally {
                            oos.close();
                        }
                    } finally {
                        socket.close();
                    }
                }
            });
            return proxy;
        }

    一般端口可以雙方約定,而host可以采用configServer的方法解決,也就是開(kāi)啟一個(gè)服務(wù),當(dāng)啟動(dòng)一個(gè)服務(wù)的時(shí)候到configServer注冊(cè)一下(服務(wù)名+host),如果是多臺(tái)服務(wù)器提供服務(wù),host就是一個(gè)list,調(diào)用方發(fā)起調(diào)用的時(shí)候首先到configServer根據(jù)服務(wù)名獲取host列表,然后選一個(gè)host發(fā)起調(diào)用!configServer的優(yōu)點(diǎn)是可以做到很多控制,比如流量控制,權(quán)重控制,調(diào)用host列表維護(hù)(死掉就剔除,重試機(jī)制)等等,這樣調(diào)用方不用關(guān)心我調(diào)用的是哪臺(tái)機(jī)器,只用關(guān)心我調(diào)用哪個(gè)方法。但也有壞處,一旦configServer掛掉了.......(其實(shí)也可以通過(guò)MS或調(diào)用方本地緩存調(diào)用列表解決)。

    一般由調(diào)用方提供一個(gè)接口包(算是一個(gè)雙方的約定),接口類中定義了提供發(fā)提供的方法
    如我們發(fā)布一個(gè)簡(jiǎn)單的服務(wù)
    1 public interface Girl {
    2     //提供服務(wù)
    3     String server(String name);
    4 }

    實(shí)現(xiàn)
    1 public class GirlImpl implements Girl{
    2     @Override
    3     public String server(String name) {
    4         return name+"亞美爹";
    5     }
    6 }
    發(fā)布服務(wù)
    這里你可以寫在一個(gè)main方法中,也可以配置一個(gè)Spring的bean,并配置init方法,然后在init方法中開(kāi)啟
    1  Girl beautifulGirl=new GirlImpl();
    2         try {
                    //在本機(jī)的1111端口上開(kāi)啟Girl的服務(wù)
    3             Utils.provide(beautifulGirl, 1111);
    4         } catch (Exception e) {
    5             e.printStackTrace();
    6         }
    消費(fèi)
    1  try {
    2             //從此你就獲得了一個(gè)漂亮妹子,她可以給你提供各種服務(wù)
    3             Girl beautifulGirl= (Girl)Utils.consume(Girl.class, "127.0.0.1", 3333);
    4             //你可以來(lái)一個(gè)循環(huán),或者來(lái)一個(gè)死循環(huán),一直哈哈
    5             beautifulGirl.server("yourName");
    6         } catch (Exception e) {
    7             e.printStackTrace();
    8         }

    總結(jié):
    其實(shí)遠(yuǎn)程調(diào)用也就是獲取服務(wù)的一個(gè)代理,每當(dāng)你調(diào)用服務(wù)的方法事,他都會(huì)想服務(wù)方傳去方法,方法參數(shù)列表,參數(shù),前兩個(gè)用于唯一確定一個(gè)方法,后一個(gè)用于方法調(diào)用。
    這里實(shí)現(xiàn)的很簡(jiǎn)答,當(dāng)然還有很復(fù)雜的,比如Spring的實(shí)現(xiàn),淘寶的HSF等等


    以上為個(gè)人理解,如果有錯(cuò)的地方,歡迎指正。

    posted @ 2012-12-26 19:25 Evan.lee 閱讀(1964) | 評(píng)論 (0)編輯 收藏

    <2012年12月>
    2526272829301
    2345678
    9101112131415
    16171819202122
    23242526272829
    303112345

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿

    隨筆檔案

    搜索

    最新評(píng)論

    主站蜘蛛池模板: 亚洲国产精品一区二区第一页| 国产成人高清精品免费观看| 国产∨亚洲V天堂无码久久久| 日韩高清在线免费看| 99re在线这里只有精品免费| 免费一级毛suv好看的国产网站 | 免费很黄无遮挡的视频毛片| 亚洲性一级理论片在线观看| 国产亚洲一区二区三区在线观看| 国产精品免费看香蕉| 成年在线网站免费观看无广告| 18禁男女爽爽爽午夜网站免费| 免费萌白酱国产一区二区三区| 免费无遮挡无码视频在线观看| 亚洲AV成人无码久久WWW| 亚洲视频无码高清在线| 亚洲人成777在线播放| 亚洲熟妇无码久久精品| 亚洲人成电影在在线观看网色| 亚洲色偷偷偷鲁综合| 亚洲午夜福利AV一区二区无码| 亚洲成aⅴ人片久青草影院| 国产又粗又长又硬免费视频 | 亚洲第一成年免费网站| 亚洲天然素人无码专区| 亚洲人成77777在线观看网| 亚洲在成人网在线看| 亚洲色欲或者高潮影院| 亚洲成a人片毛片在线| 亚洲精品视频免费看| 亚洲黄色网址在线观看| 久久亚洲日韩看片无码| 亚洲黄色免费网址| 亚洲最新在线视频| 亚洲中文久久精品无码1 | 免费看的黄色大片| 精品久久久久久久免费人妻 | 亚洲一区在线观看视频| 亚洲精品二三区伊人久久| 亚洲 日韩经典 中文字幕| 亚洲一久久久久久久久|