まずGitHubのアドレスを添付:https://github.com/kosamino/netty-root/tree/master/ym-netty-rpc
RPCの実装では、リモートプロキシオブジェクトを介してローカルコールリモートサービスです。インターネットアプリケーションシナリオ、柔軟性、スケーラビリティのサービスモノマーの極端な不足、大規模な開発チームは、管理を開発することは容易ではありません。だから、多くの場合、このサービスは、我々はサービスとしてSOAについて話している垂直モジュール、に応じて分割されます。ダイレクトサービスビジネスインタラクションシステムとのスプリットシステムの後、多くの場合、通信のためのRPCフレームワークに依存しています。
通常のRPCサーバーは、JARパッケージ、対応するインターフェースを提供対応するインタフェースを取得するために、プロキシインスタンスのRPCフレーム機能を介してクライアントを、データパッケージとの通信を処理するコールが透明です。
まず、コールフロー
まず、最初に以下のように、プロセスであり、どのような次のRPCを分析します:
私たちは、3つの部分、ユーザー、ネッティークライアント、ネッティーサーバーが含まれています。
- ユーザーが通話を開始します。
- ネッティークライアントの要求をパッケージング。
- クライアント要求は、(オブジェクト-ByteBuf)シリアライズされます。
- サーバーの後のシーケンスにメッセージを送信します。
- サーバーは、デコードされた特定の中にデシリアライズオブジェクトを要求します。
- サーバは、クライアントから送信された要求を解析し、準備し、結果を返します。
- サーバはByteBufとしてシリアル化結果を返します。
- クライアントは、リターン情報を受信し、
- 抗オブジェクト得られた情報のクライアントの欄に情報を返します。
- クライアントが要求を完了するために、ユーザーの呼び出し元に結果を返します。
技術を含む第二に、
上記のように、全体のプロセスは、このプロセス技術は、それを使用するために必要という簡単なRPCフレームワークはありますか?
- ダイナミックエージェント:、Javaプロキシ技術を介してデータ通信および包装のためのInvocationHandlerプロトコルをプロキシオブジェクトを取得します。
- シリアライゼーション、デシリアライゼーションの
- ネットワーク通信:通信が得ることができる優れたIO性能ベースのクライアントおよびサーバネッティーさん
- 反射:メソッドのサーバーインスタンスに対応するクライアント要求パラメータは、反射技術を呼び出すことによって達成されます。
技術の一部の使用に続いて、我々のコード断片分析。
1、動的プロキシ
// TODO代理对象 QueryStudentClientクライアント=(QueryStudentClient)rpcProxyFactory。factoryRemoteInvoker( "localhost"を、8080、QueryStudentClient。クラス); パブリック クラス RpcProxyFactory <T> { パブリック T factoryRemoteInvoker(文字列ホスト、INT ポート、クラスインターフェース){ // 动态代理 リターン(T)たとえば、Proxy.newProxyInstance(interfaces.getClassLoader()、新しいクラス[] {}インターフェイス、 新しいRemoteInvocationHandler(ホスト、ポート、インタフェース))。 } } パブリック クラス RemoteInvocationHandlerの実装InvocationHandler { プライベート文字列のホスト。 プライベート int型のポート。 プライベートクラスのインターフェイス。 公共 RemoteInvocationHandler(文字列ホスト、INT ポート、クラスインターフェース){ この .host = ホスト。 この .port = ポート。 この .interfaces = インターフェイス。 } パブリックオブジェクトを呼び出し(オブジェクトプロキシ、メソッドのメソッド、オブジェクト[]引数)がスローされたThrowable { // TODO封装消息 RpcContext rpcContext = 新規の RpcContext()。 rpcContext.setClassName(interfaces.getName())。 rpcContext.setMethodName(method.getName())。 rpcContext.setTypes(method.getParameterTypes())。 rpcContext.setParams(引数)。 試す{ // 通讯 NettyClientクライアント= 新しいNettyClient(ホスト、ポート)。 クライアント。接続(); リターンクライアント。sendData(rpcContext)。 } キャッチ(例外e){ } 戻り ヌル。 } }
2、シリアライズ、デシリアライゼーションの
@Overrideは、 保護された ボイド initChannel(のSocketChannel SC)がスロー例外{ ハンドラ = 新しいNettyClientHandler(ラッチ)。 HessianEncode hessionEncodeHandler = 新しいHessianEncode(); HessianDecode hessionDecodeHandler = 新しいHessianDecode(); LengthFieldPrepender fieldEncoderは = 新しい LengthFieldPrepender(2 )。 // LengthFieldBasedFrameDecoder fieldDecoder =新しいLengthFieldBasedFrameDecoder(65535、0、2、0、2); // 出站 sc.pipeline()addLast(。fieldEncoder) 。sc.pipeline()addLast(hessionEncodeHandler ;) // ための新しい新しい使用して、安全でないマルチスレッドのインバウンドLengthFieldBasedFrameDecoder、 。sc.pipeline()addLast(新新 LengthFieldBasedFrameDecoder(65535 、 0を、2、0、2 )); sc.pipeline()addLast(hessionDecodeHandler); sc.pipeline()addLast(ハンドラ);. }
パイプラインで見ることができるが追加されました:パケット長は、本明細書シリアライゼーションヘッセ行列を使用し、ハンドラの処理半ヘッダパケットの粘度、配列ツール、逆シリアル化ツールに基づいて設定されます。
図3に示すように、反射技術
公共 ボイド channelRead(ChannelHandlerContext CTX、オブジェクトMSG)はスロー例外{ RpcContextモデル = (RpcContext)MSGと、 クラスclazz = nullを。 もし(Registry.map.containsKey(model.getClassName())){ clazz = Registry.map.get(model.getClassName() )。 } オブジェクト結果 = NULL ; 試す{ メソッド法(model.getTypes()、model.getMethodName())= clazz.getMethod。 結果=method.invoke(clazz.newInstance()、model.getParams())。 }キャッチ(例外e){ e.printStackTrace(); } ctx.channel()writeAndFlush(結果)。 }
あなたは、登録したクラスのマップレジストリを得るために、クライアントに基づいて、クラスのネームサーバが来て見て、その後、戻り値の型、メソッド名、パラメータに応じて反射を呼び出すことができます。
三、ネッティー非同期協調的問題を呼び出すスレッド
クライアントを達成ネッティー使用すると、ノートにポイントを送信します。
応答を受信するイベントとchannelReadイベントの後に書かれネッティーのwriteAndFlushを呼び出して、書き込みデータチャネルがされて非同期で実行注意を払うスレッド協力する必要があるので、。Countdowlacthは、受信した応答オブジェクトを取得するために行く前にchannelread待機を実行した後、メインスレッドを達成するために使用することができます。
/ ** *クライアントデータ送信方法 * @param rpcRequest * @return * @throws InterruptedExceptionある * / 公共のsendDataは(RpcContext rpcRequest)オブジェクトスローInterruptedExceptionある{ ChannelFuture CF2 = この .getChannelFutureを(); // シングルトンはChannelFutureを取得したオブジェクト 場合(!cf.channel()= NULL && cf.channel()のisActive()){ LATCH = 新しい新たCountDownLatch(1。); clientInitializer.reLatch(LATCH)。 cf.channel()writeAndFlush(rpcRequest);. latch.await(); } 戻りclientInitializer.getServerResult(); } } // クライアントが完全にサーバーからデータを読み込み、 @Override 公共 のボイド channelRead(ChannelHandlerContext CTX、オブジェクトMSG)スロー例外{ スーパー.channelRead(CTX、MSG); 結果 = MSG; のSystem.out.println( "戻りデータが読み込まれた" ); latch.countDown(); }
これにより、スレッドの連携を実現するそれ以外の場合は、結果を返すことができません呼び出します。残りの詳細は、完全なコードを参照してください。