Kata pengantar
Perhatikan bahwa untuk menyimpan kode, HttpservletRequest tidak dinyatakan dalam badan metode, dan lubang yang dibor secara langsung disuntikkan dengan AutoWire.
Kesimpulan: Bagi mereka yang cemas. Deklarasikan httpservletRequest langsung pada variabel anggota pengontrol menggunakan @Autowire, yang amannya utas!
@ControllerPublic kelas testController {@autowire httpservletRequest permintaan; @RequestMapping ("/") public void test () {request.getAttribute ("uid"); }}Kesimpulannya seperti di atas.
latar belakang
Ini benar. Karena saya menambahkan informasi otentikasi ke kepala permintaan dalam proyek, dan setelah interseptor mencegat informasi dan melewati verifikasi, saya akan menambahkan identitas pengguna saat ini ke atribut permintaan, yang nyaman untuk menggunakannya kembali di lapisan pengontrol.
PERTANYAAN: Mengapa tidak menggunakan @Requestheader untuk mengambilnya langsung pada pengontrol? Karena header berisi data terenkripsi dan membutuhkan beberapa otentikasi dan penilaian yang kompleks, langkah ini langsung dilemparkan ke pencegat untuk dieksekusi.
Jadi setelah dekripsi, saya mengatur informasi pengguna (seperti UID) ke dalam request.setAttribute() untuk mengekstraknya di pengontrol.
Jika Anda perlu menggunakan permintaan, Anda biasanya perlu mendeklarasikannya pada metode, seperti:
Hasil Publik Simpan (permintaan httpservletrequest) {// dosomething ();}Jadi, jika saya menggunakan UID untuk setiap metode, tidak akan setiap metode menyatakan parameter permintaan, untuk menyimpan langkah yang berlebihan. Saya menulis kelas dasar.
Public Class CommonController {@autowire httpservletreqeust permintaan; Public String getuID () {return (string) request.getAttribute ("uid"); }}Kemudian saya khawatir bahwa karena pengontrol adalah singleton, akankah ini menghasilkan reqeust berikutnya yang mencakup permintaan sebelumnya, dan ada masalah keselamatan utas dalam kondisi konkurensi. Jadi saya mengajukan pertanyaan di SegmentFault, dan sebagian besar netizen mengatakan bahwa memang ada masalah threading! SegmentFault Masalah Alamat ### Proses Verifikasi Karena sebagian besar pendapat netizen adalah bahwa mereka hanya dapat mendeklarasikannya dalam hal metode, saya secara alami tidak ingin menyerah menulis begitu banyak kode sekarang, jadi saya memulai proses verifikasi saya. Para programmer yang antusias telah memberi saya beberapa solusi. Karena saya telah berupaya membuktikannya, saya akan meletakkan hasilnya di sini dan membaginya dengan Anda.
Metode 1
Metode pertama adalah menampilkan deklarasi httpservletreqeust dalam metode pengontrol, kode ini sebagai berikut:
@RequestMapping ("/test")@restControllerPublic CLASS CTEST {Logger Logger = LoggerFactory.GetLogger (getClass ()); @RequestMapping ("/iiii") tes string publik (permintaan httpservletrequest) {logger.info (request.hashcode () + ""); kembali nol; }}Tekan F5 di browser
Keluaran
Saya bingung pada waktu itu, ** Saya setuju untuk mendapatkan keselamatan utas! ** Bukankah ini permintaan yang sama? Apakah Anda bercanda! Saya sudah lama mencari permintaan untuk menulis ulang hashcode ()!
Ah, ini adalah kebenaran, karena saya menekan F5 dengan browser saya, dan tidak peduli seberapa keras saya menekannya, saya tidak dapat mensimulasikan konkurensi. Itu setara dengan server menggunakan utas yang sama untuk memproses permintaan saya. Adapun kode hash dari permintaan ini, menurut JDK, itu dihitung berdasarkan alamat virtual OBJ di JVM. Saya kira apa selanjutnya. Jika Anda tahu apa yang sebenarnya Anda inginkan, saya akan memberi tahu saya!
tebakan
Ruang memori permintaan yang diterapkan oleh setiap utas di server diperbaiki saat server dimulai. Kemudian setiap kali saya meminta, dia akan membuat permintaan baru di ruang memori yang dia minta (mungkin struktur yang mirip dengan array). (Mirip dengan titik awal array selalu merupakan alamat memori yang sama). Kemudian saya memulai permintaan, dan dia akan membuat permintaan baru di posisi awal dan meneruskannya ke servlet dan mulai memproses. Setelah pemrosesan selesai, itu akan dihancurkan. Kemudian permintaan baru yang dibuat oleh permintaan berikutnya dihancurkan, sehingga dimulai dari alamat awal. Dengan cara ini, semuanya akan dijelaskan!
Tebakan sudah selesai
Verifikasi dugaan:
Saya tidak akan membiarkan dia punya waktu untuk menghancurkannya, dapatkah saya menguji kode
@RequestMapping ("/test")@restControllerPublic CLASS CTEST {Logger Logger = LoggerFactory.GetLogger (getClass ()); @RequestMapping ("/ooooo") Public String testa (permintaan httpservletRequest) melempar Exception {thread.sleep (3000); logger.info (request.hashcode () + ""); Logger.info (reqeust.getHeader ("uid"); return null;} @RequestMapping ("/iiii") tes string publik (permintaan httpservletrequest) {logger.info (request.hashcode () + "); logger.info (reqeust.gethead (" ul; "uLl;Seperti disebutkan di atas, saya tidur di antarmuka/oooo selama 3 detik. Jika berbagi reqeust, maka permintaan selanjutnya akan menimpa reqeust dalam tidur, dan UID yang masuk adalah alamat antarmuka. Mulai /oooo pertama dan kemudian mulai /iiii
Keluaran
controller.ctest: 33 - 364716268Controller.ctest: 34 - iiiicontroller.ctest: 26 - 1892130707Controller.ctest: 27 - OOOOO
Kesimpulan: 1. /III yang diprakarsai kemudian tidak menimpa data sebelumnya /OOOO dan tidak ada masalah keamanan utas. 2. Kode hash dari permintaan berbeda. Karena /oooo blocking menyebabkan utas lain perlu memprosesnya, itu membuat permintaan baru alih -alih kode hash yang sama seperti sebelumnya.
Putaran verifikasi kedua
kelas publik httptest {public static void main (string [] args) melempar Exception {for (int i = 300; i> 0; i--) {final int final = i; utas baru () {@Override public void run () {System.out.println ("V ###" + final); HttpRequest.get ("http: // localhost: 8080/test/iiii?") .Header ("uid", "v ###" + final) .send (); } }.awal(); }}}Dalam kondisi konkurensi yang disimulasikan, UID300 di header sepenuhnya menerima tanpa menimpa
Jadi dengan cara ini, tidak ada masalah keamanan utas.
Metode 2
Di CommonController, gunakan @modelattribute untuk menangani.
Public Class CommonController {// @Autowired Dilindungi permintaan httpservletRequest; @Modelattribute public void bindreq (permintaan httpservletRequest) {this.Request = request; } string protected getuid () {System.out.println (request.toString ()); return request.getAttribute ("uid") == null? null: (string) request.getAttribute ("uid"); }}Ini memiliki masalah keamanan utas! Permintaan selanjutnya dapat mencakup yang sebelumnya!
Kode verifikasi
@Restcontroller@requestMapping ("/test") CTEST PUBLIK PENGETAHUAN COMMONCONTROLLER {LOGGER LOGGER = LOGGERFACTORY.GETLOGGER (getClass ()); @RequestMapping ("/iiii") Public String test () {logger.info (request.getheader ("uid")); kembali nol; }} kelas publik httptest {public static void main (string [] args) melempar Exception {for (int i = 100; i> 0; i--) {final int final = i; utas baru () {@Override public void run () {System.out.println ("V ###" + final); Httprequest.get ("http: // localhost: 8080/test/iiii") .Header ("uid", "v ###" + final) .send (); } }.awal(); }}}Hasil output parsial dicegat
controller.ctest: 26 - V ### 52Controller.ctest: 26 - V ### 13Controller.ctest: 26 - V ### 57Controller.ctest: 26 - V ### 57Controller.ctest: 26 - V ### 21Controller.ctest: 26 - V ### 10ckon. 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###71controller.CTest:26 - V ### 71Controller.ctest: 26 - V ### 85Controller.ctest: 26 - V ### 85Controller.ctest: 26 - V ### 14Controller.ctest: 26 - V ### 47Controller.ctest: 26 - V ### 47Controller.ctest: 26 -controller.ctest: 2 26 - V ### 47Controller.ctest: 26 -controller.ctest: V ### 47Controller.ctest: 26 -controller.ctest: V ### 47Controller.ctest: 26 -controller.ctest: V ### 47Controller.ctest: 26 -controller.ctest: V ### 47Controller.ctest: 26 -controller.ctest: V ### 47Controller.ctest: 26 -controller. V ### 22Controller.ctest: 26 - V ### 55Controller.ctest: 26 - V ### 61
Anda dapat melihat bahwa 57, 71, 85, dan 47 tertutup, dan beberapa permintaan hilang!
Melakukannya adalah utas-tidak aman!
Metode 3
Gunakan CommonController sebagai kelas dasar untuk meminta Autowire.
Public Class CommonController {@Autowired Dilindungi permintaan httpservletRequest; string protected getuid () {System.out.println (request.toString ()); return request.getAttribute ("uid") == null? null: (string) request.getAttribute ("uid"); }}Antarmuka uji sama seperti di atas, dan hasilnya memuaskan! Tidak ada pertanggungan untuk 100 permintaan. Saya meningkatkan ruang lingkup dan mengujinya lima atau enam kali, dan tidak ada pertanggungan untuk ribuan permintaan. Ini dapat membuktikan bahwa tidak ada masalah keamanan utas dalam metode penulisan ini!
Hal lain yang menarik adalah bahwa tidak peduli berapa banyak konkurensi yang digunakan, kode hashcing dari permintaan selalu sama. Selain itu, saat menguji antarmuka yang berbeda di pengontrol yang sama, itu sama. Saat menggunakan tidur untuk memaksa blok, kode hash adalah sama. Namun, kode hash berbeda ketika mengakses pengontrol yang berbeda, jadi saya tidak terus menggali lebih dalam cara mengimplementasikannya.
Tetapi kesimpulannya sudah keluar, seperti yang dikatakan artikel itu di awal.
Meringkaskan
Di atas adalah seluruh konten artikel ini. Saya berharap konten artikel ini memiliki nilai referensi tertentu untuk studi atau pekerjaan semua orang. Jika Anda memiliki pertanyaan, Anda dapat meninggalkan pesan untuk berkomunikasi. Terima kasih atas dukungan Anda ke wulin.com.