Kata pengantar
Mengikuti artikel sebelumnya Dekripsi Musim Semi - Pendaftaran Parsing dan Bean XML, mari kita terus menganalisis kode sumber. Tanpa basa -basi lagi, mari kita lihat perkenalan yang terperinci bersama -sama.
Dekripsi
Ada dua kategori utama deklarasi dalam konfigurasi XML Spring. Salah satunya adalah yang default, seperti <bean id="person"/> , dan yang lainnya adalah yang kustom, seperti <tx:annotation-driven /> . Kedua tag tersebut memiliki metode penguraian yang sangat berbeda. Metode Parsebeandefinitions digunakan untuk membedakan metode parse yang digunakan oleh tag yang berbeda. Dapatkan namespace melalui metode node.getNamespaceURI() , tentukan apakah itu namespace default atau namespace khusus, dan bandingkan dengan namespace fixed http://www.springframework.org/schema/beans di musim semi. Jika konsisten, gunakan parseDefaultElement(ele, delegate); Kalau tidak, itu delegate.parseCustomElement(ele);
Penguraian tag default
ParsedefaultElement telah melakukan pemrosesan yang berbeda untuk 4 tag berbeda impor, alias, kacang, dan kacang. Di antara mereka, analisis tag kacang adalah yang paling kompleks dan penting, jadi kami akan memulai analisis mendalam dari kacang. Jika kita dapat memahami proses analisis tag ini, analisis tag lain secara alami akan diselesaikan. Dalam artikel sebelumnya, kami hanya menjelaskannya secara singkat. Dalam artikel ini, kami akan membahasnya secara rinci di sekitar modul analisis.
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { // import tag parsing if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } // alias tag parsing lain jika (delegate.nodenameequals (ele, alias_element)) {processaliasregistration (ELE); } // resolusi tag bean lain jika (delegate.nodenameequals (ele, bean_element)) {processBeandefinition (ele, delegate); } // Impor resolusi tag lain jika (delegate.nodenameequals (ele, nested_beans_element)) {// metode resolusi tag resolusi recursive doregisterbeandefinitions (ele); }}} Pertama, mari kita analisis processBeanDefinition(ele, delegate) di kelas
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // Delegate the parseBeanDefinitionElement method of the BeanDefinitionDelegate class for element parsing BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdholder! = null) {// Ketika bdholder yang dikembalikan tidak kosong, jika ada atribut khusus di bawah simpul anak dari label default, Anda perlu menguraikan label khusus lagi bdholder = delegate.decorateBeandefinitionifRequired (ELE, BDHOLDERER); Coba {// Setelah parsing selesai, BDHolder yang diuraikan perlu didaftarkan. Operasi pendaftaran didelegasikan ke Metode Registerbeandefinition dari BeandefinitionReaderutils.RegisterBeandefinition (BDHolder, getReaderContext (). GetRegistry ()); } catch (BeandefinitionStoreException ex) {getReaderContext (). Kesalahan ("Gagal mendaftarkan definisi kacang dengan nama '" + bdholder.getBeanName () + "'", ele, ex); } // Akhirnya, acara respons dikeluarkan untuk memberi tahu pendengar yang relevan bahwa kacang telah dimuat getReaderContext (). FirecomponentRegistered (new BeanComponentDefinition (BDHolder)); }}Dalam kode ini:
Mari kita analisis secara rinci bagaimana pegas mem -parsing setiap tag dan node
Analisis tag kacang
Kelas Publik BeandefinitionParserDelegate {@nullable Public BeandefinitionHolder ParsebeandefinitionElement (Element Ele, @Nullable Beandefinition berisi) {// Dapatkan atribut ID dari string tag bean ID = ELE.GetAttribute (ID_ATRRIBUT); // Dapatkan atribut nama dari string tag bean nameAttr = ele.getAttribute (name_attribute); Daftar <String> aliass = new ArrayList <> (); if (stringutils.haslength (nameAttr)) {// Lewati nilai atribut nama, dan pisahkan menjadi nomor string (yaitu, jika beberapa nama dikonfigurasi dalam file konfigurasi, prosesnya di sini) string [] nameArr = stringutils.TokenIzetoStringArray (nameAttr, multi_value_attribute_dibuted) (nameAttr, multi_value_attributeed) (nameattr, multi_value_attributeed) (nameAttr, multi_value_attributed) (nameattr, multi_value_attributed) (nameattr, multi_value_attributed) (nameattr, multi_value_attributed) (nameattr, multi_value_attributed); aliass.addall (arrays.aslist (namearr)); } String beanname = id; // Jika ID kosong, gunakan atribut nama depan yang dikonfigurasi sebagai ID if (! Stringutils.hastext (beanname) &&! Aliases.isempty ()) {beanname = aliass.remove (0); if (logger.isdebugeNabled ()) {logger.debug ("no xml 'id' ditentukan - menggunakan '" + beanname + "' sebagai nama kacang dan" + alias + "sebagai alias"); }} if (containingBean == null) {// Verifikasi keunikan beanname dan alias // inti internal adalah menggunakan koleksi nama yang digunakan untuk menyimpan semua nama beanname dan aliasyuniqueness (beanname, alias, ele); } // Lebih lanjut parse semua properti lain ke dalam objek Genericbeandefinition AbstractBeandefinition beandefinition = parsebeandefinitionElement (ele, beanname, containsbean); if (beandefinition! = null) {// Jika kacang tidak menentukan beanname, maka gunakan aturan default untuk menghasilkan beanname untuk bean if ini (! stringutils.hastext (beanname)) {coba {if (containingBean! = null) {beanname = beanDefinition this.readerContext.getRegistry (), true); } else {beanName = this.readercontext.generateBeanName (beandefinition); // Daftarkan alias untuk nama kelas kacang biasa, jika masih memungkinkan, // Jika generator mengembalikan nama kelas ditambah akhiran. // Ini diharapkan untuk kompatibilitas musim semi 1.2/2.0 ke belakang. String beanscasname = beandefinition.getBeanClassName (); if (beAnclassName! = null && beanname.startswith (beansclassname) && beanname.length ()> beansclassname.length () &&! this.readercontext.getregistry (). IsBeanNameUse (beansclassname)) {ALLEASES.ADIASS.ADDASS (beansname (beansclassname)) {ALLEASES.ADIASS.ADIAS (). }} if (logger.isdebugeNabled ()) {logger.debug ("Tidak ada xml 'id' atau 'nama' yang ditentukan -" + "menggunakan nama kacang yang dihasilkan [" + beanname + "]"); }} catch (Exception ex) {error (ex.getMessage (), ele); kembali nol; }} String [] aliasesArray = stringutils.tostringarray (aliass); // Encapsulate Informasi ke dalam BeandefinitionHolder Object Return New BeandefinitionHolder (Beandefinition, Beanname, AliasesArray); } return null; }} Metode ini terutama memproses atribut terkait seperti ID, nama, alias, dll., Menghasilkan beanname, dan melengkapi penguraian tag inti dalam metode kelebihan fungsi parseBeanDefinitionElement(ele, beanName, containingBean) .
Selanjutnya, fokus pada parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)
Lihat bagaimana menyelesaikan operasi parsing tag
Analisis node dan atribut kacang
@NullablePublic AbstractBeAndefinition ParsebeandefinitionElement (Element Ele, String Beanname, @nullable Beandefinition containsbean) {this.parseState.push (beanentry baru (beanname)); // Dapatkan atribut kelas dari string tag bean className = null; if (ele.hasattribute (class_attribute)) {className = ele.getAttribute (class_attribute) .trim (); } // Dapatkan atribut induk dari string tag bean Parent = null; if (ele.hasattribute (parent_attribute)) {parent = ele.getAttribute (parent_attribute); } coba {// Buat AbstractBeandefinition ke Host Atribut AbstrakBeandFinition bd = createBeandefinition (className, Parent); // Dapatkan berbagai atribut bean tag parsebeandefinitionattributes (ele, beanname, containingbean, bd); // Parse Deskripsi Tag BD.SetDescription (domutils.getChildElementValueBeebYTagname (ELE, Deskripsi_element)); // parse meta tag parsemetaelement (ele, bd); // Parse Lookup-Method Tag parselookupoverridesubelements (ele, bd.getmethodoverrides ()); // parse diganti tag parsereplacedMethodsubelements (ele, bd.getMethodoverrides ()); // parse diganti tag parsereplacedMethodsubelements (ele, bd.getMethodoverrides ()); // parse konstruktor-arg tag parseconstructorargelements (ele, bd); // parse properti tag parsepropertyelements (ele, bd); // parse kualifikasi tag parequalifierelements (ele, bd); BD.SetResource (this.readercontext.getResource ()); BD.Setsource (ExtractSource (ELE)); mengembalikan bd; } catch (classNotFoundException ex) {error ("class bean [" + className + "] tidak ditemukan", ele, ex); } catch (noClassDeffoundError err) {error ("class that bean class [" + className + "] tergantung pada tidak ditemukan", ele, err); } catch (Throwable ex) {error ("kegagalan tak terduga selama parsing definisi kacang", ele, ex); } akhirnya {this.parseState.pop (); } return null;}Lebih lanjut parse atribut dan elemen lain (ada banyak elemen dan atribut, jadi ini adalah beban kerja yang sangat besar) dan mengemasnya ke GenericBeandefinition. Setelah mem -parsing atribut dan elemen ini, jika Anda mendeteksi bahwa kacang tidak memiliki nama beanname yang ditentukan, maka Anda menggunakan aturan default untuk menghasilkan nama kacang untuk kacang.
// BeanDefinitionParserDelegate.javaprotected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName) throws ClassNotFoundException { return BeanDefinitionReaderUtils.createBeanDefinition( parentName, className, this.readerContext.getBeanClassLoader());}public class BeanDefinitionReaderUtils { public static AbstractBeanDefinition createBeanDefinition( @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException { GenericBeanDefinition bd = new Genericbeandefinition (); // ParentName mungkin kosong bd.setParentName (parentName); // Jika ClassLoader tidak kosong // maka gunakan ClassLoader yang diteruskan untuk memuat objek kelas dengan mesin virtual yang sama. Jika tidak, hanya ClassLoader yang direkam if (className! = Null) {if (classloader! = Null) {bd.setBeanClass (classutils.forname (classname, classloader)); } else {bd.setBeanClassName (className); }} return bd; }}Beandefinition adalah representasi internal dari <Bean> dalam wadah, dan beandefinition dan <Bean> adalah satu-ke-satu. Pada saat yang sama, Beandefinition akan terdaftar di Beandefinitionregistry, yang seperti database dalam memori informasi konfigurasi pegas.
Sejauh ini, createBeanDefinition(className, parent); telah selesai, dan kami juga telah memperoleh abstractbeandfinition yang digunakan untuk meng -host atribut. Mari kita lihat bagaimana parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); parsebeandefinitionattributes (ele, beanname, containingbean, bd); Parse berbagai atribut tag dalam kacang.
kelas publik beandefinitionparserdelegate {public abstractBeandfinition parsebeandefinitionAttributes (elemen ele, string beanname, @Bullable beandefinition berisi kode yang tidak dapat diatasi. Jika ada, bd.set (atribut); mengembalikan bd; }} `` `Parsing lengkap dari tag `bean` telah berakhir. Elemen yang parsing di bawah tag `bean` serupa. Jika Anda tertarik, Anda dapat melacak kode sumber dan melihat metode parsing seperti `kualifikasi, pencarian-metode` (*tidak rumit dari` bean`*). Konten tag khusus lebih rinci di bab berikutnya.
Akhirnya, merangkum informasi yang diperoleh ke dalam instance `BeandefinitionHolder`
``` java// BeanDefinitionParserDelegate.java@Nullablepublic BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containsBean) { // ... return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);}Daftarkan beandefinition parsed
Setelah parsing file konfigurasi, kami telah memperoleh semua properti kacang, dan langkah selanjutnya adalah mendaftarkan kacang
Kelas Publik BeandefinitionReaderutils {public static void registerbeandefinition (BeandefinitionHolder DefinitionHolder, Beandefinitionregistry Registry) melempar BeandefinitionStoreException {// Gunakan beanname sebagai pengidentifikasi unik beanName = Definition.getBeanname (); // Daftarkan kode inti dari registry bean.registerbeandefinition (Beanname, DefinitionHolder.getBeandefinition ()); // Daftarkan semua alias untuk string kacang [] alias = DefinitionHolder.getaliases (); if (aliass! = null) {for (string alias: alias) {registry.registeralias (beanname, alias); }}}}Kode di atas terutama menyelesaikan dua fungsi: satu adalah untuk mendaftarkan beandefinition menggunakan beanname, dan yang lainnya adalah untuk menyelesaikan pendaftaran alias.
Beanname Register Beandefinition
kelas publik defaultListableBeanFactory {@Override public void registerbeandefinition (string beanname, beandefinition beandefinition) melempar beandefinitionstoreeexception {assert.hastext (beanname, "name bean tidak boleh kosong"); Assert.notnull (beandefinition, "beandefinition tidak boleh null"); if (beandefinition instance dari AbstractBeandefinition) {try {// Verifikasi terakhir sebelum pendaftaran, verifikasi di sini berbeda dari verifikasi file XML // ini terutama untuk verifikasi MethodOverrides dalam abstrak yang tidak ada di Abstrak (MethodInden) yang ada di abstrak (MethodInden. beandefinition) .validate (); } catch (beandefinitionValidationException ex) {throw new BeandefinitionStoreException (beandefinition.getResourcedescription (), beanname, "validasi definisi kacang gagal", ex); }} Beandefinition OldBeandefinition; // Dapatkan beandefinition dalam cache oldbeandefinition = this.beandefinitionMap.get (beanname); if (oldbeandefinition! = null) {// Jika ada cache, tentukan apakah impliting diizinkan jika (! isallowbeandefinitionoverriding ()) {lempar beandefinitionstoreException (beandefinition. "getResourcedescription (), beanName," Beandefinition. "getResourcedescription (), beanName," BEANDEFINIONIONIONIONIONIONIONIONIONIONIONIONIONIONIONION "," BEANDEFINIONION "," BEANDEFINITION (), BEANDEFINIONIONIONIONIONIONIONIONIONIONIONIEM (), BEANDEFINIONIONIONIONIONIONIONIONIONIONIONIONIONIE (), BEANDEFINIONEIMEIM (" "': Sudah ada [" + oldbeandefinition + "] terikat."); } lain if (oldbeandefinition.getrole () <beandefinition.getrole ()) {// misalnya role_application, sekarang ditimpa dengan role_support atau role_infrastructure if (this.logger.iswarnenable ()) {this.logger.warn ("this.logger. Definisi kacang yang dihasilkan kerangka kerja: mengganti [" + oldbeandefinition +"] dengan [" + beandefinition +"] "); }} lain if (! beandefinition.equals (oldbeandefinition)) {if (this.logger.isinfoEnabled ()) {this.logger.info ("overriding bean Definition for bean '" + beanname + "dengan definisi yang berbeda: penggantian [" + oldbeanDefin "" + "' dengan definisi yang berbeda: balai [" + oldbeANDefin "" + "'dengan definisi yang berbeda: replacing [" + oldbeanDefin "" with "BEANDING [" + oldBeANDEFIN " +" dengan BEANTIONTIONTIONTIONIONAL "dengan definisi yang berbeda [" + oldBeANDEFIN) [" + oldBeANDEFIN" + BEANDEFINION + "dengan BEANDEFINIONDION;" }} else {if (this.logger.isdebugeNabled ()) {this.logger.debug ("definisi kacang overriding untuk kacang '" + beanname + "' dengan definisi yang setara: mengganti [" + oldbeandefinition + "] dengan [" + beanDefinisi + "]") ")") ")") ")") "); }} // Jika ditimpa diizinkan, simpan beandefinition menjadi beandefinitionmap this.beandefinitionmap.put (beanname, beandefinition); } else {// Tentukan apakah kreasi kacang telah dimulai jika (hasbeansCreationStarted ()) {// tidak dapat memodifikasi elemen pengumpulan waktu startup lagi (untuk iterasi stabil) disinkronkan (this.beandefinitionMap) {// simpan beanDefinition menjadi beandefinitionMap this.beandefinitionMinitionM. // Perbarui Daftar BeanName terdaftar <string> updateDDefinitions = new ArrayList <> (this.beandefinitionNames.size () + 1); updatedDefinitions.addall (this.beandefinitionNames); updatedDefinitions.Add (beanname); this.beandefinitionNames = updateDDefinitions; if (this.manualsingLetonNames.Contains (beanName)) {set <string> updateDeDateLeTons = new LinkedHashSet <> (this.manualsingLetonNames); Diperbarui SingleTons.Remove (Beanname); this.manualSingLeTonNames = updateSingletons; }}} else {// Saya belum mulai membuat kacang ini.beandefinitionMap.put (beanname, beandefinition); this.beandefinitionnames.add (beanname); this.manualSingLeTonnames.remove (beanname); } this.frozenBeandefinitionNames = null; } if (oldBeandefinition! = null || berisiingleton (beanname)) {// Reset cache yang sesuai dengan beanname resetBeandefinition (beanname); }}}Daftarkan alias
Setelah mendaftarkan Beandefinition, langkah selanjutnya adalah mendaftarkan alias. Hubungan yang sesuai antara alias terdaftar dan Beanname disimpan dalam alimap. Anda akan menemukan bahwa metode registeralias diimplementasikan
Public Class SimpleAsregistry { / ** peta dari alias ke nama kanonik* / peta akhir privat <string, string> alimap = concurrenthashmap baru <> (16); public void registeralias (nama string, string alias) {assert.hastext (name, "'name' tidak boleh kosong"); Assert.hastext (alias, "'alias' tidak boleh kosong"); if (alias.equals (name)) {// Jika beanname sama dengan alias, alias tidak akan direkam dan menghapus alias yang sesuai this.aliasmap.remove (alias); } else {string registeredName = this.alimapap.get (alias); if (terdaftarname! = null) {if (terdaftarname.equals (name)) {// Jika alias telah terdaftar dan nama yang ditunjuk sama dengan nama saat ini, tidak ada pemrosesan yang akan dilakukan; } // Jika alias tidak mengizinkan impliting, pengecualian akan dilemparkan jika (! Allowaliasoverriding ()) {melempar IllegalStateException baru ("tidak dapat mendaftarkan alias '" + alias + "' untuk nama '" + nama + "': sudah terdaftar untuk nama '" + terdaftar nama + "');"); }} // Poin periksa ke dependensi seperti a-> b b-> c c-> a, kesalahan terjadi checkforaliascircle (nama, alias); this.aliasmap.put (alias, nama); }}} Periksa ketergantungan melingkar alias melalui metode checkForAliasCircle() . Ketika A -> B ada, jika A -> C -> B muncul lagi, pengecualian akan dilemparkan:
Lindung void checkForAliascircle (nama string, string alias) {if (hasalias (alias, name)) {lempar baru ilegalstateException ("tidak dapat mendaftarkan alias '" + alias + "' untuk nama '" + "" Aleas "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "Alias +" Alias + "" Alias ALIAS; }} public boolean hasalias (nama string, string alias) {for (map.entry <string, string> entri: this.aliasmap.entryset ()) {string registeredName = entry.getValue (); if (registeredName.equals (name)) {string registeredalias = entry.getKey (); return (registeredalias.equals (alias) || hasalias (registeredalias, alias)); }} return false;}Pada titik ini, pendaftaran alias telah selesai, dan tugas -tugas berikut telah selesai.
Kirim Pemberitahuan
Beri tahu pendengar untuk diuraikan dan terdaftar
//DefaultbeandefinitionDocumentReader.javaprotected void ProcessBandefinition (Element Ele, BeandefinitionParserDelegate Delegate) {// Kirim acara pendaftaran. getReaderContext (). FireComponentRegistered (new BeanComponentDefinition (BDHolder));}Metode FirecomponentRegistered digunakan untuk memberi tahu pendengar untuk menguraikan dan mendaftarkan pekerjaan. Implementasi di sini hanya untuk ekstensi. Ketika pengembang program perlu mendengarkan acara beandefinition terdaftar, ia dapat mendaftarkan pendengar dan menulis logika pemrosesan ke pendengar. Saat ini, Spring tidak menangani acara ini di acara ini
ReaderContext dihasilkan dengan menelepon createreadercontext di kelas XMLBeandefinitionReader, dan kemudian memanggil fireComponentRegistered()
Analisis tag alias
Spring menyediakan konfigurasi alias untuk <alias name="person" alias="p"/> . Resolusi tag dilakukan dalam metode ProcessaliAsregistration (Element ELE).
kelas publik defaultBeandefinitionDocumentReader {Protected void ProcessaliAsregistration (elemen ele) {// Dapatkan nama tag alisa name string nama = ele.getAttribute (name_attribute); // Dapatkan alisa tag alisa tag alias atribut string alias = ele.getAttribute (alias_attribute); Boolean valid = true; if (! stringutils.hastext (name)) {getReaderContext (). error ("name tidak boleh kosong", ele); valid = false; } if (! stringutils.hastext (alias)) {getReaderContext (). error ("alias tidak boleh kosong", ele); valid = false; } if (valid) {coba {// Register alias getReaderContext (). getRegistry (). registerAlias (name, alias); } catch (Exception ex) {getReaderContext (). error ("Gagal mendaftarkan alias '" + alias + "' untuk kacang dengan nama '" + name + "'", ele, ex); } // Setelah mendaftarkan alias, beri tahu pendengar untuk melakukan pemrosesan yang sesuai getReaderContext (). Firealiasegistered (nama, alias, ExtractSource (ELE)); }}}Pertama, atribut tag alias diekstraksi dan diverifikasi. Setelah verifikasi disahkan, pendaftaran alias dilakukan. Pendaftaran dan pendaftaran alias dalam analisis tag kacang telah dilakukan. Saya tidak akan mengulanginya di sini.
analisis tag impor
kelas publik defaultBeandefinitionDocumentReader {Protected void ImportBeandefinitionResource (elemen ele) {// Dapatkan atribut sumber daya dari lokasi string tag impor = ELE.GetAttribute (Resource_Attribute); // Jika tidak ada, tidak ada pemrosesan yang dilakukan jika (! Stringutils.hastext (lokasi)) {getReaderContext (). Kesalahan ("Lokasi sumber daya tidak boleh kosong", ele); kembali; } // format atribut placeholder parsing seperti "$ {user.dir}" location = getReaderContext (). Getenvironment (). ResolverquiredplaceHolder (lokasi); Set <seragaraan> Sumber aktual = LinkedHashset baru <> (4); // Tentukan apakah sumber daya merupakan jalur absolut atau jalur relatif boolean absolutelocation = false; coba {absolutelocation = resourcePatternutils.isUrl (lokasi) || Resourceutils.touri (lokasi) .isabsolute (); } catch (UrisyntaxException ex) {// Tidak dapat dikonversi ke URI, mempertimbangkan relatif lokasi // kecuali itu adalah awalan pegas yang terkenal "classpath*:"} // Jika itu adalah jalur absolut, file konfigurasi yang sesuai akan dimuat secara langsung sesuai dengan alamat jika (absolutelocation) {try {int Importcount = = getReaderContext (). getReader (). LoadBeandefinitions (Lokasi, ActualResources); if (logger.isdebugeNabled ()) {logger.debug ("diimpor" + importCount + "definisi kacang dari lokasi url [" + lokasi + "]"); }} catch (beandefinitionStoreException ex) {getReaderContext (). Kesalahan ("Gagal mengimpor definisi kacang dari lokasi url [" + lokasi + "]", ele, ex); }} else {coba {int importCount; // Muat sumber daya sesuai dengan relatif relatif sumber daya relativerSource = getReaderContext (). GetResource (). Createrelative (lokasi); if (RELATIVERSOURCE.EXIST ()) {importCount = getReaderContext (). getReader (). LoadBeandefinitions (RelativerSource); ActualResources.Add (Relativeresource); } else {string baselocation = getReaderContext (). getResource (). getUrl (). ToString (); importCount = getReaderContext (). getReader (). LoadBeandefinitions (Stringutils.ApplyrelativePath (Baselocation, Location), ActualResources); } if (logger.isdebugeNabled ()) {logger.debug ("diimpor" + importCount + "definisi kacang dari lokasi relatif [" + lokasi + "]"); }} catch (ioException ex) {getReaderContext (). error ("Gagal menyelesaikan lokasi sumber daya saat ini", ELE, EX); } catch (BeandefinitionStoreException ex) {getReaderContext (). Kesalahan ("Gagal mengimpor definisi kacang dari lokasi relatif [" + lokasi + "], ele, ex); }} // Setelah parsing, pemrosesan aktivasi pendengar dilakukan. Sumber daya [] actresArray = aktual sumber daya. getReaderContext (). FireImportProced (Lokasi, ActresArray, ExtractSource (ELE)); }} Setelah menyelesaikan pemrosesan tag impor, hal pertama adalah untuk mendapatkan jalur yang diwakili oleh atribut sumber daya <import resource="beans.xml"/> , kemudian parsing placeholder atribut di jalur seperti ${user.dir} , dan kemudian tentukan apakah lokasi tersebut merupakan jalur absolut atau jalur relatif. Jika ini merupakan jalur absolut, proses penguraian kacang disebut rekursif (loadBeanDefinitions(location, actualResources);) untuk melakukan analisis lain. Jika itu adalah jalur relatif, hitung jalur absolut dan parsing. Akhirnya, beri tahu pendengar dan parsing selesai.
Meringkaskan
Setelah beberapa musim gugur, musim dingin, musim semi, dan musim panas yang tidak diketahui, semuanya akan mengikuti arah yang Anda inginkan ...
Oke, 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.
Katakan sesuatu
Kode Teks Lengkap: https://gitee.com/battcn/battcn-spring-source/tree/master/chapter1 (unduhan lokal)