مقدمة
بعد المقالة السابقة Dring Decryption - تحليل XML وتسجيل الفول ، دعنا نستمر في تحليل الكود المصدري. بدون مزيد من اللغط ، دعونا نلقي نظرة على المقدمة التفصيلية معًا.
فك التشفير
هناك فئتان رئيسيتان من الإعلانات في تكوين XML في الربيع. أحدهما هو الافتراضي ، مثل <bean id="person"/> ، والآخر هو المخصص ، مثل <tx:annotation-driven /> . العلامتين لهما طرق تحليل مختلفة للغاية. يتم استخدام طريقة parsebeandefinitions لتمييز طرق التحليل المستخدمة بواسطة علامات مختلفة. احصل على مساحة الاسم من خلال طريقة node.getNamespaceURI() ، وحدد ما إذا كانت مساحة اسم افتراضية أو مساحة اسم مخصصة ، وقارنها مع مساحة الاسم الثابتة http://www.springframework.org/schema/beans في الربيع. إذا كان ثابتًا ، فاستخدم parseDefaultElement(ele, delegate); خلاف ذلك ، فهو delegate.parseCustomElement(ele);
تحليل العلامات الافتراضية
قام ParsEdefaultElement بمعالجة مختلفة لـ 4 علامات مختلفة استيراد ، الاسم المستعار ، الفاصوليا ، والفاصوليا. من بينها ، تحليل علامات الفول هو الأكثر تعقيدًا وأهمية ، لذلك سنبدأ التحليل المتعمق من الفول. إذا تمكنا من فهم عملية تحليل هذه العلامة ، فسيتم حل تحليل العلامات الأخرى بشكل طبيعي. في المقالة السابقة ، نصفها بإيجاز. في هذه المقالة ، سنناقشها بالتفصيل حول وحدة التحليل.
الطبقة العامة DefaultBeanDefinitionDocumentReader تنفذ beandefinitiondocumentreader {private void parsedefaultelement (element ele ، beandefinitionparserdelegate depegate) {// elempianting tag if (devate.nodenameequals (ele ، elem_element)) }. } // دقة علامات الفول الأخرى إذا (devate.nodenameequals (eLe ، bean_element)) {processBeanDefinition (eLe ، depate) ؛ } // استيراد دقة علامة أخرى إذا (devate.nodenameequals (eLE ، nested_beans_element)) {// beans tag desolution method doregisterbeandefinitions (eLE) ؛ }}} أولاً ، دعنا نحلل processBeanDefinition(ele, delegate) في الفصل
processpeandefinition المحمية المحمية (Element ELE ، BeanDefinitionParserDelegate مندوب) {// تفويض طريقة parsebeandefinitionlement من فئة BeanDefinitionDelegate ل Parsingiping Beandefinitionholder Bdholder = مندوب. إذا (bdholder! = null) {// عندما يكون Bdholder الذي تم إرجاعه فارغًا ، إذا كانت هناك سمة مخصصة تحت العقدة الفرعية للعلامة الافتراضية ، فأنت بحاجة إلى تحليل التسمية المخصصة مرة أخرى bdholder = devate.decoreBeanDefinitionifrequired (ele ، bdholder) ؛ حاول {// بعد اكتمال التحليل ، يجب تسجيل حامل BDHOLED. يتم تفويض عملية التسجيل إلى طريقة registerBeanDefinition لـ BeanDefinitionReaderUtils.RegisterBeanDefinition (BDHolder ، getReaderContext (). getRegistry ()) ؛ } catch (BeanDefinitionStoreException ex) {getReaderContext (). error ("فشل في تسجيل تعريف الفول بالاسم" + bdholder.getBeanname () + "'' ، ele ، ex) ؛ } // أخيرًا ، يتم إصدار حدث استجابة لإخطار المستمع ذي الصلة بأن الفول قد تم تحميل getReaderContext (). }}في هذا الرمز:
دعونا نحلل بالتفصيل كيف يخلع الربيع كل علامة وعقدة
تحليل علامة الفول
الفئة العامة BeanDefinitionParserDelegate {nullablebulable BeanDefinitionholder ParsebeanDefinitionElement (Element ele ، @nullable continsbean) {// احصل على سمة المعرف لمعرف سلسلة الفول = ele.getattribute (id_attribute) ؛ // احصل على سمة الاسم لسلسلة العلامة Bean nameattr = eLe.GetAttribute (name_attribute) ؛ قائمة <Tring> aliases = new ArrayList <> () ؛ if (stringUtils.hasLength (nameattr)) {// تمرير قيمة سمة الاسم ، وقسمها إلى رقم سلسلة (أي ، إذا تم تكوين أسماء متعددة في ملف التكوين ، قم بمعالجته هنا) String [] namearr = stringutils.tokenizetoStringArray (nameattr ، multi_value_attribute_delimiters) ؛ aliases.addall (arrays.aslist (namearr)) ؛ } String Beanname = id ؛ // إذا كان المعرف فارغًا ، فاستخدم سمة الاسم الأول المكون كمعرف إذا (! stringUtils.hastext (beanname) &&! aliases.isempty ()) {beanname = aliases.remove (0) ؛ if (logger.isdebugenabled ()) {logger.debug ("no xml 'id' المحددة - باستخدام '" + beanname + "as as bean name و" + alases + "as leases") ؛ }} if (contineBean == NULL) {// تحقق من تفرد Beanname و Aliases // CORE الداخلي هو استخدام مجموعة الأسماء المستخدمة لإنقاذ جميع beanname و aliasesuniquence المستخدمة (beanname ، leases ، ele) ؛ }. if (beandefinition! = null) {// إذا لم تحدد الفول beanname ، فاستخدم القاعدة الافتراضية لإنشاء beanname لهذا الفاصوليا إذا (! stringUtils.hastext (beanname)) this.readercontext.getRegistry () ، true) ؛ } else {beanname = this.readerContext.generateBeanName (BeanDefinition) ؛ . // من المتوقع أن يكون هذا التوافق الخلفي في الربيع 1.2/2.0. String beanclassName = BeanDefinition.getBeanClassName () ؛ if (beanclassname! = null && beanname.startswith (beanclassName) && beanname.length ()> beanclassname.length () &&! this.readercontext.getregistry (). isbeannameinuse (beanclassname)) }} if (logger.isdebugenabled ()) {logger.debug ("لا xml 'id' ولا" الاسم "المحدد -" + "باستخدام اسم الفول المولد [" + beanname + "]") ؛ }} catch (استثناء ex) {error (ex.getMessage () ، eLe) ؛ العودة لاغية. }} string [] aliasesarray = stringUtils.ToStringArray (alases) ؛ . } إرجاع فارغ ؛ }} تقوم هذه الطريقة بشكل رئيسي بمعالجة السمات ذات الصلة مثل المعرف والاسم والاسم المستعار ، وما إلى ذلك ، وتولد Beanname ، وتكمل تحليل العلامة الأساسية في وظيفة parseBeanDefinitionElement(ele, beanName, containingBean) .
بعد ذلك ، ركز على parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)
انظر كيف تكمل عملية تحليل العلامة
عقدة الفول وتحليل السمات
@nullablepublic AbstractBeanDefinition ParsebeanDefinitionElement (Element ele ، String Beanname ، @nullable containsbean) // احصل على سمة الفئة من className ClassName = null ؛ if (ele.hasattribute (class_attribute)) {className = eLe.getAttribute (class_attribute) .trim () ؛ } // احصل على السمة الأصل لسلسلة العلامة بين الوالدين = null ؛ if (ele.hasattribute (parent_attribut)) {parent = eLe.getAttribute (parent_attribute) ؛ } جرب {// إنشاء ustrultBeanDefinition لاستضافة سمات accticbeandefinition bd = createBeanDefinition (className ، parent) ؛ // احصل على سمات مختلفة من علامة الفول parsebeandefinitionattributes (ele ، beanname ، continingbean ، bd) ؛ // parse description tag bd.setDescription (domutils.getChildElementValuebyTagname (ele ، description_element)) ؛ // parse meta tag parsemetaelements (ele ، bd) ؛ // parse lookup-method tag parselookupoverridesubelements (ele ، bd.getMethodoverRides ()) ؛ // parse استبدال علامة method parsereplacedMethodSubelements (eLe ، bd.getMethodoverRides ()) ؛ // parse استبدال علامة method parsereplacedMethodSubelements (eLe ، bd.getMethodoverRides ()) ؛ // parse constructor-arg tag parseconstructorArgelements (ELE ، BD) ؛ // Parse Property Tag ParsePropertyElements (ELE ، BD) ؛ // parse التصفيات علامة parequalifierElements (ELE ، BD) ؛ bd.setResource (this.readercontext.getResource ()) ؛ Bd.SetSource (ExtractSource (ELE)) ؛ إرجاع BD ؛ } catch (classnotfoundException ex) {error ("Bean Class [" + className + "] غير موجود" ، ele ، ex) ؛ } catch (noclassDeffounderror err) {error ("class that bean class [" + className + "] تعتمد على عدم العثور عليها" ، eLe ، err) ؛ } catch (throwable ex) {error ("فشل غير متوقع أثناء تحليل تعريف الفول" ، eLe ، ex) ؛ } أخيرًا {this.parsestate.pop () ؛ } إرجاع فارغ ؛}مزيد من التحليل للسمات والعناصر الأخرى (هناك العديد من العناصر والسمات ، لذلك هذا عبء عمل ضخم) وقم بتعبئتها في التعريف العام. بعد تحليل هذه السمات والعناصر ، إذا اكتشفت أن الحبة لا تحتوي على beanname محدد ، فأنت تستخدم القواعد الافتراضية لإنشاء beanname للفول.
) BeanDefinitionReaderUtils {public static ustrultbeandefinition createBeanDefinition ( @nullable string parentname ، nullable string className ، @nullable classloader classloader) يلقي classnotfoundException {genericbeandefinition bd = new genericbeanfinition () ؛ // قد يكون اسم ParentName فارغًا bd.setParentName (اسم الوفل) ؛ // إذا لم يكن ClassLoader فارغًا // ، فاستخدم جهاز تحميل classed لتحميل كائن الفئة مع نفس الجهاز الظاهري. خلاف ذلك ، يتم تسجيل فقط classloader إذا (className! = null) {if (classloader! = null) {bd.setBeanClass (classutils.forname (className ، classloader)) ؛ } آخر {bd.setBeanClassName (className) ؛ }} return bd ؛ }}BeanDefinition هو تمثيل داخلي لـ <bean> في حاوية ، و Beandefinition و <bean> هم واحد إلى واحد. في الوقت نفسه ، سيتم تسجيل BeanDefinition في BeanDefinitionregistry ، والتي تشبه قاعدة بيانات الذاكرة لمعلومات تكوين الربيع.
حتى الآن ، createBeanDefinition(className, parent); لقد انتهى ، وقد حصلنا أيضًا على ustrultBeanDefinition المستخدم لاستضافة السمات. دعونا نلقي نظرة على كيفية parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); ParsebeanDefinitionAttributes (ele ، beanname ، continingbean ، bd) ؛ تحليل سمات العلامات المختلفة في الفاصوليا.
الفئة العامة beandefinitionparserdelegate {public abstractbeandefinition parsebeanDefinitionTributes (element ele ، string beanname ، @nullable BeanDefinition يحدد بشكل رئيسي ما إذا كان ذلك يحتوي على ما إذا كان ذلك محددًا. إذا كان هناك ، bd.set (السمة) ؛ إرجاع BD ؛ }} `` `انتهى التحليل الكامل لعلامة "الفول". العنصر التحليلي تحت علامة "الفول" مشابه. إذا كنت مهتمًا ، فيمكنك تتبع الكود المصدري ورؤية أساليب التحليل مثل "التصفيات المؤهلة ، وطرق البحث" (*ليست معقدة من "بين"*). محتوى العلامة المخصص أكثر تفصيلًا في الفصل التالي.
أخيرًا ، قم بتغليف المعلومات التي تم الحصول عليها في مثيل `beandefinitionholder`
`` `java // beandefinitionparserdelegate.java@nullablepublicpublic beandefinitionholder parsebeanDefinitionElement (element ele ، @nullable beandefinition convalbean) ؛
تسجيل الفاصوليا المحفورة
بعد تحليل ملف التكوين ، حصلنا على جميع خصائص الفول ، والخطوة التالية هي تسجيل الفول
الفئة العامة BeanDefinitionReaderUtils {public static void registerbeandefinition (BeanDefinitionHolderder ، RESARTER BeanDefinitionregistry) يلقي BeanDefinitionStoreException {// استخدام beanname كمعرف فريد من نوعه = defintionholderder.getbeanname () ؛ . // تسجيل جميع الأسماء المستعارة لسلسلة الفول [] الأسماء المستعارة = التعريف holder.getaliases () ؛ if (alases! = null) {for (string alias: aliases) {registry.registeralias (beanname ، alias) ؛ }}}}يكمل الرمز أعلاه بشكل أساسي وظيفتين: إحداها هي تسجيل BeanDefinition باستخدام Beanname ، والآخر هو إكمال تسجيل الاسم المستعار.
Beanname سجل Beandefinition
الفئة العامة defaultListableBeanfactory {Override public void registerBeanDefinition (سلسلة beanname ، beandefinition beandefinition) يلقي beandefinitionstoreException {Assert.hastext (beanname ، "يجب ألا يكون اسم الفول فارغًا") ؛ Assert.notnull (BeanDefinition ، "يجب ألا يكون BeanDefinition فارغًا") ؛ إذا كان (مثيل BeanDefinition extryof AbstractBeanDefinition) {try {// آخر التحقق قبل التسجيل ، فإن التحقق هنا يختلف عن التحقق من ملف XML // إنه أمر أساسي بالنسبة لعلم الأسلوب في rexctractbeandeition) beandefinition) .validate () ؛ } catch (BeanDefinitionValidationException ex) {رمي جديد beandefinitionStoreException (beandefinition.getResourCedescription () ، beanname ، "التحقق من تعريف الفاصوليا" ، على سبيل المثال) ؛ }} beandefinition oldbeandefinition ؛ // احصل على beandefinition في ذاكرة التخزين المؤقت oldbeandefinition = this.beanDefinitionMap.get (beanname) ؛ إذا كان (oldbeandefinition! = null) {// إذا كان هناك ذاكرة التخزين المؤقت ، فحدد ما إذا كان يتم السماح بما إذا كان (! isallowbeandefinitionoverriding ()) {رمي جديد beandefinitionStoreException (BeanDefinition.getResourcedes () ، beanname ، " oldbeandefinition + "] ملزمة.") ؛ } آخر إذا كان (oldbeandefinition.getRole () <beandefinition.getRole ()) {// eg كان rob_application ، والآن يتغلب على rob_support أو robe_infrustructure if (this.logger.iswarnenabled ()) التعريف: استبدال [" + oldbeandefinition +"] مع [" + beandefinition +"] ") ؛ }} آخر if (! beandefinition.equals (oldbeandefinition)) {if (this.logger.isinfoenabled ()) {this.logger.info ("تعريف الفاصوليا المتجاوز لـ Bean '" + Beanname + "' مع تعريف مختلف: استبدال [" + oldbeandefinition + "] مع [ +" + ". }} else {if (this.logger.isdebugenabled ()) {this.logger.debug ("تعريف الفاصوليا المتجاوز للفول" + beanname + "" مع تعريف مكافئ: استبدال [ + oldbeandefinition + "] مع [" + beandefinition + "]") ؛ }} // إذا تم السماح بالكتابة فوق ، احفظ beandefinition في beandefinitionmap this.beanDefinitionMap.put (beanname ، beandefinition) ؛ } آخر {// حدد ما إذا كان إنشاء الفول قد بدأ إذا لم يعد (hasbeancreationStarted ()) {// تعديل عناصر تجميع وقت بدء التشغيل بعد الآن (للتكرار المستقر) متزامن (this.beandefinitionmap) {// save beandefinition في beandefinitionmap this.beandefinitionmap. // تحديث قائمة beanname المسجلة <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> updatedSingletons = new LinkedHashset <> (this.manualsingletonnames) ؛ updatedsingletons.remove (beanname) ؛ this.manualsingletonnames = updatedsingletons ؛ }}} آخر {// لم أبدأ في إنشاء الفاصوليا بعد هذا. this.beandefinitionnames.add (beanname) ؛ this.manualsingletonnames.remove (beanname) ؛ } this.frozenbeanDefinitionNames = null ؛ } if (oldbeandefinition! = null || continsingleton (beanname)) {// إعادة تعيين ذاكرة التخزين المؤقت المقابلة لـ beanname refetBeanDefinition (beanname) ؛ }}}تسجيل الاسم المستعار
بعد تسجيل BeanDefinition ، فإن الخطوة التالية هي تسجيل الاسم المستعار. يتم تخزين العلاقة المقابلة بين الاسم المستعار المسجل واسم Beanname في الاسم المستعار. ستجد أن طريقة التسجيل يتم تنفيذها في SimpleAliasregistry
الفئة العامة simplealiasregistry { / ** خريطة من الاسم المستعار إلى الاسم الكنسي* / الخريطة النهائية الخاصة <string ، string> aliasmap = concurrenthashmap new concurrenthashmap <> (16) ؛ public void registerAlias (اسم السلسلة ، السلسلة الاسم المستعار) {Assert.hastext (الاسم ، "اسم" يجب ألا يكون فارغًا ") ؛ Assert.hastext (الاسم المستعار ، "الاسم المستعار" يجب ألا يكون فارغًا ") ؛ إذا كان (alias.equals (name)) {// إذا كان beanname هو نفسه الاسم المستعار ، فلن يتم تسجيل الاسم المستعار وحذف الاسم المستعار المقابل this.aliasmap.remove (الاسم المستعار) ؛ } آخر {string jectedName = this.aliasmap.get (alias) ؛ if (registerName! = null) {if (registerName.equals (name)) {// إذا تم تسجيل الاسم المستعار وتم توجيه الاسم إليه هو نفس الاسم الحالي ، فلن تتم أي معالجة ؛ } // إذا كان الاسم المستعار لا يسمح بالكتابة الزائدة ، فسيتم طرح استثناء إذا (! allowAliasOverriding ()) {رمي جديد غير aluvalstateException ("لا يمكن تسجيل اسم" + alias + "" للاسم " + name +" ": إنه مسجل بالفعل للاسم" + registerName + "". ") ؛ }} // نقاط حلقة الشيكات إلى التبعيات مثل a-> b-> c c-> a ، يحدث خطأ checkforaliasCircle (الاسم ، الاسم المستعار) ؛ this.aliasmap.put (الاسم المستعار ، الاسم) ؛ }}} تحقق من التبعية الدائرية الاسم المستعار من خلال طريقة checkForAliasCircle() . عند وجود A -> B ، إذا ظهر A -> C -> B مرة أخرى ، سيتم طرح استثناء:
checkforeforaliascircle المحمي (اسم السلسلة ، السلسلة الاسم المستعار) {if (hasalias (alias ، name)) {رمي جديد alualtStateException ("لا يمكن تسجيل الاسم المستعار" + alias + "'for name" + name + "': circular - '" + "name +"' 'هو غير مستقر أو غير مستقر " + alias +"' 'بالفعل ") ؛ }} public boolean hasalias (اسم السلسلة ، الاسم المستعار السلسلة) {for (map.entry <string ، string> entry: this.aliasmap.entrySet ()) {String registerName = intplic.getValue () ؛ if (regignedName.equals (name)) {String registerEdalias = entrate.getKey () ؛ العائد (registeredalias.equals (الاسم المستعار) || hasalias (registeredalias ، alias)) ؛ }} إرجاع خطأ ؛}في هذه المرحلة ، تم الانتهاء من تسجيل الاسم المستعار ، وتم الانتهاء من المهام التالية.
إرسال إشعار
إخطار المستمع ليتم تحليله وتسجيله
. getReaderContext ().
يتم استخدام طريقة FireComponentRegistered لإخطار المستمع لتحليل وتسجيل العمل. التنفيذ هنا هو فقط للتمديد. عندما يحتاج مطور البرنامج إلى الاستماع إلى حدث BeanDefinition المسجل ، يمكنه تسجيل المستمع وكتابة منطق المعالجة إلى المستمع. حاليا ، الربيع لا يتعامل مع هذا الحدث في هذا الحدث
يتم إنشاء readercontext عن طريق الاتصال بالتواصل مع createreadercontext في الفئة xmlbeandefinitionReader ، ثم استدعاء fireComponentRegistered()
تحليل علامة الاسم المستعار
يوفر الربيع تكوين الاسم المستعار للاسم <alias name="person" alias="p"/> . تتم دقة العلامة في طريقة WorporiasRegistration (Element ELE).
الفئة العامة defaultBeanDefinitionDocumentReader {protected void processAliasRegistration (element ele) {// get alisa tag name name string name = ele.getattribute (name_attribute) ؛ // Get Alisa Tag Alisa Tag alias string alias = ele.getAttribute (alias_attribute) ؛ منطقية صالحة = صواب ؛ if (! stringUtils.hastext (name)) {getReaderContext (). خطأ ("يجب ألا يكون الاسم فارغًا" ، eLe) ؛ صالح = خطأ ؛ } if (! stringUtils.hastext (alias)) {getReaderContext (). خطأ ("يجب ألا يكون الاسم فارغًا" ، eLe) ؛ صالح = خطأ ؛ } if (صالح) {try {// register alias getReaderContext (). } catch (استثناء ex) {getReaderContext (). خطأ ("فشل في تسجيل الاسم المستعار '" + alias + "' for bean with name '" + name + "' '، ele ، ex) ؛ } // بعد تسجيل الاسم المستعار ، أخبر المستمع أن يقوم بالمعالجة المقابلة getReaderContext (). firealiasregistered (الاسم ، الاسم المستعار ، المستخلص (ELE)) ؛ }}}أولاً ، يتم استخراج سمة علامة الاسم المستعار والتحقق منها. بعد تمرير التحقق ، يتم تسجيل الاسم المستعار. تم تسجيل الاسم المستعار وتسجيل الاسم المستعار في تحليل علامة الفول. لن أكررها هنا.
تحليل علامة الاستيراد
الفئة العامة DefaultBeanDefinitionDocumentReader {محمية void importBeanDefinitionResource (element ele) {// احصل على السمة المورد لموقع سلسلة الاستيراد = ele.getAttribute (Resource_attribute) ؛ // إذا لم يكن موجودًا ، فلا تتم معالجة إذا (! stringUtils.hastext (location)) {getReaderContext (). خطأ ("يجب ألا يكون موقع المورد فارغًا" ، eLe) ؛ يعود؛ }. SET <Sresource> agaulResources = New LinkedHashSet <> (4) ؛ // تحديد ما إذا كان المورد مسارًا مطلقًا أو مسارًا نسبيًا منطقيًا المطلقة = خطأ ؛ جرب {Abssolblocation = resourceptintnutils.isurl (location) || ResourceUtils.touri (الموقع) .isabsolute () ؛ } catch (urisyntaxexception ex) {// لا يمكن تحويل إلى URI ، بالنظر إلى الموقع النسبي // ما لم يكن بادئة الربيع المعروفة "classpath*:"} // إذا كان مسارًا مطلقًا ، فسيتم تحميل ملف التكوين المقابل () فعليات) ؛ if (logger.isdebugenabled ()) {logger.debug ("مستوردة" + importCount + "تعريفات الفول من موقع url [" + location + "]") ؛ }} catch (BeanDefinitionStoreException ex) {getReaderContext (). خطأ ("فشل في استيراد تعريفات الفاصوليا من موقع url [" + location + "] ، ele ، ex) ؛ }} آخر {try {int importCount ؛ // قم بتحميل المورد وفقًا لموارد المسار النسبي relativeresource = getReaderContext (). getResource (). createrelative (الموقع) ؛ if (relativeresource.exists ()) {importCount = getReaderContext (). getReader (). ReactResources.Add (Relativeresource) ؛ } آخر {String baseLocation = getReaderContext (). getResource (). geturl (). toString () ؛ importCount = getReaderContext (). getReader (). loadBeanDefinitions (stringUtils.ApplyRelative (BaseLocation ، الموقع) ، REACTERSOURCES) ؛ } if (logger.isdebugenabled ()) {logger.debug ("مستوردة" + importCount + "تعريفات الفول من الموقع النسبي [" + location + "]") ؛ }} catch (ioException ex) {getReaderContext (). خطأ ("فشل في حل موقع الموارد الحالي" ، ele ، ex) ؛ } catch (BeanDefinitionStoreException ex) {getReaderContext (). خطأ ("فشل في استيراد تعريفات الفاصوليا من الموقع النسبي [" + location + "] ، ele ، ex) ؛ }} // بعد التحليل ، يتم تنفيذ معالجة تنشيط المستمع. Resource [] ActresArray = agaulResources.toarray (مورد جديد [stualresources.size ()]) ؛ getReaderContext (). }} بعد الانتهاء من معالجة علامة الاستيراد ، فإن أول شيء هو الحصول على المسار الذي يمثله سمة <import resource="beans.xml"/> ، ثم تحليل العنصر النائب في المسار مثل ${user.dir} ، ثم تحديد ما إذا كان الموقع مسارًا مطلقًا أو مسارًا نسبيًا. إذا كان مسارًا مطلقًا ، فسيتم تسمية عملية تحليل الفول بشكل متكرر (loadBeanDefinitions(location, actualResources);) لإجراء تحليل آخر. إذا كان مسارًا نسبيًا ، فقم بحساب المسار المطلق وحوضه. أخيرًا ، أبلغ المستمع ويتم الانتهاء من التحليل.
لخص
بعد بضع خريف غير معروف ، الشتاء والربيع والصيف ، سيتبع كل شيء الاتجاه الذي تريده ...
حسنًا ، ما سبق هو المحتوى الكامل لهذه المقالة. آمل أن يكون لمحتوى هذه المقالة قيمة مرجعية معينة لدراسة أو عمل الجميع. إذا كان لديك أي أسئلة ، فيمكنك ترك رسالة للتواصل. شكرا لك على دعمك إلى wulin.com.
قل شيئا
رمز النص الكامل: https://gitee.com/battcn/battcn-spring-source/tree/master/chapter1 (تنزيل محلي)