คำนำ
โปรดทราบว่าในการบันทึกรหัส HttpservletRequest ไม่ได้ถูกประกาศในตัววิธีการและหลุมเจาะถูกฉีดโดยตรงด้วย autoWire
สรุป: สำหรับผู้ที่กังวล ประกาศ httpservletrequest โดยตรงบนตัวแปรสมาชิกคอนโทรลเลอร์โดยใช้ @autowire ซึ่งเป็นเธรดที่ปลอดภัย!
@ControllerPublic คลาส testController {@autowire httpservletrequest คำขอ; @RequestMapping ("/") การทดสอบโมฆะสาธารณะ () {request.getAttribute ("uid"); -ข้อสรุปดังกล่าวข้างต้น
พื้นหลัง
นี่เป็นเรื่องจริง เนื่องจากฉันเพิ่มข้อมูลการรับรองความถูกต้องลงในส่วนหัวของคำขอในโครงการและหลังจากการสกัดกั้นข้อมูลและผ่านการตรวจสอบฉันจะเพิ่มตัวตนของผู้ใช้ปัจจุบันลงในแอตทริบิวต์ของคำขอซึ่งสะดวกสำหรับการนำกลับมาใช้ใหม่ในชั้นคอนโทรลเลอร์
คำถาม: ทำไมไม่ใช้ @requestheader เพื่อดึงข้อมูลโดยตรงบนคอนโทรลเลอร์? เนื่องจากส่วนหัวมีข้อมูลที่เข้ารหัสและต้องการการตรวจสอบความถูกต้องและการตัดสินที่ซับซ้อนขั้นตอนนี้จะถูกโยนลงในตัวดักเพื่อดำเนินการโดยตรง
ดังนั้นหลังจากถอดรหัสฉันตั้งค่าข้อมูลผู้ใช้ (เช่น UID) เป็น request.setAttribute() เพื่อแยกมันในคอนโทรลเลอร์
หากคุณต้องการใช้คำขอโดยทั่วไปคุณจะต้องประกาศในวิธีการเช่น:
บันทึกผลลัพธ์สาธารณะ (คำขอ httpservletrequest) {// dosomething ();};ดังนั้นถ้าฉันใช้ UID สำหรับแต่ละวิธีจะไม่ทุกวิธีจะประกาศพารามิเตอร์คำขอเพื่อบันทึกขั้นตอนที่ซ้ำซ้อนหรือไม่ ฉันเขียนชั้นเรียนฐาน
คลาสสาธารณะ CommonController {@autowire httpservletreqeust คำขอ; สตริงสาธารณะ getUid () {return (string) request.getAttribute ("uid"); -ต่อมาฉันกังวลว่าเนื่องจากคอนโทรลเลอร์เป็นซิงเกิลตันจะส่งผลให้เกิด reqeust ที่ตามมาซึ่งครอบคลุมคำขอก่อนหน้านี้และมีปัญหาด้านความปลอดภัยของด้ายภายใต้เงื่อนไขการเกิดขึ้นพร้อมกัน ดังนั้นฉันจึงถามคำถามเกี่ยวกับ SegmentFault และชาวเน็ตส่วนใหญ่บอกว่ามีปัญหาการทำเกลียวแน่นอน! ที่อยู่ปัญหา SegmentFault ### กระบวนการตรวจสอบเนื่องจากความคิดเห็นของชาวเน็ตส่วนใหญ่คือพวกเขาสามารถประกาศพวกเขาในแง่ของวิธีการเท่านั้นฉันไม่ต้องการเลิกเขียนโค้ดมากในตอนนี้ดังนั้นฉันจึงเริ่มกระบวนการตรวจสอบของฉัน โปรแกรมเมอร์ที่กระตือรือร้นได้ให้วิธีแก้ปัญหาหลายอย่างแก่ฉัน เนื่องจากฉันได้พยายามพิสูจน์มันฉันจะใส่ผลลัพธ์ที่นี่และแบ่งปันกับคุณ
วิธีที่ 1
วิธีแรกคือการแสดงการประกาศ httpservletreqeust ในวิธีการควบคุมรหัสมีดังนี้:
@RequestMapping ("/test")@restControllerPublic คลาส ctest {logger logger = loggerFactory.getLogger (getClass ()); @RequestMapping ("/iiii") การทดสอบสตริงสาธารณะ (คำขอ httpservletRequest) {logger.info (request.hashCode () + ""); คืนค่า null; -กด F5 ในเบราว์เซอร์
เอาท์พุท
ฉันสับสนในเวลานั้น ** ฉันตกลงที่จะปลอดภัยด้าย! ** นี่เป็นคำขอเดียวกันหรือ? คุณล้อเล่นฉัน! ฉันค้นหามาเป็นเวลานานเพื่อขอให้เขียน HashCode () ใหม่!
อ่านี่คือความจริงเพราะฉันกด F5 ด้วยเบราว์เซอร์ของฉันและไม่ว่าฉันจะกดมันยากแค่ไหนฉันก็ไม่สามารถจำลองการเกิดขึ้นพร้อมกันได้ เทียบเท่ากับเซิร์ฟเวอร์โดยใช้เธรดเดียวกันเพื่อประมวลผลคำขอของฉัน สำหรับ HashCode ของคำขอนี้ตาม JDK จะคำนวณตามที่อยู่เสมือนจริงของ OBJ ใน JVM ฉันเดาว่าเกิดอะไรขึ้นต่อไป ถ้าคุณรู้ว่าคุณต้องการอะไรฉันจะบอกฉัน!
เดา
พื้นที่หน่วยความจำของคำขอที่ใช้โดยแต่ละเธรดในเซิร์ฟเวอร์ได้รับการแก้ไขเมื่อเซิร์ฟเวอร์เริ่มต้นขึ้น จากนั้นทุกครั้งที่ฉันร้องขอเขาจะสร้างคำขอใหม่ในพื้นที่หน่วยความจำที่เขาร้องขอ (อาจเป็นโครงสร้างที่คล้ายกับอาร์เรย์) (คล้ายกับจุดเริ่มต้นของอาร์เรย์เป็นที่อยู่หน่วยความจำเดียวกันเสมอ) จากนั้นฉันเริ่มคำขอและเขาจะสร้างคำขอใหม่ที่ตำแหน่งเริ่มต้นและส่งผ่านไปยัง Servlet และเริ่มการประมวลผล หลังจากการประมวลผลเสร็จสิ้นมันจะถูกทำลาย จากนั้นคำขอใหม่ที่สร้างขึ้นโดยคำขอต่อไปของเขาจะถูกทำลายดังนั้นจึงเริ่มจากที่อยู่เริ่มต้น ด้วยวิธีนี้ทุกอย่างจะถูกอธิบาย!
การเดาเสร็จแล้ว
ตรวจสอบการคาดเดา:
ฉันจะไม่ปล่อยให้เขามีเวลาทำลายมันฉันสามารถทดสอบรหัสได้ไหม
@RequestMapping ("/test")@restControllerPublic คลาส ctest {logger logger = loggerFactory.getLogger (getClass ()); @RequestMapping ("/oooo") สตริงสาธารณะ testa (คำขอ httpservletrequest) โยนข้อยกเว้น {thread.sleep (3000); logger.info (request.hashCode () + ""); logger.info (reqeust.getheader ("uid"); return null;} @requestmapping ("/iiii") การทดสอบสตริงสาธารณะ (คำขอ httpservletrequest) {logger.info (request.hashcode () + ""); logger.infoดังที่ได้กล่าวมาแล้วฉันนอนในอินเทอร์เฟซ/oooo เป็นเวลา 3 วินาที หากแชร์ reqeust การร้องขอที่ตามมาจะเขียนทับ reqeust ในการนอนหลับและ UID ที่เข้ามาคือที่อยู่อินเตอร์เฟส เริ่ม /oooo ก่อนจากนั้นเริ่ม /iiii
เอาท์พุท
Controller.ctest: 33 - 364716268controller.ctest: 34 - iiiicontroller.ctest: 26 - 1892130707controller.ctest: 27 - oooooo
สรุป: 1. /III ที่ริเริ่มในภายหลังไม่ได้เขียนทับข้อมูลก่อนหน้า /oooo และไม่มีปัญหาด้านความปลอดภัยของเธรด 2. HashCode ของคำขอแตกต่างกัน เนื่องจากการบล็อก /oooo ทำให้เธรดอื่นต้องประมวลผลมันจึงสร้างคำขอใหม่แทน hashcode เดียวกันเหมือนเดิม
รอบที่สองของการตรวจสอบ
ชั้นเรียนสาธารณะ httptest {โมฆะคงที่สาธารณะหลัก (สตริง [] args) โยนข้อยกเว้น {สำหรับ (int i = 300; i> 0; i--) {สุดท้าย int finali = i; เธรดใหม่ () {@Override โมฆะสาธารณะเรียกใช้ () {system.out.println ("v ###" + finali); httprequest.get ("http: // localhost: 8080/test/iiii?") .header ("uid", "v ###" + finali). send (); } }.เริ่ม(); -ภายใต้เงื่อนไขที่เกิดขึ้นพร้อมกัน UID300 ในส่วนหัวยอมรับอย่างเต็มที่โดยไม่ต้องเอาชนะ
ด้วยวิธีนี้ไม่มีปัญหาด้านความปลอดภัยของด้าย
วิธีที่ 2
ใน CommonController ให้ใช้ @modelattribute เพื่อจัดการ
คลาสสาธารณะ CommanController {// @autowired ป้องกัน httpservletrequest คำขอ; @ModelAttribute โมฆะสาธารณะ BindReq (คำขอ httpservletRequest) {this.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")); คืนค่า null; - ชั้นเรียนสาธารณะ httptest {โมฆะคงที่สาธารณะหลัก (สตริง [] args) โยนข้อยกเว้น {สำหรับ (int i = 100; i> 0; i--) {สุดท้าย int finali = i; เธรดใหม่ () {@Override โมฆะสาธารณะเรียกใช้ () {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 ### 82Controller.ctest: 26 - V ### 93controller.ctest: 26 - V ### 71controller.ctest: 26 - V ### 71controller.ctest: 26 - V ### 71controller.ctest: 26 - V ## 71controller v ### 71controller.ctest: 26 - V ### 85controller.ctest: 26 - V ### 85controller.ctest: 26 - V ### 14controller.ctest: 26 - V ### 47controller.ctest: 26 - V ## 47controller v ### 22controller.ctest: 26 - V ### 55controller.ctest: 26 - V ### 61
คุณจะเห็นว่ามีการครอบคลุม 57, 71, 85 และ 47 และคำขอบางอย่างหายไป!
การทำเช่นนั้นคือด้าย-ความปลอดภัย!
วิธีที่ 3
ใช้ CommonController เป็นคลาสพื้นฐานเพื่อขอ AutoWire
คลาสสาธารณะ CommanController {@autowired ป้องกัน httpservletrequest คำขอ; สตริงที่ได้รับการป้องกัน getUid () {system.out.println (request.toString ()); return request.getAttribute ("uid") == null? null: (สตริง) request.getAttribute ("uid"); -อินเทอร์เฟซทดสอบนั้นเหมือนกับข้างต้นและผลลัพธ์ก็น่ายินดี! ไม่มีความคุ้มครองสำหรับ 100 คำขอ ฉันเพิ่มขอบเขตและทดสอบห้าหรือหกครั้งและไม่มีความคุ้มครองสำหรับคำขอนับพัน สิ่งนี้สามารถพิสูจน์ได้ว่าไม่มีปัญหาด้านความปลอดภัยของเธรดในวิธีการเขียนนี้!
สิ่งที่น่าสนใจอีกอย่างคือไม่ว่าจะมีการใช้งานพร้อมกันมากแค่ไหน HashCode ของคำขอก็เหมือนกันเสมอ ยิ่งกว่านั้นเมื่อทดสอบอินเทอร์เฟซที่แตกต่างกันในคอนโทรลเลอร์เดียวกันมันก็เหมือนกัน เมื่อใช้การนอนหลับเพื่อบังคับบล็อก hashcode จะเหมือนกัน อย่างไรก็ตาม HashCode นั้นแตกต่างกันเมื่อเข้าถึงตัวควบคุมที่แตกต่างกันดังนั้นฉันจึงไม่ได้ขุดลึกลงไปในวิธีการใช้งาน
แต่ข้อสรุปก็ออกมาเช่นเดียวกับที่บทความพูดในตอนแรก
สรุป
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com