0 Ringkasan
Artikel ini secara singkat menjelaskan tautan pemetaan prosesor SpringMVC dari tingkat kode sumber, yaitu, proses terperinci untuk menemukan pengontrol
1 Proses Permintaan SpringMVC
Controller Mencari Langkah 1 hingga 2 yang sesuai dengan gambar di atas
Bagan Aliran Operasi Rinci SpringMVC
2 Proses Inisialisasi SpringMVC
2.1 Pertama pahami dua kategori
1.RestMappingInfo
Encapsulation Requestmapping Anotasi
Berisi informasi yang relevan tentang header permintaan HTTP
Sebuah contoh sesuai dengan anotasi permintaan permintaan
2.Handlermethod
Metode penanganan permintaan untuk pengontrol enkapsulasi
Termasuk objek kacang yang menjadi milik metode, objek metode yang sesuai dengan metode ini, parameter metode, dll.
Hubungan warisan RequestMappappapingLermapping
Selama inisialisasi SpringMVC
Pertama -tama jalankan afterpropertiesset dari requestmappingHandlermapping
Kemudian masukkan abstracthandlermethodmapping setelah propertiesset
Metode ini akan memasuki inithandlermethods dari kelas ini
Bertanggung jawab untuk memindai kacang dari ApplicationContext, kemudian menemukan dan mendaftarkan metode prosesor dari kacang
// Pindai kacang dalam aplikasi ApplicationContext, Detect and Register Handler.Protected void inithandlermethods () {... // Dapatkan semua kacang di string ApplicationContext [] beannames = (this.detecthandlermethodsinancestorcontexts? Beanfactoryuteutils.beannamespforforforforporporporTexts? : getApplicationContext (). GetBeanNamesFortype (Object.class)); // Transfer array beanname untuk (string beanname: beannames) {// ishandler akan menilai apakah definisi kacang berisi anotasi pengontrol atau anotasi permintaan permintaan berdasarkan kacang. If (ishandler (getApplicationContext (). GetType (beanname))) {detecthandlermethods (beanname); }} handlermethodsinitialized (getHandlermethods ());} RequestMappingHandlermapping#ISHandler
Metode di atas adalah untuk menentukan apakah definisi kacang saat ini berisi anotasi pengontrol atau anotasi pengendalian permintaan
Jika saja meminta Mapping mulai berlaku? TIDAK!
Karena dalam hal ini, kelas tidak akan terdaftar sebagai kacang musim semi saat menginisialisasi pegas, dan kelas tidak akan dilalui saat melintasi nama bean, jadi tidak apa -apa untuk mengganti controller dengan kompoen di sini, tetapi ini tidak dilakukan secara umum
Setelah mengkonfirmasi bahwa kacang adalah penangan, metode pawang spesifik akan ditemukan dari kacang (yaitu, metode pemrosesan permintaan yang ditentukan dalam kelas pengontrol). Kode pencarian adalah sebagai berikut
/** * Cari metode penangan di pawang * @param handler nama kacang pawang atau instance pawang */void detecthandlermethods (handler objek akhir) {// Dapatkan objek kelas dari controller BeanClass <?> Handlertype = (handler instance dari string)? getApplicationContext (). getType ((string) handler): handler.getClass (); // Hindari panggilan berulang ke getMappingFormethod untuk membangun kembali requestMappingInfo instance peta akhir <metode, t> mappings = identityHashMap <Method, t> (); // Sama seperti di atas, ini juga merupakan objek kelas dari Kelas Akhir Kontroler <?> UserType = classutils.getUserClass (handlerType); //Get all handler methods of the current bean //Define whether it has RequestMapping according to the method //If there is, create a RequestMappingInfo instance Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() { @Override public boolean matches(Method method) { T mapping = getMappingForMethod(method, userType); if (mapping != null) {Mappings.put (Metode, Pemetaan); // bepergian dan daftarkan semua metode penangan dari kacang saat ini untuk (metode metode: metode) {// Metode penangan register dan masukkan metode berikut registerhandlermethod (pawang, metode, mappings.get (metode)); } Ada dua tempat dalam kode di atas yang memanggil getMappingFormethod
Buat RequestMappingInfo Menggunakan Anotasi Metode dan Type Level
@Override Protected RequestMappingInfo getMappingFormethod (metode metode, kelas <?> HandlerType) {requestMappingInfo info = null; // Dapatkan metode @RequestMapping MethodAnnotation @RequestMapping = annotationutils.findannotation (Metode, RequestMapping.class); if (methodAnnotation! = null) {requestCondition <?> MethodCondition = getCustommethodCondition (Method); info = createRequestMappingInfo (MethodAnnotation, MethodCondition); // Dapatkan anotasi @requtestmapping dari kacang yang menjadi bagian dari metode tersebut meminta typeannotation = annotationutils.findannotation (handlerType, requestMapping.class); if (typeannotation! = null) {requestCondition <?> typecondition = getCustomTypeCondition (handLerType); // gabungkan dua info anotasi @RequestMapping = createRequestMappingInfo (typeannotation, typecondition) .combine (info); }} return info; } Tujuan dari metode ini adalah untuk membuat objek RequestMappingInfo berdasarkan metode metode penangan. Pertama, tentukan apakah mehtod berisi anotasi permintaan. Jika demikian, buat objek RequestMappingInfo secara langsung berdasarkan konten anotasi. Setelah pembuatan, tentukan apakah kacang yang mana metode saat ini juga berisi anotasi permintaan permintaan. Jika anotasi ini disertakan, objek RequestMappingInfo akan dibuat berdasarkan anotasi pada kelas. Kemudian, objek RequestMappingInfo pada metode penggabungan dikembalikan, dan objek gabungan akhirnya dikembalikan. Sekarang, melihat kembali metode detecthandlermethods, ada dua panggilan untuk mendapatkan metode formethod. Saya pribadi berpikir ini bisa dioptimalkan. Saat menilai apakah metode ini adalah penangan di tempat pertama, objek RequestMappingInfo yang dibuat dapat disimpan dan digunakan langsung nanti, yang berarti bahwa proses membuat objek RequestMappingInfo tidak ada. Kemudian segera masukkan metode registerhandlermehtod, sebagai berikut
Protected void registerHandLermethod (penangan objek, metode metode, pemetaan t) {// Buat handlermethod handlermethod newhandlermethod = createHandlermethod (handler, method); Handlermethod oldhandmethod = handlermethods.get (pemetaan); // Periksa apakah ada ambiguitas dalam konfigurasi jika (oldhandlermethod! = Null &&! Oldhandlermethod.equals (newhandlermethod)) {lempar baru ilegalstateException ("pemetaan ambigu. oldhandlermethod.getBean () + "'Metode kacang/n" + oldhandlermethod + "dipetakan."); } this.handlermethods.put (pemetaan, newhandlermethod); if (logger.isInfoEnabled ()) {logger.info ("dipetakan /" " + pemetaan +" /"ke" + newhandlermethod); } // Dapatkan nilai anotasi @RequestMapping, dan kemudian tambahkan nilai-> requestMappingInfo Mapping Record ke URLMAP Set <string> Patterns = getMappingPathPattern (pemetaan); untuk (pola string: pola) {if (! getPathmatcher (). isPattern (pola)) {this.urlmap.add (pola, pemetaan); }}} Di sini jenis t adalah requestmappingInfo. Objek ini adalah informasi yang relevan dari anotasi requestmapping dari metode di bawah pengontrol spesifik yang dienkapsulasi. Anotasi Permintaan Permintaan Sesuai dengan Objek RequestMappingInfo. Handlermethod mirip dengan RequestMappingInfo, dan merupakan enkapsulasi metode pemrosesan spesifik di bawah Controlelr. Pertama -tama lihat baris pertama dari metode ini dan buat objek Handlermethod berdasarkan Handler dan Mehthod. Baris kedua menggunakan peta handlermethods untuk mendapatkan handlermethod yang sesuai dengan pemetaan saat ini. Kemudian tentukan apakah ada konfigurasi pemasangan permintaan yang sama. Konfigurasi berikut akan menyebabkan dilemparkan ke sini
Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping found. Cannot map...
abnormal
@Controller @requestMapping ("/ambiguoustest") kelas publik ambiguoustestController {@RequestMapping (value = "/test1") @ResponseBody public string test1 () {return "Method test1"; } @RequestMapping (value = "/test1") @ResponseBody public string test2 () {return "Method test2"; }} Periksa apakah konfigurasi RequestMapping adalah ambiguitas selama fase Startup SpringMVC (Inisialisasi), yang merupakan salah satu hal yang harus diperiksa ambiguitas (tempat untuk memeriksa ambiguitas saat runtime akan disebutkan nanti). Kemudian, setelah mengonfirmasi bahwa konfigurasi normal, objek RequestMappapingInfo dan Handlermethod akan ditambahkan ke Handlermethods (LinkedHashMap), dan kemudian Nilai Beranotasi Permintaan dan objek ReuqestMappapingInfo akan ditambahkan ke URLMAP.
Ringkasan sederhana dari metode registerhandlermethod
Ada tiga tanggung jawab utama dari metode ini
1. Periksa apakah konfigurasi anotasi permintaan adalah ambiguitas.
2. Bangun peta requestmappingInfo ke Handlermethod. Peta ini adalah variabel anggota handlermethods dari abstracthandlermethodmapping. LinkedHashMap.
3. Bangun Urlmap Variabel Anggota dari Abstracthandlermethodmapping dan Multivaluemap. Struktur data ini dapat dipahami sebagai peta>. Kunci tipe string menyimpan nilai anotasi requestmapping pada metode pemrosesan. Ini URI spesifik
Pertama ada pengontrol berikut
@Controller @requestMapping ("/urlmap") kelas publik urlMapController {@RequestMapping (value = "/test1", method = requestMethod.get) @ResponseBody Public String test1 () {return "Method test1"; } @RequestMapping (value = "/test1") @ResponseBody public string test2 () {return "Method test2"; } @RequestMapping (value = "/test3") @ResponseBody public string test3 () {return "Method test3"; }} Setelah inisialisasi selesai, struktur urlmap yang sesuai dengan abstracthandlermethodmapping adalah sebagai berikut
Di atas adalah proses utama inisialisasi springmvc
Proses pencarian
Untuk memahami proses pencarian, dengan sebuah pertanyaan, pengontrol berikut tersedia
@Controller @requestMapping ("/lookuptest") kelas publik lookuptestController {@RequestMapping (value = "/test1", method = requestMethod.get) @ResponseBody Public String test1 () {return "Method test1"; } @RequestMapping (value = "/test1", headers = "referer = https: //www.baidu.com") @ResponseBody public string test2 () {return "Method test2"; } @RequestMapping (value = "/test1", params = "id = 1") @ResponseBody public string test3 () {return "Method test3"; } @RequestMapping (value = "/*") @ResponseBody public string test4 () {return "Method test4"; }} Ada permintaan sebagai berikut
Metode mana yang akan dimasuki permintaan ini?
Setelah menerima permintaan, wadah web (Tomcat, Jetty) diserahkan ke DispatcherServlet untuk diproses. FrameWorServlet memanggil metode permintaan yang sesuai (misalnya: Dapatkan panggilan doget), dan kemudian memanggil metode proses proses. Setelah memasuki metode ProcessRequest, setelah serangkaian pemrosesan, masukkan metode doservice dalam baris: 936. Kemudian masukkan metode Dodispatch di line856. Dapatkan Handler Prosesor yang saat ini diminta dalam barisan: 896. Kemudian masukkan metode lookuphandlermethod dari abstracthandlermethodmapping. Kodenya adalah sebagai berikut
handlermethod yang dilindungi lookuphandlermethod (string lookuppath, httpservletRequest request) melempar pengecualian {list <cratch> matches = new ArrayList <Cath> (); // Dapatkan DirectPathmatchs berdasarkan daftar URI <T> DirectPathmatches = this.urlmap.get (lookuppath); if (DirectPathmatches! = Null) {AddMatchingMappings (DirectPathMatches, Matches, Request); } // Tidak ada permintaan pencocokan langsungMappapingInfo, mengulangi semua requestMappingInfo if (matches.isempty ()) {// tidak ada pilihan selain melalui semua pemetaan addMatchingMappings (this.handlermethods.keyset (), cocok, permintaan); } // Dapatkan Handlermethod yang sesuai dengan RequestMappingInfo terbaik MatchMapping if (! Matches.isempty ()) {comparator <Cick> comparator = new MatchComparator (getMappingComparator (request)); Collections.sort (kecocokan, pembanding); if (logger.istraceEnabled ()) {logger.trace ("found" + matches.size () + "pencocokan pemetaan untuk [" + lookuppath + "]:" + cocok); } // Periksa ambiguitas konfigurasi lagi cocok dengan BestMatch = Matches.get (0); if (match.size ()> 1) {match SecondBestMatch = matches.get (1); if (pembanding. Metode m2 = SecondBestMatch.Handlermethod.getMethod (); Lempar IllegalStateException baru ("Metode penangan yang ambigu dipetakan untuk jalur http '" + request.getRequestUrl () + "': {" + m1 + "," + m2 + "}"); }} HandLeMatch (BestMatch.Mapping, Lookuppath, Request); return BestMatch.Handlermethod; } else {return handlenomatch (handlermethods.keyset (), lookuppath, request); }} Masukkan metode lookuphandlermethod, di mana lookuppath = "/lookuptest/test1", menurut lookuppath, yaitu URI yang diminta. Langsung temukan urlmap dan dapatkan daftar requestMappingInfo yang cocok secara langsung. Di sini kami akan mencocokkan 3 requestMappingInfos. sebagai berikut
Kemudian masukkan metode AddMatchingMappings
Private Void AddMatchingMappings (koleksi <T> pemetaan, daftar <CATCH> Pencocokan, permintaan httpservletRequest) {for (t pemetaan: pemetaan) {t match = getMatchingMapping (pemetaan, permintaan); if (match! = null) {matches.add (new match (match, handlermethods.get (pemetaan))); }}} Tanggung jawab metode ini adalah untuk melintasi apakah URI yang diminta saat ini dan RequestMappingInfo di pemetaan dapat cocok, dan jika demikian, buat objek RequestMappapingInfo yang sama. Kemudian dapatkan Handlermethod sesuai dengan RequestMappingInfo. Kemudian buat objek pertandingan dan tambahkan ke daftar pertandingan. Setelah menjalankan metode AddMatchingMappings, kembali ke Lookuphandlermethod. Pada saat ini, pertandingan masih memiliki 3 objek RequestMappingInfo yang dapat cocok. Proses selanjutnya adalah mengurutkan daftar pencocokan dan kemudian mendapatkan elemen pertama dari daftar sebagai pencocokan terbaik. Mengembalikan handlermethod pertandingan. Di sini kita memasukkan metode CompareTo dari RequestMappingInfo dan lihat logika penyortiran tertentu. Kodenya adalah sebagai berikut
compareto int publik (requestMappingInfo Lainnya, permintaan httpservletRequest) {int result = polaScondition.compareto (Other.getPatternScondition (), request); if (hasil! = 0) {hasil pengembalian; } result = paramscondition.compareto (Other.getParamScondition (), request); if (hasil! = 0) {hasil pengembalian; } result = headersCondition.Competo (Other.getHeadersCondition (), Request); if (hasil! = 0) {hasil pengembalian; } result = consumercondition.compareto (Other.getConsumescondition (), request); if (hasil! = 0) {hasil pengembalian; } result = prodentescondition.compareto (Other.getProduceScondition (), Request); if (hasil! = 0) {hasil pengembalian; } result = methodScondition.compareto (Other.getMethodScondition (), request); if (hasil! = 0) {hasil pengembalian; } result = customConditionHolder.Competo (Other.CustomConditionHolder, Request); if (hasil! = 0) {hasil pengembalian; } return 0;} Seperti yang dapat Anda lihat dalam kode, urutan kecocokan adalah nilai> params> header> Consumes> menghasilkan> Metode> Kustom. Melihat ini, pertanyaan sebelumnya dapat dengan mudah dijawab. Dalam hal nilai yang sama, Params dapat cocok terlebih dahulu. Sehingga permintaan itu akan memasukkan metode test3 (). Kembali ke Lookuphandlermethod dan temukan Handlermethod. SpringMVC akan memeriksa ambiguitas konfigurasi lagi di sini. Prinsip cek di sini adalah untuk membandingkan dua requestmappingInfos dengan gelar pencocokan tertinggi. Mungkin ada pertanyaan di sini bahwa ketika menginisialisasi springmvc, ada pemeriksaan konfigurasi yang ambigu, mengapa diperiksa lagi di sini? Jika ada dua metode dalam pengontrol sekarang, konfigurasi berikut dapat diperiksa melalui ambiguitas inisialisasi.
@RequestMapping (value = "/test5", Method = {requestMethod.get, requestMethod.post})@responseBodypublic string test5 () {return "Method test5";}@requestMapping (value = "/test5, Method = {requestMethod.get, requestMethod.delete}@response6@response6@response6 {@response6 {@response6 {@response, Sekarang jalankan http: // localhost: 8080/springmvc-demo/lookuptest/test5 permintaan, dan itu akan dilemparkan ke dalam metode lookuphandlermethod
java.lang.IllegalStateException: Ambiguous handler methods mapped for HTTP path 'http://localhost:8080/SpringMVC-Demo/LookupTest/test5' pengecualian. Pengecualian dilemparkan ke sini karena metode Compareto dari RequestMethodSrequestCondition adalah nomor metode perbandingan. Kodenya adalah sebagai berikut
Public int compareto (RequestMethodSRequestCondition lainnya, permintaan httpservletrequest) {return lainnya.methods.size () - this.methods.size ();}Kapan wildcard cocok? Ketika RequestMappingInfo yang secara langsung cocok dengan nilai tidak dapat diperoleh melalui URLMAP, pencocokan wildcard akan digunakan untuk memasukkan metode AddMatchingMappings.
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.