序文
コードを保存するために、Httpservletrequestはメソッド本体で宣言されておらず、掘削されたピットにAutowireを直接注入したことに注意してください。
結論:不安な人のために。 @autowireを使用して、コントローラーのメンバー変数でhttpservletrequestを直接宣言します。
@controllerpublic class testController {@autowire httpservletrequest request; @RequestMapping( "/")public void test(){request.getAttribute( "uid"); }}結論は上記のとおりです。
背景
これは本当です。プロジェクトのリクエストの責任者に認証情報を追加し、インターセプターが情報をインターセプトして検証を渡した後、現在のユーザーのIDをリクエストの属性に追加します。これは、コントローラー層で再利用するのに便利です。
質問:@RequestHeaderを使用してコントローラーで直接取得してみませんか?ヘッダーには暗号化されたデータが含まれており、複雑な認証と判断が必要なため、このステップは実行のためにインターセプターに直接投げ込まれます。
そのため、復号化後、ユーザー情報(UIDなど)をrequest.setAttribute()に設定して、コントローラーに抽出します。
リクエストを使用する必要がある場合は、通常、次のようなメソッドで宣言する必要があります。
public result save(httpservletrequest request){// dosomething();}したがって、各メソッドにUIDを使用する場合、冗長なステップを保存するために、すべての方法が要求パラメーターを宣言するわけではありません。私は基本クラスを書きました。
Public Class CommonController {@autowire httpservletreqeust request; public string getUid(){return(string)request.getAttribute( "uid"); }}その後、コントローラーはシングルトンであるため、これにより以前のリクエストをカバーするその後のreqeustが得られることを心配しました。そこで私はセグメントフォールトについて質問しましたが、ほとんどのネチズンは、実際にスレッドの問題があると言いました!セグメントフォールトの問題アドレス###検証プロセスほとんどのネチズンの意見は、方法でのみ宣言できるということであるため、当然、今すぐ多くのコードを書くことをあきらめたくないので、確認プロセスを開始しました。熱狂的なプログラマーは、いくつかのソリューションを提供してくれました。私はそれを証明するために努力したので、私はここに結果を置いてあなたと共有します。
方法1
最初の方法は、コントローラーメソッドで宣言httpservletreqeustを表示することです。コードは次のとおりです。
@RequestMapping( "/test")@restcontrollerpublic class ctest {logger logger = loggerFactory.getLogger(getClass()); @RequestMapping( "/iiii")public string test(httpservletrequest request){logger.info(request.hashcode() + ""); nullを返します。 }}ブラウザでF5を押します
出力
当時私は混乱していました**私はスレッドの安全であることに同意しました! **これは同じリクエストではありませんか?私をからかってるの! HashCode()を書き換えるリクエストを長い間探していました!
ああ、これは真実です。なぜなら、私はブラウザでF5を押し、どんなに難しいかを押しても、同時性をシミュレートすることはできません。これは、同じスレッドを使用してリクエストを処理するサーバーと同等です。この要求のハッシュコードについては、JDKによると、JVMのOBJの仮想アドレスに基づいて計算されます。次は何だと思いますか。あなたが本当に欲しいものを知っているなら、私は私に言います!
推測
サーバーの各スレッドによって適用されるリクエストのメモリスペースは、サーバーの起動時に固定されます。その後、私が要求するたびに、彼は要求したメモリスペースに新しいリクエストを作成します(おそらくアレイに似た構造)。 (配列の開始点と同様に、常に同じメモリアドレスです)。次に、リクエストを開始すると、彼は開始位置で新しいリクエストを作成し、サーブレットに渡して処理を開始します。処理が完了すると、破壊されます。次に、彼の次のリクエストによって作成された新しいリクエストが破壊されるため、開始アドレスから開始します。このようにして、すべてが説明されます!
推測が終了しました
推測を確認します:
私は彼にそれを破壊する時間をさせません、私はコードをテストできますか
@RequestMapping( "/test")@restcontrollerpublic class ctest {logger logger = loggerFactory.getLogger(getClass()); @RequestMapping( "/oooo")public string testa(httpservletrequest request)throws exception {swrep.sleep(3000); logger.info(request.hashcode() + ""); logger.info(reqeust.getheader( "uid"); return null;} @requestmapping( "/iiii")public string test(httpservletrequest request){ogger.info(request.hashcode() + ""); reqeust.gether(uid ");上記のように、私はインターフェイス/ooooで3秒間寝ます。それがreqeustを共有する場合、その後の要求は睡眠中のreqeustを上書きし、着信UIDはインターフェイスアドレスです。最初に /oooooを開始してから、 /iiiiを開始します
出力
controller.ctest:33-364716268Controller.ctest:34 -iiiicontroller.ctest:26-1892130707Controller.ctest:27 -ooooです
結論:1。後に開始された /IIIは、以前の /ooooのデータを上書きせず、スレッドの安全性の問題はありません。 2。リクエストのハッシュコードは異なります。 /ooooブロッキングにより別のスレッドが処理する必要があるため、以前と同じハッシュコードの代わりに新しいリクエストが作成されます。
検証の第2ラウンド
public class httptest {public static void main(string [] args)throws exception {for(int i = 300; i> 0; i-){final int finali = i; new shood(){@override public void run(){system.out.println( "v ###" + finali); httprequest.get( "http:// localhost:8080/test/iiii?").header( "uid"、 "v ###" + finali).send(); } }。始める(); }}}シミュレートされた同時条件下では、ヘッダーのUID300はオーバーライドせずに完全に受け入れます
したがって、このように、スレッドの安全性の問題はありません。
方法2
CommonControllerでは、@modelattributeを使用してハンドルを使用します。
Public Class CommonController {// @Autowired Protected HTTPSERVLETREQUESTリクエスト。 @modelattribute public void bindreq(httpservletrequest request){this.request = request; } protected string getUid(){system.out.println(request.toString()); return request.getAttribute( "uid")== null? null:(string)request.getAttribute( "uid"); }}これにはスレッドの安全性の問題があります!後続の要求は、前の要求をカバーする場合があります!
検証コード
@retycontroller@requestMapping( "/test")public class ctestはcommoncontroller {logger logger = loggerFactory.getLogger(getClass()); @RequestMapping( "/iiii")public string test(){logger.info(request.getheader( "uid")); nullを返します。 }} public class httptest {public static void main(string [] args)throws exception {for(int i = 100; i> 0; i--){final int finali = i; new shood(){@override public void run(){system.out.println( "v ###" + finali); httprequest.get( "http:// localhost:8080/test/iiii").header( "uid"、 "v ###" + finali).send(); } }。始める(); }}}部分出力の結果が傍受されました
Controller.Ctest:26 -V ### 52Controller.Ctest:26 -V ### 13Controller.ctest:26 -V ### 57Controller.ctest:26 -V ### 57Controller.ctest:26 -V ### 21Controller.Ctest:26 -V V ### 82Controller.ctest:26 -V ### 93Controller.ctest:26 -V ### 71Controller.ctest:26 -V ### 71Controller.Ctest:26 -V ### 71Controller.Ctest:26 -V ### 71Controller.Ctest:26 -V ### 71 -Contest:26 -V ### 71 -Contest V ### 71Controller.ctest:26 -V ### 85Controller.ctest:26 -V ### 85Controller.ctest:26 -V ### 14Controller.Ctest:26 -V ### V ### 22Controller.Ctest:26 -V ### 55Controller.ctest:26 -V ### 61
57、71、85、および47がカバーされており、一部のリクエストが失われていることがわかります!
そうすることはスレッドインスケールです!
方法3
CommonControllerを基本クラスとして使用して、Autowireを要求します。
Public Class CommonController {@Autowired Protected HTTPSERVLETREQUESTリクエスト。 protected string getUid(){system.out.println(request.toString()); return request.getAttribute( "uid")== null? null:(string)request.getAttribute( "uid"); }}テストインターフェイスは上記と同じであり、結果は満足しています! 100のリクエストのカバレッジはありません。私は範囲を増やし、それを5〜6回テストしましたが、数千のリクエストのカバレッジはありませんでした。これは、この書き込み方法にスレッドの安全性の問題がないことを証明できます!
もう1つの興味深いことは、どれだけの並行性を使用しても、リクエストのハッシュコードは常に同じであるということです。さらに、同じコントローラー内の異なるインターフェイスをテストする場合、それは同じです。睡眠を使用してブロックを強制する場合、ハッシュコードは同じです。ただし、ハッシュコードは異なるコントローラーにアクセスするときに異なるため、実装方法を深く掘り下げ続けませんでした。
しかし、記事が最初に言ったように、結論は出ています。
要約します
上記は、この記事のコンテンツ全体です。この記事の内容には、すべての人の研究や仕事に特定の参照値があることを願っています。ご質問がある場合は、メッセージを残してコミュニケーションをとることができます。 wulin.comへのご支援ありがとうございます。