مقدمة
لاحظ أنه من أجل حفظ الرمز ، لم يتم الإعلان عن httpservletrequest في جسم الطريقة ، وتم حقن الحفرة المحفورة مباشرة باستخدام الأسلاك التلقائية.
الخلاصة: بالنسبة لأولئك الذين يشعرون بالقلق. إعلان httpservletrequest مباشرة على متغير عضو وحدة التحكم باستخدام Autowire ، وهو مؤشر ترابط آمن!
ControllerPublic Class TestController {Autowire httpservletrequest طلب ؛ requestmapping ("/") public void test () {request.getAttribute ("uid") ؛ }}الاستنتاج على النحو الوارد أعلاه.
خلفية
هذا صحيح. منذ أن أضفت معلومات المصادقة إلى رأس الطلب في المشروع ، وبعد اعتراض المعرض للمعلومات وتجاوز التحقق ، سأضيف هوية المستخدم الحالي إلى سمة الطلب ، والتي تكون مريحة لإعادة استخدامها في طبقة وحدة التحكم.
سؤال: لماذا لا تستخدم @requestheader لاسترداده مباشرة على وحدة التحكم؟ نظرًا لأن الرأس يحتوي على بيانات مشفرة ويتطلب بعض المصادقة والحكم المعقدين ، يتم طرح هذه الخطوة مباشرة في اعتراض التنفيذ.
لذلك بعد فك التشفير ، قمت بتعيين معلومات المستخدم (مثل UID) في request.setAttribute() لاستخراجها في وحدة التحكم.
إذا كنت بحاجة إلى استخدام الطلب ، فأنت بحاجة عمومًا إلى إعلانه على الطريقة ، مثل:
النتيجة العامة حفظ (طلب httpservletrequest) {// dosomething () ؛}لذا ، إذا استخدمت UID لكل طريقة ، فلن تعلن كل طريقة عن معلمة طلب ، من أجل حفظ خطوة زائدة عن الحاجة. كتبت فئة قاعدة.
الطبقة العامة CommonController {Autowire httpservletreqeust طلب ؛ السلسلة العامة getuid () {return (string) request.getAttribute ("uid") ؛ }}في وقت لاحق ، كنت قلقًا من أنه نظرًا لأن وحدة التحكم هي المفرد ، فهل سيؤدي هذا إلى تغطية الطلب السابق للطلب السابق ، وهناك مشكلات سلامة الخيوط في ظل ظروف التزامن. لذلك طرحت سؤالاً على SegmentFault ، وقال معظم مستخدمي الإنترنت أن هناك بالفعل مشكلة في الخيوط! عنوان مشكلة SEGNOTFAULT ### عملية التحقق لأن معظم آراء مستخدمي الإنترنت هي أنه يمكنهم فقط إعلانهم من حيث الطرق ، بطبيعة الحال لا أريد التخلي عن كتابة الكثير من التعليمات البرمجية الآن ، لذلك بدأت عملية التحقق الخاصة بي. لقد وفر لي المبرمجون المتحمسين عدة حلول. منذ أن بذلت الجهود المبذولة لإثبات ذلك ، سأضع النتائج هنا ومشاركتها معك.
الطريقة 1
الطريقة الأولى هي عرض الإعلان httpservletreqeust في طريقة وحدة التحكم ، والرمز كما يلي:
requestmapping ("/test")@restControllerPublic class ctest {logger logger = loggerFactory.getLogger (getClass ()) ؛ @requestmapping ("/iiii") اختبار السلسلة العامة (طلب httpservletrequest) {logger.info (request.hashCode () + "") ؛ العودة لاغية. }}اضغط F5 في المتصفح
الإخراج
كنت في حيرة من أمري في ذلك الوقت ، ** وافقت على أن أكون سلامة الموضوع! ** أليس هذا هو نفس الطلب؟ هل تمزح معي! لقد كنت أبحث لفترة طويلة عن طلب إعادة كتابة hashcode ()!
آه ، هذه هي الحقيقة ، لأنني أضغط على F5 مع متصفحي ، وبغض النظر عن مدى صعوبة الضغط عليه ، لا يمكنني محاكاة التزامن. هذا يعادل الخادم باستخدام نفس مؤشر الترابط لمعالجة طلبي. أما بالنسبة إلى Hashcode لهذا الطلب ، وفقًا لـ JDK ، يتم حسابه بناءً على العنوان الظاهري لـ OBJ في JVM. أعتقد ما هو التالي. إذا كنت تعرف ما تريده حقًا ، سأقول لي!
يخمن
يتم إصلاح مساحة ذاكرة الطلب المطبقة من قبل كل مؤشر ترابط في الخادم عند بدء تشغيل الخادم. ثم في كل مرة أطلبها ، سيقوم بإنشاء طلب جديد في مساحة الذاكرة التي طلبها (ربما بنية مشابهة لمجموعة). (على غرار نقطة انطلاق الصفيف هو دائمًا نفس عنوان الذاكرة). ثم أبدأ طلبًا ، وسيقوم بإنشاء طلب جديد في موضع البداية ونقله إلى Servlet ويبدأ المعالجة. بعد اكتمال المعالجة ، سيتم تدميرها. ثم يتم تدمير الطلب الجديد الذي أنشأه طلبه التالي ، لذلك يبدأ من عنوان البداية. بهذه الطريقة ، سيتم شرح كل شيء!
انتهى التخمين
تحقق من التخمين:
لن أسمح له بالحصول على الوقت لتدميره ، هل يمكنني اختبار الرمز
requestmapping ("/test")@restControllerPublic class ctest {logger logger = loggerFactory.getLogger (getClass ()) ؛ requestmapping ("/ooooo") السلسلة العامة testa (طلب httpservletrequest) يلقي الاستثناء {thread.sleep (3000) ؛ logger.info (request.hashCode () + "") ؛ logger.info (reqeust.getheader ("uid") ؛ return null ؛} requestmapping ("/iiii") اختبار السلسلة العامة (httpservletrequest طلب) {logger.info (request.hashcode () + "")كما ذكر أعلاه ، أنام في الواجهة/Oooo لمدة 3 ثوان. إذا كان يشترك في عملية reqeust ، فسيقوم الطلب اللاحق بالكتابة فوق reqeust في النوم ، و uid الواردة هو عنوان الواجهة. ابدأ /oooo أولاً ثم ابدأ /iiii
الإخراج
Controller.ctest: 33 - 364716268Controller.ctest: 34 - iiiicontroller.ctest: 26 - 189213070707controller.ct: 27 - Ooooo
الخلاصة: 1. /III الذي بدأ في وقت لاحق لا يكتب البيانات السابقة /OOOO ولا توجد مشكلة سلامة مؤشر ترابط. 2. ترميز الرمز من الطلب مختلف. نظرًا لأن /OooO ، يؤدي حظر OOOO إلى حاجة مؤشر ترابط آخر إلى معالجته ، فإنه ينشئ طلبًا جديدًا بدلاً من نفس رمز Hashcode كما كان من قبل.
الجولة الثانية من التحقق
الطبقة العامة httptest {public static void main (string [] args) يلقي الاستثناء {for (int i = 300 ؛ i> 0 ؛ i--) {final int finii = i ؛ new Thread () {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 للتعامل.
الفئة العامة CommonController {// @Autowired HttpservletRequest طلب ؛ modelattribute public void bindReq (httpservletrequest request) {this.request = request ؛ } سلسلة محمية getuid () {system.out.println (request.toString ()) ؛ Return request.getAttribute ("uid") == NULL؟ NULL: (سلسلة) request.getAttribute ("uid") ؛ }}هذا لديه قضايا السلامة الموضوع! قد يغطي الطلب اللاحق الطلب السابق!
رمز التحقق
@restController@requestMapping ("/test") الفئة العامة CTEST تمتد CommonController {logger logger = loggerfactory.getLogger (getClass ()) ؛ requestmapping ("/iiii") اختبار السلسلة العامة () {logger.info (request.getheader ("uid")) ؛ العودة لاغية. }} الطبقة العامة httptest {public static void main (string [] args) يلقي الاستثناء {for (int i = 100 ؛ i> 0 ؛ i--) {final int finii = i ؛ new Thread () {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.ct: 26 - V ### 57Controller V ### 82Controller.ctest: 26 - V ### 93Controller.ctest: 26 - V ### 71Controller.ct: 26 - V ### 71Controller.ctest: 26 - V ### 71Controller.ctest: 26 - V ## 71Controller.ctest: 26 - V ### 71 Controller. V ### 71Controller.ctest: 26 - V ### 85Controller.ctest: 26 - V ### 85Controller.ctest: 26 - V ### 14Controller.ctest: 26 - V ### 47Controller.ctest: 26 - V ## 47Controller.ctest: 26 - V ### 69 Controller V ### 22Controller.ctest: 26 - V ### 55Controller.ctest: 26 - V ### 61
يمكنك أن ترى أن 57 و 71 و 85 و 47 مغطاة ، وتفقد بعض الطلبات!
القيام بذلك هو تعزيز الخيط!
الطريقة 3
استخدم CommonController باعتباره الفئة الأساسية لطلب AutoWire.
الطبقة العامة CommonController {Autowired HttpservletRequest طلب ؛ سلسلة محمية getuid () {system.out.println (request.toString ()) ؛ Return request.getAttribute ("uid") == NULL؟ NULL: (سلسلة) request.getAttribute ("uid") ؛ }}واجهة الاختبار هي نفسها كما هو مذكور أعلاه ، والنتائج مرضية! لا توجد تغطية لـ 100 طلب. لقد قمت بزيادة النطاق واختبرته خمس أو ست مرات ، ولا تغطية لآلاف الطلبات. هذا يمكن أن يثبت أنه لا توجد مشكلة سلامة مؤشر ترابط في طريقة الكتابة هذه!
شيء آخر مثير للاهتمام هو أنه بغض النظر عن مقدار التزامن المستخدم ، فإن رمز التجزئة للطلب هو نفسه دائمًا. علاوة على ذلك ، عند اختبار واجهات مختلفة في نفس وحدة التحكم ، فهذا هو نفسه. عند استخدام النوم لإجبار الكتلة ، يكون الرمز هو نفسه. ومع ذلك ، فإن رمز الهاش مختلف عند الوصول إلى وحدات تحكم مختلفة ، لذلك لم أستمر في البحث بشكل أعمق في كيفية تنفيذها.
لكن الاستنتاج قد خرج ، تمامًا كما قال المقال في البداية.
لخص
ما سبق هو المحتوى الكامل لهذه المقالة. آمل أن يكون لمحتوى هذه المقالة قيمة مرجعية معينة لدراسة أو عمل الجميع. إذا كان لديك أي أسئلة ، فيمكنك ترك رسالة للتواصل. شكرا لك على دعمك إلى wulin.com.