Kata pengantar
Masalah keamanan utas multithreading halus dan tidak terduga, karena urutan operasi di multithreads tidak dapat diprediksi tanpa sinkronisasi yang tepat. Beberapa utas yang mengakses variabel bersama yang sama sangat rentan terhadap masalah konkurensi, terutama ketika beberapa utas perlu menulis variabel bersama, untuk memastikan keamanan utas,
Secara umum, pengguna perlu melakukan sinkronisasi yang tepat saat mengakses variabel bersama, seperti yang ditunjukkan pada gambar di bawah ini:
Dapat dilihat bahwa ukuran sinkronisasi umumnya mengunci, yang mengharuskan pengguna untuk memiliki pemahaman tertentu tentang kunci, yang jelas meningkatkan beban pada pengguna. Jadi adakah cara saat membuat variabel, ketika setiap utas mengaksesnya, ia mengakses variabel utasnya sendiri? Faktanya, Threalocal dapat melakukan ini. Perhatikan bahwa kemunculan threadlocal tampaknya tidak menyelesaikan masalah di atas.
Threadlocal disediakan dalam paket JDK. Ini menyediakan variabel thread-lokal. Artinya, jika Anda membuat variabel threadlocal, maka setiap utas yang mengakses variabel ini akan memiliki salinan variabel lokal. Ketika beberapa utas mengoperasikan variabel ini, mereka benar -benar mengoperasikan variabel dalam memori lokal mereka sendiri, sehingga menghindari masalah keamanan utas. Setelah membuat variabel threadlocal,
Setiap utas akan menyalin variabel ke memori lokalnya, seperti yang ditunjukkan pada gambar di bawah ini:
Oke, sekarang mari kita pikirkan pertanyaan: prinsip implementasi Threadlocal, dan bagaimana Threadlocal diimplementasikan sebagai metode isolasi utas variabel, secara internal?
Pertama, kita perlu melihat struktur diagram kelas Threadlocal, seperti yang ditunjukkan pada gambar berikut:
menyukai
Seperti yang dapat dilihat pada diagram kelas di atas, ada threadlocals dan diwariskan yang menjadi sulung di kelas utas. Kedua jenis variabel adalah threadlocalmap, dan threadlocalmap adalah hashmap yang disesuaikan. Secara default, kedua variabel di setiap utas adalah nol. Mereka hanya akan dibuat ketika utas memanggil set threadlocal atau mendapatkan metode untuk pertama kalinya.
Faktanya, variabel lokal dari masing -masing utas tidak disimpan dalam instance threadlocal, tetapi disimpan dalam variabel threadlocals dari utas panggilan. Dengan kata lain, variabel lokal dari threadlocal tipe disimpan dalam ruang memori utas tertentu.
Threadlocal sebenarnya adalah shell. Ini menempatkan nilai nilai ke dalam benang utas panggil Thread Threadlocals melalui metode yang ditetapkan dan menyimpannya. Ketika utas panggilan memanggil metode GET, dikeluarkan dari variabel threadlocals dari utas saat ini. Jika utas panggilan tidak berakhir, maka variabel lokal akan disimpan dalam variabel threadlocals dari utas panggilan.
Oleh karena itu, ketika Anda tidak perlu menggunakan variabel lokal, Anda dapat menghapus variabel lokal dari variabel threadlocals dari utas saat ini dengan memanggil metode hapus variabel threadlocal. Beberapa orang mungkin bertanya mengapa threadlocals dirancang sebagai struktur peta? Jelas bahwa setiap utas dapat dikaitkan dengan beberapa variabel threadlocal.
Selanjutnya kita dapat memasukkan kode sumber di ThreadLocal seperti yang ditunjukkan pada kode berikut:
Ini terutama melihat logika implementasi dari tiga metode yang ditetapkan, dapatkan, dan hapus, sebagai berikut:
Mari kita lihat metode set (t var1) terlebih dahulu
public void set (t var1) {// (1) Dapatkan utas saat ini var2 = thread.currentThread (); // (2) Utas saat ini digunakan sebagai kunci untuk menemukan variabel utas yang sesuai. Jika ditemukan, atur threadlocal.threadlocalmap var3 = this.getMap (var2); if (var3! = null) {var3.set (this, var1); } else {// (3) Panggilan pertama dibuat untuk membuat hashmap yang sesuai untuk utas saat ini this.createMap (var2, var1); }}Seperti disebutkan di atas kode (1), pertama -tama dapatkan utas panggilan, dan kemudian gunakan utas saat ini sebagai parameter untuk memanggil metode getMap (var2). Kode getMap (utas var2) adalah sebagai berikut:
Threadlocal.threadlocalmap getMap (thread var1) {return var1.threadlocals; }Dapat dilihat bahwa apa yang dilakukan getMap (var2) adalah untuk mendapatkan ulir variabel utas sendiri, dan variabel threadlocal terikat pada variabel anggota utas.
Jika getMap (var2) mengembalikan tidak kosong, lalu atur nilai nilai ke threadlocals, yaitu, masukkan nilai variabel saat ini ke dalam ulir variabel memori dari utas saat ini. Threadlocals adalah struktur hashmap, di mana kunci adalah referensi dari objek instance threadlocal saat ini, dan nilai adalah nilai yang dilewati melalui metode yang ditetapkan.
Jika getMap (var2) kembali kosong, itu berarti bahwa metode yang ditetapkan disebut pertama kali, dan kemudian variabel threadlocals dari utas saat ini dibuat. Mari kita lihat apa yang dilakukan dalam createMap (var2, var1)?
void createMap (thread var1, t var2) {var1.threadlocals = new threadlocal.threadlocalmap (this, var2); }Yang dapat Anda lihat adalah membuat variabel threadlocals dari utas saat ini.
Selanjutnya, mari kita lihat metode get (), kodenya adalah sebagai berikut:
public t get () {// (4) Dapatkan utas saat ini var1 = thread.currentThread (); // (5) Dapatkan threadlocals variabel threadlocal.threadlocalmap var2 = this.getMap (var1); // (6) Jika threadlocals tidak nol, nilai variabel lokal yang sesuai dikembalikan if (var2! = Null) {threadlocal.threadlocalmap.entry var3 = var2.getEntry (ini); if (var3! = null) {objek var4 = var3.value; mengembalikan var4; }} // (7) Jika threadlocals kosong, variabel anggota threadlocals dari utas saat ini diinisialisasi. kembalikan this.setInitialValue (); }Kode (4) Pertama dapatkan instance utas saat ini. Jika variabel utas dari utas saat ini tidak nol, ia akan secara langsung mengembalikan variabel lokal dari utas saat ini. Jika tidak, jalankan kode (7) untuk diinisialisasi, dan kode setInitialValue () adalah sebagai berikut:
private t setInitialValue () {// (8) diinisialisasi ke objek null var1 = this.initialValue (); Thread var2 = thread.currentThread (); Threadlocal.threadlocalmap var3 = this.getMap (var2); // (9) Jika variabel threadlocals dari variabel utas saat ini tidak kosong jika (var3! = Null) {var3.set (ini, var1); // (10) Jika variabel threadlocals dari utas saat ini kosong} else {this.createMap (var2, var1); } return var1; }Seperti disebutkan di atas, jika variabel threadlocals dari utas saat ini tidak kosong, maka nilai variabel lokal dari utas saat ini diatur ke nol. Jika tidak, CreateMap dipanggil ke variabel createMap dari utas saat ini.
Selanjutnya, kita melihat metode void remove (), kodenya adalah sebagai berikut:
public void remeed () {threadlocal.threadlocalmap var1 = this.getMap (thread.currentThread ()); if (var1! = null) {var1.remove (this); }}Seperti disebutkan di atas, jika variabel threadlocals dari utas saat ini tidak kosong, variabel lokal yang ditentukan dalam instance threadlocal di utas saat ini dihapus.
Selanjutnya, mari kita lihat demo tertentu, kodenya adalah sebagai berikut:
/*** Dibuat oleh Cong pada 2018/6/3. */Public Class ThreadLocalTest {// (1) Fungsi cetak statis void print (string str) {//1.1 Cetak nilai variabel LocalVariable dalam memori lokal dari thread system.out.out.println saat ini (str + ":" + localvariable.get ()); //1.2 Bersihkan variabel LocalVariable dalam memori lokal dari utas saat ini //localvariable.remove (); } // (2) Buat threadlocal variabel statis threadlocal <string> localvariable = new threadlocal <> (); public static void main (string [] args) {// (3) Buat utas satu threade threadone = utas baru (runnable baru () {public void run () {//3.1 Tetapkan nilai variabel lokal LocalVariable dalam thread satu localvariable.set ("variabel lokal dari thread 1"); //3. System.out.println ("Hasil Setelah Menghapus Variabel Lokal Thread 1" + ":" + LocalVariable.get ()); // (4) Buat utas dua thread threadtwo = utas baru (runnable baru () {public void run () {//4.1 Tetapkan nilai variabel lokal LocalVariable dalam thread satu localvariable.set ("variabel lokal thread 2" variabel nilai variabel lokal. 2 " +": " + localvariable.get ());}}); // (5) Mulai thread threadone.start (); threadtwo.start (); }}Kode (2) membuat variabel threadlocal;
Kode (3) dan (4) masing -masing membuat utas 1 dan 2;
Kode (5) memulai dua utas;
Kode 3.1 Dalam Thread 1 mengatur nilai LocalVariable melalui metode Set. Pengaturan ini sebenarnya adalah salinan di memori lokal Thread 1. Salinan ini tidak dapat diakses oleh utas 2. Kemudian kode 3.2 memanggil fungsi cetak, dan kode 1.1 memperoleh nilai LocalVariable dalam memori lokal dari utas saat ini (utas 1) melalui fungsi GET;
Thread 2 mengeksekusi mirip dengan utas 1.
Hasil operasi adalah sebagai berikut:
Di sini kita perlu memperhatikan masalah kebocoran memori dari threadlocal
Setiap utas memiliki variabel anggota bernama Threadlocals di dalamnya. Jenis variabelnya adalah hashmap. Kuncinya adalah referensi ke variabel threadlocal yang kami tentukan, dan nilainya adalah nilainya saat kami mengatur. Variabel lokal dari masing -masing utas disimpan dalam threadlocals variabel memori utas sendiri. Jika utas saat ini tidak hilang, maka variabel lokal ini akan disimpan sampai.
Oleh karena itu, dapat menyebabkan kebocoran memori, jadi setelah menggunakannya, ingatlah untuk memanggil metode hapus threadlocal untuk menghapus variabel lokal dalam ulir utas dari utas yang sesuai.
Setelah membongkar komentar dalam kode 1.2, jalankan lagi, dan hasil jalankan adalah sebagai berikut:
Pernahkah kita memikirkan pertanyaan seperti ini: apakah kita mendapatkan nilai variabel utas yang diatur dalam utas induk di utas anak?
Di sini kami dapat memberi tahu Anda bahwa nilai variabel threadlocal yang diatur dalam utas induk tidak dapat diperoleh di utas anak. Jadi apakah ada cara untuk membuat utas anak mengakses nilai di utas induk? Diwarisieadlokal muncul di masa depan. Warisasi warisan warisan dari threadlocal dan menyediakan fitur bahwa anak -anak dapat mengakses variabel lokal yang ditetapkan dalam utas induk.
Pertama, mari kita pergi ke kode sumber kelas warisan yang diwariskan untuk membaca, sebagai berikut:
Kelas Publik WoltionableThreadlocal <T> Memperluas Threadlocal <T> {public OnterIblethreadLocal () {} // (1) T lindung t childValue (t var1) {return var1; } // (2) threadLocalMap getMap (thread var1) {return var1.inheritableThreadlocals; } // (3) void createMap (thread var1, t var2) {var1.inheritableThreadlocals = new threadLocalMap (this, var2); }}Anda dapat melihat bahwa warisan yang diwariskan warisan utas dan menulis ulang tiga metode. Kode di atas telah ditandai. Kode (3) dapat dilihat bahwa diwarisieatreadlokal menulis ulang metode createMap, sehingga dapat dilihat bahwa ketika metode yang ditetapkan dipanggil untuk pertama kalinya, contoh variabel warisan yang diwariskan.
Kode (2) Anda dapat mengetahui bahwa ketika metode GET dipanggil untuk mendapatkan variabel peta internal dari utas saat ini, warisan yang dapat diperoleh, bukan threadlocals.
Poin kuncinya ada di sini, ketika kode yang ditulis ulang (1) dieksekusi, dan bagaimana mengimplementasikan bahwa utas anak dapat mengakses variabel lokal utas induk. Dimulai dengan kode yang dibuat berdasarkan utas, konstruktor default utas dan konstruktor kelas thread.java adalah sebagai berikut:
/*** Dibuat oleh Cong pada 2018/6/3. */ utas publik (target runnable) {init (null, target, "thread-" + nextthreadnum (), 0); } private void init (threadGroup G, target runnable, nama string, stacksize panjang, accessControlContext acc) {// ... // (4) Dapatkan utas utas saat ini saat ini = currentThread (); // ... // (5) Jika variabel warisasi yang diwariskaneadlokal dari utas induk tidak nol if (parent.inHeritableThreadlocals! = Null) // (6) atur variabel warisane -rreadlocals; neatreadlocals = threadlocal.createineritededmapapeTeReDetHeThetHerHitals. this.stacksize = stacksize; tid = nextThreadId (); }Saat membuat utas, metode init akan dipanggil dalam konstruktor. Seperti yang disebutkan sebelumnya, kelas pewarisan yang diwariskan. Mari kita lihat kode sumber metode CreateInitedMap, sebagai berikut:
statis ThreadLocalMap createinitedMap (threadLocalMap ParentMap) {return new ThreadLocalMap (ParentMap); }Anda dapat melihat bahwa CreateInitedMap menggunakan variabel warisasi yang diwariskan dengan utas induk sebagai konstruktor untuk membuat variabel utas baru, dan kemudian menugaskannya ke variabel warisan yang diwariskan dengan warisan. Kemudian masukkan konstruktor threadlocalmap. Kode sumber adalah sebagai berikut:
threadlocalmap pribadi (threadLocalMap parentMap) {entri [] parenttable = parentMap.table; int len = parenttable.length; setThreshold (len); Tabel = entri baru [len]; untuk (int j = 0; j <len; j ++) {entri e = parenttable [j]; if (e! = null) {@suppressWarnings ("Uncecked") ThreadLocal <BOMPOCTE> key = (ThreadLocal <Peject>) e.get (); if (key! = null) {// (7) Panggil nilai objek metode yang ditimpa = key.childValue (e.value); // return e.Value entri c = entri baru (key, nilai); int h = key.threadlocalhashcode & (len - 1); while (tabel [h]! = null) h = nextIndex (h, len); Tabel [h] = c; ukuran ++; }}}}}}Apa yang dilakukan kode di atas adalah menyalin nilai variabel anggota warisan induk pewaris induk ke objek threadlocalmap baru, dan kode (1) ditulis ulang oleh kode (7) kelas yang diwariskan dengan kelas yang diwariskan.
Secara umum: kelas warisan yang diwariskaneadlokal menulis ulang kode (2) dan (3) dan menyimpan variabel lokal ke dalam variabel warisan yang diwariskan. Ketika utas mengatur variabel melalui metode set atau get dari instance wariseableThreadlocals, itu akan membuat variabel warisasi yang diwariskaneadlokal dari utas saat ini. Saat utas induk membuat utas anak,
Konstruktor akan menyalin variabel lokal dalam variabel warisasi yang diwarisan di utas induk dan menyalinnya ke variabel warisasi yang diwariskan.
Setelah prinsip dipahami dengan baik, mari kita ambil contoh untuk memverifikasi apa yang kita ketahui di atas, sebagai berikut:
Paket com.hjc;/*** Dibuat oleh Cong pada 2018/6/3. */kelas publik diwaritableThreadLocaltest {// (1) Buat utas variabel statis public statis <string> threadlocal = new ThreadLocal <string> (); public static void main (string [] args) {// (2) atur thread variable threadlocal.set ("hello java"); // (3) Mulai utas utas anak utas = utas baru (runnable baru () {public void run () {// (4) Nilai utas anak menghasilkan sistem variabel utas.out.println ("subthread:" + threadlocal.get ());}}); thread.start (); // (5) Utas utama menghasilkan sistem nilai variabel utas.out.println ("Thread induk:" + threadlocal.get ()); }}Hasil operasi adalah sebagai berikut:
Dengan kata lain, setelah variabel utas yang sama diatur dalam utas induk, tidak dapat diperoleh di utas anak. Menurut pengantar di bagian sebelumnya, ini harus menjadi fenomena normal, karena utas saat ini adalah utas anak ketika utas anak memanggil metode GET, dan metode yang ditetapkan dipanggil untuk mengatur variabel utas adalah utas utama. Keduanya adalah utas yang berbeda, dan tentu saja utas anak kembali nol saat mengakses.
Jadi apakah ada cara untuk membuat utas anak mengakses nilai di utas induk? Jawabannya adalah ya, jadi gunakan warisan yang dianalisis dengan prinsip kami di atas.
Ubah kode (1) dari contoh di atas menjadi:
// (1) Buat thread variabel statis public statis <string> threadlocal = new OheritableThreadlocal <String> ();
Hasil operasi adalah sebagai berikut:
Dapat dilihat bahwa nilai variabel utas sekarang dapat diperoleh secara normal dari utas anak. Jadi dalam keadaan apa anak -anak perlu mendapatkan variabel benang dari utas induk?
Ada cukup banyak situasi, seperti variabel utas yang menyimpan informasi login pengguna. Sangat mungkin bahwa subthreads juga perlu menggunakan informasi login pengguna. Misalnya, beberapa middleware perlu menggunakan ID pelacakan terpadu untuk merekam seluruh tautan panggilan.
Penggunaan Threadlocal dalam Permintaan Singkirkan Lingkup Kacang Musim Semi
Kita tahu bahwa ketika mengkonfigurasi kacang di XML di musim semi, Anda dapat menentukan atribut ruang lingkup untuk mengonfigurasi ruang lingkup kacang yang menjadi singleton, prototipe, permintaan, sesi, dll. Prinsip implementasi ruang lingkup kacang diimplementasikan menggunakan threadlocal. Jika Anda ingin kacang di wadah musim semi Anda memiliki ruang lingkup web,
Selain atribut ruang lingkup yang sesuai yang diperlukan untuk mengonfigurasi level kacang, itu juga harus dikonfigurasi dalam web.xml sebagai berikut:
<listener> <listener-class> org.springframework.web.context.request.requestContextListener </engeaner-class> </engeaner>
Di sini kami terutama melihat dua metode RequestContextListener:
public void requestInitialized (ServletRequestEvent RequestEvent)
Dan
public void requestDestroyed (ServletRequestEvent RequestEvent)
Ketika permintaan Web datang, metode requestInitialized akan dieksekusi:
public void requestInitialized (servletRequestEvent requestEvent) {..... oMit httpservletRequest request = (httpservletRequest) requestEvent.getServletRequest (); Atribut ServletRequestAttributes = ServletRequestAttributes baru (permintaan); request.setAttribute (request_attributes_attribute, atribut); Localecontextholder.setLocale (request.getLocale ()); // atur atribut ke threadlocal variabel requestContextholder.setRequestAttributes (atribut); } public static void setRequestAttributes (requestAttributes atribut) {setRequestAttributes (atribut, false); } public static void setRequestAttributes (requestAttributes atribut, boolean warisan) {if (atribut == null) {resetRequestAttributes (); } else {// default inheritable = false if (inheritable) {wheritableRequestAttributeSholder.set (atribut); requestAttributeSholder.remove (); } else {requestAttributeSholder.set (atribut); wheritableRequestAttributeSholder.remove (); }}}Anda dapat melihat kode sumber di atas. Karena default yang diwariskan adalah salah, nilai atribut kami ditempatkan di RequestAttributeShoder, dan definisinya adalah:
thread final private statis <merplocal <merquestAttributes> requestAttributeSholder = new NamedThreadlocal <EnquestAttributes> ("Atribut Permintaan"); Threadlocal final private static <merquestAttributes> OnteryableRequestAttributeSholder = new NamedInhitableThreadlocal <EmployAttributes> ("Permintaan Konteks");Di antara mereka, bernamaThreadlocal <T> memperluas threadlocal <T>, sehingga tidak dapat diwariskan.
Di antara mereka, bernamaThreadlocal <T> memperluas threadlocal <T>, sehingga tidak dapat diwariskan.
NameInheritableThreadlocal <T> Memperluas warisan yang dapat diwariskan <T>, sehingga memiliki warisan, sehingga nilai atribut yang ditempatkan di PermintaancontExtholder secara default tidak dapat diperoleh di utas anak.
Ketika permintaan berakhir, metode requestDestroyed dipanggil, dan kode sumber adalah sebagai berikut:
public void requestDestroyed (servletRequestEvent requestEvent) {servletRequestAttributes atribut = (servletRequestAttributes) requestEvent.getSerVletRequest (). getAttribute (request_attributes_attribute); ServletRequestAttributes threatTattributes = (servletRequestAttributes) requestContextholder.getRequestAttributes (); if (threatTattributes! = null) {// kami sangat mungkin untuk menghapus utas utas saat ini di utas permintaan awal jika (atribut == null) {atribut = threatTattributes; } // Saat permintaan berakhir, hapus variabel utas utas saat ini. Localecontextholder.resetlocaleContext (); RequestContextholder.resetRequestAttributes (); } if (atribut! = null) {attributes.RequestCompleted (); }}Selanjutnya, mari kita lihat logika permintaan web panggilan dari bagan waktu:
Dengan kata lain, setiap kali permintaan web dimulai sebelum memproses konteks (aplikasi spesifik) di Tomcat, properti RequestContExtholder akan ditetapkan setelah host cocok, sehingga RECEVERATtributeSholder tidak kosong dan akan dihapus pada akhir permintaan.
Oleh karena itu, secara default, utas anak atribut yang ditempatkan di REVERVERCONTEXTHOLDER tidak dapat diakses, dan kacang dalam ruang lingkup permintaan musim semi diimplementasikan menggunakan Threadlocal.
Selanjutnya, permintaan simulasi contoh dilakukan, kodenya adalah sebagai berikut:
Konfigurasi web.xml adalah sebagai berikut:
Karena ini adalah ruang lingkup permintaan, itu harus merupakan proyek web dan RequestContextListener perlu dikonfigurasi ke web.xml.
<listener> <listener-class> org.springframework.web.context.request.requestContextListener </engeaner-class> </engeaner>
Kemudian suntikkan kacang lingkup permintaan ke dalam wadah IOC. Kodenya adalah sebagai berikut:
<bean id = "requestBean" scope = "request"> <properti name = "name" value = "hjc" /> <aop: scoped-proxy /> </ bean>
Kode tes adalah sebagai berikut:
@WebResource ("/testService") TestRPC kelas publik {@Autowired Private RequestBean RequestInfo; @ResourCeMapping ("test") Public ActionResult tes (Konteks errorContext) {ActionResult Hasil = ActionResult baru (); pvginfo.setname ("hjc"); Name string = requestInfo.getName (); result.setValue (nama); hasil pengembalian; }}Seperti disebutkan di atas, pertama -tama konfigurasikan RequestContextListener ke Web.xml, lalu suntikkan instance RequestBean ke dalam wadah IOC dengan ruang lingkup permintaan. Akhirnya, instance RequestBean disuntikkan ke testrpc. Metode Tes Pertama Panggilan Metode RequestInfo SetName Untuk mengatur atribut nama, lalu dapatkan atribut nama dan kembalikan.
Di sini, jika objek RequestInfo adalah Singleton, setelah beberapa utas memanggil metode uji secara bersamaan, setiap utas adalah operasi set-get. Operasi ini bukan atom dan akan menyebabkan masalah keamanan utas. Lingkup yang dinyatakan di sini adalah tingkat permintaan, dan setiap utas memiliki variabel lokal dengan RequestInfo.
Bagan waktu dari permintaan metode contoh di atas adalah sebagai berikut:
Kita perlu fokus pada apa yang terjadi saat memanggil tes:
Faktanya, RequestInfo yang dibuat sebelumnya adalah setelah diproksi oleh CGLIB (jika Anda tertarik, Anda dapat mempelajari SCOPEDPROXYFACTORYBEAN dan jenis lainnya), jadi ketika Anda memanggil SetName atau GetName, Anda akan dicegat oleh DynamicAdvisedInterceptor. Interceptor pada akhirnya akan memanggil metode GET RequestScope untuk mendapatkan variabel lokal yang dipegang oleh utas saat ini.
Kuncinya ada di sini. Kita perlu melihat kode sumber dari Metode Get RequestScope sebagai berikut:
Objek publik get (nama string, objekFactory objectFactory) {requestAttributes atribut = requestContextholder.currentRequestAttributes (); // (1) objek scopedObject = attributes.getAttribute (name, getScope ()); if (scopedObject == null) {scopedObject = objectFactory.getObject (); // (2) atribut.setAttribute (name, scopedObject, getscope ()); // (3)} return scopedObject; }Dapat dilihat bahwa ketika suatu permintaan dimulai, RECEVINGAttributeSholder akan ditetapkan dengan menelepon RequestContextListener.Requestinitialized di RequestContextListener.setRequestAttributess.
Kemudian setelah permintaan dialihkan ke metode pengujian TestRPC, pertama kali metode SetName dipanggil dalam metode pengujian, metode RequestScope.get () pada akhirnya akan dipanggil. Kode dalam metode GET (1) mendapatkan nilai dari set atribut yang disimpan oleh variabel thread-local requestAttributeSholder yang ditetapkan melalui RequestContextListener.requestinitialized.
Kemudian periksa apakah ada atribut bernama RequestInfo di set atribut. Karena ini adalah panggilan pertama, itu tidak ada, sehingga kode akan dieksekusi (2) dan membiarkan Spring membuat objek RequestInfo, dan kemudian mengaturnya ke atribut set atribut, yaitu, itu akan disimpan dalam memori lokal dari utas permintaan saat ini. Kemudian kembalikan objek yang dibuat dan panggil setName dari objek yang dibuat.
Akhirnya, metode getName dipanggil dalam metode pengujian, dan metode requestScope.get () akan dipanggil. Kode dalam metode GET (1) mendapatkan utas variabel lokal yang ditetapkan melalui requestContextListener.requestinitialized, dan kemudian lihat apakah ada atribut bernama RequestInfo dalam set atribut.
Karena kacang bernama RequestInfo telah diatur ke variabel utas ketika dipanggil untuk SetName untuk pertama kalinya, dan utas yang sama dipanggil untuk SetName dan GetName, objek RequestInfo yang dibuat ketika memanggil SetName secara langsung dikembalikan ke sini, dan kemudian metode GetName -nya dipanggil.
Sejauh ini, kami telah memahami prinsip implementasi Threadlocal dan menunjukkan bahwa Threadlocal tidak mendukung warisan; Kemudian kami segera menjelaskan bagaimana warisan yang dapat dikompensasi untuk fitur yang tidak mendukung warisan; Akhirnya, kami secara singkat memperkenalkan cara menggunakan Threadlocal dalam kerangka musim semi untuk mengimplementasikan Bean of Reqeust Scope.
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.