คำนำ
หลังจากบทความก่อนหน้านี้ถอดรหัสสปริง - การแยกวิเคราะห์ 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 แท็กนามแฝงถั่วและถั่ว ในหมู่พวกเขาการวิเคราะห์แท็กถั่วนั้นซับซ้อนและสำคัญที่สุดดังนั้นเราจะเริ่มการวิเคราะห์เชิงลึกจากถั่ว หากเราสามารถเข้าใจกระบวนการวิเคราะห์ของแท็กนี้การวิเคราะห์แท็กอื่น ๆ จะได้รับการแก้ไขตามธรรมชาติ ในบทความก่อนหน้านี้เราเพิ่งอธิบายสั้น ๆ ในบทความนี้เราจะหารือเกี่ยวกับรายละเอียดเกี่ยวกับโมดูลการวิเคราะห์
ระดับสาธารณะเริ่มต้น BEANDEFINITIONDOCUMENTREADER ใช้ BEANDEFINITIONDOCUMENTREADER {Void Private ParsedefaultElement (Element Ele, BeanDefinitionParserDelegate Delegate) {// นำเข้าแท็กการแยกวิเคราะห์ (delegate.nodenameequals } // นามแฝงแท็กการแยกวิเคราะห์อื่นถ้า (delegate.nodenameeQuals (ele, alias_element)) {processualiasregistration (ELE); } // ความละเอียดแท็กถั่วอื่นถ้า (delegate.nodenameeQuals (ele, bean_element)) {processBeanDefinition (Ele, ผู้แทน); } // นำเข้าความละเอียดแท็กอื่นถ้า (delegate.nodenameeQuals (ele, nested_beans_element)) {// ถั่วความละเอียดแท็กวิธีการเรียกซ้ำวิธี Doregisterbeandefinitions (ELE); - ก่อนอื่นให้วิเคราะห์ processBeanDefinition(ele, delegate) ในชั้นเรียน
Void ProcessBeanDefinition (Element ELE, BEANDEFINITIONPARSERDELEGATE ผู้แทน) {// มอบหมายวิธีการ parsebeanDefinitionElement ของ BEANDEFINITIONDELEGATE สำหรับองค์ประกอบการวิเคราะห์ความเป็นอยู่ ถ้า (bdholder! = null) {// เมื่อ bdholder ที่ส่งคืนไม่ว่างเปล่าหากมีแอตทริบิวต์ที่กำหนดเองภายใต้โหนดลูกของฉลากเริ่มต้นคุณจะต้องแยกวิเคราะห์ฉลากที่กำหนดเองอีกครั้ง bdholder = มอบหมาย ลอง {// หลังจากการแยกวิเคราะห์เสร็จสิ้นผู้ถือหุ้นที่แยกวิเคราะห์จะต้องลงทะเบียน การดำเนินการลงทะเบียนได้รับการมอบหมายให้ใช้วิธีการลงทะเบียนของ BEANDEFINITIONREADERUTILS.REGISTERBEANDEFINITION (BDHOLDER, GETREADERCONTEXT (). getRegistry ()); } catch (beandefinitionstoreexception ex) {getReaderContext (). ข้อผิดพลาด ("ล้มเหลวในการลงทะเบียนนิยามถั่วด้วยชื่อ '" + bdholder.getBeanName () + "" ", ele, ex); } // ในที่สุดเหตุการณ์การตอบกลับจะออกเพื่อแจ้งผู้ฟังที่เกี่ยวข้องว่าถั่วได้รับการโหลด getReaderContext (). FireComponentRegered (New BeanComponentDefinition (BDHOLDER)); -ในรหัสนี้:
ลองวิเคราะห์รายละเอียดว่าฤดูใบไม้ผลิแยกวิเคราะห์แต่ละแท็กและโหนด
การวิเคราะห์แท็กถั่ว
คลาสสาธารณะ beandefinitionparserdelegate {@nullable สาธารณะ beandefinitionholder parsebeanDefinitionElement (องค์ประกอบ ele, @nullable beandefinition containsbean) {// รับแอตทริบิวต์ ID ของแท็กถั่ว // รับแอตทริบิวต์ชื่อของสตริงแท็กถั่ว nameattr = ele.getAttribute (name_attribute); รายการ <String> aliases = new ArrayList <> (); if (stringutils.haslength (nameattr)) {// ส่งค่าของแอตทริบิวต์ชื่อและแบ่งออกเป็นหมายเลขสตริง (นั่นคือถ้ามีการกำหนดค่าหลายชื่อในไฟล์การกำหนดค่าให้ประมวลผลที่นี่) สตริง [] namearr = stringutils.tokenizetoStringarray Aliases.addall (array.aslist (namearr)); } string beanname = id; // ถ้า id ว่างเปล่าให้ใช้แอตทริบิวต์ชื่อที่กำหนดค่าเป็น ID ถ้า (! stringutils.hastext (Beanname) &&! aliases.isempty ()) {beanname = aliases.remove (0); if (logger.isdebugenabled ()) {logger.debug ("ไม่ระบุ XML 'ID' - การใช้ '" + BeanName + "' เป็นชื่อถั่วและ" + นามแฝง + "เป็นนามแฝง"); }} if (containingBean == null) {// ตรวจสอบความเป็นเอกลักษณ์ของ BeanName และนามแฝง // แกนภายในคือการใช้คอลเลกชันที่ใช้แล้วเพื่อบันทึก BeanName ที่ใช้แล้วทั้งหมดและนามแฝง (ชื่อ Beanname, นามแฝง } // แยกวิเคราะห์คุณสมบัติอื่น ๆ ทั้งหมดลงในวัตถุ GenericBeandefinition AbstractBeandEfinition BeanDefinition = ParsebeanDefinitionElement (Ele, Beanname, ContainedBean); ถ้า (beandefinition! = null) {// ถ้าถั่วไม่ได้ระบุ Beanname จากนั้นใช้กฎเริ่มต้นเพื่อสร้าง Beanname สำหรับถั่วนี้ถ้า (! stringutils.hastext (Beanname)) {ลอง {ถ้า this.readerContext.getRegistry (), จริง); } else {beanName = this.readerContext.generateBeanName (BeanDefinition); // ลงทะเบียนนามแฝงสำหรับชื่อคลาสถั่วธรรมดาหากยังคงเป็นไปได้ // หากเครื่องกำเนิดไฟฟ้าส่งคืนชื่อคลาสพร้อมคำต่อท้าย // คาดว่าจะเข้ากันได้กับสปริง 1.2/2.0 ย้อนหลัง สตริง beanclassName = beandefinition.getBeanClassName (); if (beanclassName! = null && beanname.startswith (beanclassName) && beanname.length ()> beanclassname.length () &&! this.readerContext.getRegistry (). isBeanNameInuse }} if (logger.isdebugenabled ()) {logger.debug ("ไม่มี XML 'ID' หรือ 'ชื่อ' ที่ระบุ -" + "โดยใช้ชื่อถั่วที่สร้างขึ้น [" + BeanName + "]"); }} catch (Exception Ex) {ข้อผิดพลาด (ex.getMessage (), ele); คืนค่า null; }} string [] aliasesarray = stringUtils.toStringArray (นามแฝง); // ห่อหุ้มข้อมูลลงในวัตถุ beandefinitionholder ส่งคืนใหม่ beandefinitionholder (beandefinition, Beanname, aliasesarray); } return null; - วิธีนี้ส่วนใหญ่ประมวลผลแอตทริบิวต์ที่เกี่ยวข้องเช่น ID, ชื่อ, นามแฝง ฯลฯ สร้าง BeanName และเสร็จสิ้นการแยกวิเคราะห์แท็กหลักในฟังก์ชั่นโอเวอร์โหลด parseBeanDefinitionElement(ele, beanName, containingBean)
จากนั้นมุ่งเน้นไปที่ parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)
ดูว่าการดำเนินการแยกวิเคราะห์แท็กเสร็จสมบูรณ์อย่างไร
การวิเคราะห์โหนดถั่วและแอตทริบิวต์
@NullablePublic AbstractBeanDefinition ParsebeanDefinitionElement (Element Ele, string beanname, @nullable beandefinition มี) {this.parsestate.push (New Beanentry (Beanname)); // รับแอตทริบิวต์คลาสของสตริงแท็กถั่ว className = null; if (ele.hasattribute (class_attribute)) {className = ele.getAttribute (class_attribute) .Trim (); } // รับแอตทริบิวต์พาเรนต์ของสตริงแท็กสตริงของถั่ว = null; if (ele.hasattribute (parent_attribute)) {parent = ele.getAttribute (parent_attribute); } ลอง {// สร้าง AbstractBeanDefinition เพื่อโฮสต์แอตทริบิวต์ AbstractBeanDefinition BD = CreateBeanDefinition (ClassName, Parent); // รับแอตทริบิวต์ต่าง ๆ ของแท็กถั่ว ParsebeanDefinitionAttributes (Ele, Beanname, ContainingBean, BD); // แยกวิเคราะห์คำอธิบายแท็ก bd.setdescription (domutils.getChildElementValueByTagname (ele, description_element)); // Parse Meta Tag Parsemetaelements (Ele, Bd); // Parse lookup-method แท็ก parselookupoverridesubelements (Ele, bd.getMethodoverrides ()); // การแยกวิเคราะห์แท็กวิธีการเปลี่ยนรูปแบบ parsereplacedMethodsubelements (Ele, bd.getMethodoverrides ()); // การแยกวิเคราะห์แท็กวิธีการเปลี่ยนรูปแบบ parsereplacedMethodsubelements (Ele, bd.getMethodoverrides ()); // Parse Constructor-Arg Tag ParseconstructorGelements (Ele, Bd); // การแยกวิเคราะห์แท็กคุณสมบัติ parsepropertyelements (ele, bd); // Parse Qualifier Tag ParmenseMerceMefierElements (ELE, BD); bd.setResource (this.readerContext.getResource ()); Bd.SetSource (ExtractSource (ELE)); กลับ BD; } catch (classnotfoundexception ex) {ข้อผิดพลาด ("คลาสถั่ว [" + classname + "] ไม่พบ", ele, ex); } catch (noclassDeffoundError err) {ข้อผิดพลาด ("คลาสที่ bean class [" + classname + "] ขึ้นอยู่กับไม่พบ", ele, err); } catch (ex throwable) {ข้อผิดพลาด ("ความล้มเหลวที่ไม่คาดคิดในระหว่างการแยกวิเคราะห์ถั่ว", ele, ex); } ในที่สุด {this.parsestate.pop (); } return null;}แยกวิเคราะห์คุณลักษณะและองค์ประกอบอื่น ๆ เพิ่มเติม (มีองค์ประกอบและคุณลักษณะมากมายดังนั้นนี่จึงเป็นภาระงานที่ยิ่งใหญ่) และจัดเก็บไว้ใน GenericBeandefinition หลังจากแยกวิเคราะห์แอตทริบิวต์และองค์ประกอบเหล่านี้หากคุณตรวจพบว่าถั่วไม่มีชื่อถั่วที่ระบุคุณจะใช้กฎเริ่มต้นเพื่อสร้าง Beanname สำหรับถั่ว
// beandefinitionparserdelegate.javaprotected บทคัดย่อ abstractBeanDefinition createBeanDefinition (@Nullable String className, @Nullable String ParentName) พ่น classNotFoundException {return BEANDEFINITIONUTELS.CREATEBEARDEFINITION beanDefinitionReaderUtils {public Static AbstractBeanDefinition CreateBeanDefinition (@Nullable String ParentName, @Nullable String className, @Nullable classloader classloader) พ่น classnotFoundException // parentName อาจว่าง bd.setParentName (ชื่อ parentName); // ถ้า classloader ไม่ว่าง // จากนั้นใช้ classloader ที่ผ่านเพื่อโหลดวัตถุคลาสด้วยเครื่องเสมือนเดียวกัน มิฉะนั้นจะมีการบันทึกเฉพาะ classloader หาก (className! = null) {ถ้า (classloader! = null) {bd.setBeanClass (classutils.forname (className, classloader)); } else {bd.setBeanClassName (className); }} ส่งคืน bd; -Beandefinition เป็นตัวแทนภายในของ <Bean> ในภาชนะและ beandefinition และ <bean> เป็นแบบหนึ่งต่อหนึ่ง ในเวลาเดียวกัน BeanDefinition จะลงทะเบียนใน BEANDEFINITIONREGISTRY ซึ่งเป็นเหมือนฐานข้อมูลในหน่วยความจำของข้อมูลการกำหนดค่าสปริง
จนถึงตอนนี้ createBeanDefinition(className, parent); เสร็จสิ้นแล้วและเรายังได้รับ AbstractBeandEfinition ที่ใช้ในการโฮสต์คุณลักษณะ ลองมาดูกันว่า parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); ParsebeanDefinitionAttributes (Ele, Beanname, Comitainingbean, BD); แยกวิเคราะห์แอตทริบิวต์แท็กต่าง ๆ ในถั่ว
ระดับสาธารณะ beandefinitionparserdelegate {Public AbstractBeanDefinition ParsebeanDefinitionAttributes (Element Ele, String Beanname, @Nullable BEANDEFINITION BEANDEFINITION มีความเป็นนามธรรม หากมี bd.set (แอตทริบิวต์); กลับ BD; -การแยกวิเคราะห์ที่สมบูรณ์ของแท็ก `ถั่ว 'สิ้นสุดลงแล้ว องค์ประกอบการแยกวิเคราะห์ภายใต้แท็ก `Bean` นั้นคล้ายคลึงกัน หากคุณสนใจคุณสามารถติดตามซอร์สโค้ดและดูวิธีการแยกวิเคราะห์เช่น `qualifier, lookup-method` (*ไม่ซับซ้อนกว่า` bean`*) เนื้อหาแท็กที่กำหนดเองมีรายละเอียดมากขึ้นในบทถัดไป
ในที่สุดห่อหุ้มข้อมูลที่ได้รับลงในอินสแตนซ์ `beandefinitionholder '
`` `java // beandefinitionparserdelegate.java@nullablepublic beandefinitionholder parsebeandefinitionelement (Element ele, @nullable beandefinition) {// ... กลับมาใหม่ลงทะเบียน beandefinition ที่แยกวิเคราะห์
หลังจากแยกวิเคราะห์ไฟล์การกำหนดค่าเราได้รับคุณสมบัติทั้งหมดของถั่วและขั้นตอนต่อไปคือการลงทะเบียนถั่ว
ชั้นเรียนสาธารณะ beandefinitionreaderutils {public static void registerbeandefinition (beandefinitionholder regitionholder, beandefinitionregistry registry) โยน beandefinitionstoreexception {// ใช้ beanname // ลงทะเบียนรหัสหลักของ Registry Bean.registerBeandEfinition (Beanname, คำนิยามผู้ใช้งาน GetBeanDefinition ()); // ลงทะเบียนนามแฝงทั้งหมดสำหรับสตริงถั่ว [] นามแฝง = คำนิยามผู้ถือครอง. getaliases (); if (นามแฝง! = null) {สำหรับ (สตริงนามแฝง: นามแฝง) {registry.registeralias (Beanname, นามแฝง); -รหัสข้างต้นส่วนใหญ่ทำสองฟังก์ชั่น: หนึ่งคือการลงทะเบียน beandefinition โดยใช้ Beanname และอีกฟังก์ชั่นอื่น ๆ คือการลงทะเบียนนามแฝงให้เสร็จสมบูรณ์
beanname register beandefinition
คลาสสาธารณะ defaultListableBeanFactory {@Override โมฆะสาธารณะ registerBeanDefinition (สตริง Beanname, BeanDefinition BeanDefinition) พ่น BeanDefinitionstoreexception {assert.hastext (Beanname, "Bean Name ต้องไม่ว่าง"); assert.notnull (beandefinition, "beandefinition ต้องไม่เป็นโมฆะ"); if (beandefinition instanceof abstractBeandEfinition) {ลอง {// การตรวจสอบครั้งสุดท้ายก่อนการลงทะเบียนการตรวจสอบที่นี่แตกต่างจากการตรวจสอบไฟล์ XML // เป็นหลักสำหรับการตรวจสอบ Methodoverrides beandefinition) .validate (); } catch (beandefinitionValidationexception ex) {โยน beandefinitionstoreexception ใหม่ (beandefinition.getResourcedescription (), Beanname, "การตรวจสอบความถูกต้องของคำจำกัดความของถั่วล้มเหลว", Ex); }} BeanDefinition OldBeanDefinition; // รับ beandefinition ในแคช OldBeanDefinition = this.beanDefinitionMap.get (Beanname); ถ้า (oldBeanDefinition! = null) {// ถ้ามีแคชให้พิจารณาว่าอนุญาตให้มีการเขียนทับหาก (! isallowbeanDefinitionOverriding ()) {โยน beandefinitionstoreexception (beandefinition "': มีอยู่แล้ว [" + OldBeanDefinition + "] ผูกพัน"); } อื่นถ้า (oldBeanDefinition.getRole () <beanDefinition.getRole ()) {// eg เป็น role_application ตอนนี้เอาชนะด้วย role_support หรือ role_infasture ถ้า (this.logger.iswarnenabled () นิยามถั่วที่สร้างเฟรมเวิร์ก: การแทนที่ [" + oldBeanDefinition +"] ด้วย [" + beandefinition +"] "); }} else if (! beandefinition.equals (oldBeanDefinition)) {ถ้า (this.logger.isinfoenabled ()) {this.logger.info ("คำจำกัดความถั่วที่เหนือกว่าสำหรับถั่ว +" beanname + " }} else {if (this.logger.isdebugenabled ()) {this.logger.debug ("คำจำกัดความถั่วเอาชนะสำหรับถั่ว '" + Beanname + "' ด้วยคำจำกัดความที่เทียบเท่า: แทนที่ [" + oldbeandefinition + "] }} // หากอนุญาตให้เขียนทับให้บันทึก beandefinition ลงใน beandefinitionmap this.beandefinitionmap.put (Beanname, beandefinition); } else {// พิจารณาว่าการสร้างถั่วเริ่มต้นขึ้นหรือไม่ถ้า (HasebeanCreationStarted ()) {// ไม่สามารถแก้ไของค์ประกอบการรวบรวมเวลาเริ่มต้นได้อีกต่อไป (สำหรับการวนซ้ำที่เสถียร) ซิงโครไนซ์ // อัปเดตรายการ beanname ที่ลงทะเบียน <String> updateDefinitions = new ArrayList <> (this.beanDefinitionNames.size () + 1); UpdatedDefinitions.addall (this.beandefinitionnames); updatedDefinitions.add (Beanname); this.beanDefinitionNames = updatedDefinitions; if (this.ManualSingleTonNames.Contains (BeanName)) {ตั้งค่า <string> updatedSingletons = ใหม่ linkedHashSet <> (this.ManualSingleTonNames); UPDATEDSINGLETONS.REMOVE (BeanName); this.manualsingletonNames = updatedSingletons; }}} else {// ฉันยังไม่ได้เริ่มสร้างถั่ว แต่สิ่งนี้ beanDefinitionMap.put (BeanName, BeanDefinition); this.beandefinitionnames.add (Beanname); this.manualsingletonnames.remove (Beanname); } this.frozenBeanDefinitionNames = null; } if (OldBeanDefinition! = NULL || ประกอบด้วย (BeanName)) {// รีเซ็ตแคชที่สอดคล้องกับ BeanName RESETBEANDEFINITION (BeanName); -ลงทะเบียนนามแฝง
หลังจากลงทะเบียน beandefinition ขั้นตอนต่อไปคือการลงทะเบียนนามแฝง ความสัมพันธ์ที่สอดคล้องกันระหว่างนามแฝงที่ลงทะเบียนและชื่อถั่วจะถูกเก็บไว้ใน aliasmap คุณจะพบว่าวิธีการลงทะเบียนถูกนำไปใช้ใน SimpleLeiAsRegistry
คลาสสาธารณะ SimpleLiAsRegistry { / ** แผนที่จากนามแฝงถึงชื่อที่เป็นที่ยอมรับ* / แผนที่สุดท้ายส่วนตัว <String, String> AliasMap = ใหม่พร้อมกันพร้อมกัน <> (16); โมฆะสาธารณะ registeralias (ชื่อสตริง, นามแฝงสตริง) {assert.hastext (ชื่อ, "ชื่อ 'ต้องไม่ว่าง"); assert.hastext (นามแฝง, "'นามแฝง' ต้องไม่ว่างเปล่า"); ถ้า (Alias.equals (ชื่อ)) {// ถ้า BeanName เหมือนกับนามแฝงนามแฝงจะไม่ถูกบันทึกและลบนามแฝงที่สอดคล้องกัน this.aliasmap.remove (นามแฝง); } else {สตริง registeredName = this.aliasmap.get (นามแฝง); if (registeredName! = null) {ถ้า (registeredName.equals (ชื่อ)) {// ถ้านามแฝงได้รับการลงทะเบียนแล้วและชื่อที่ชี้ไปเป็นชื่อเดียวกับชื่อปัจจุบันจะไม่มีการประมวลผลใด ๆ } // ถ้านามแฝงไม่อนุญาตให้มีการเขียนทับจะมีการโยนข้อยกเว้นถ้า (! lewalaliAsoverRiding ()) {โยนใหม่ผิดกฎหมาย StateException ("ไม่สามารถลงทะเบียนนามแฝง '" + นามแฝง + "' สำหรับชื่อ '" + ชื่อ + "': มันลงทะเบียนแล้วสำหรับชื่อ '" }} // การตรวจสอบลูปชี้ไปที่การพึ่งพาเช่น A-> B B-> C C-> A, ข้อผิดพลาดเกิดขึ้น checkforaliascircle (ชื่อ, นามแฝง); this.aliasmap.put (นามแฝง, ชื่อ); - ตรวจสอบการพึ่งพาวงกลมนามแฝงผ่านวิธี checkForAliasCircle() เมื่อ A -> B มีอยู่ถ้า A -> C -> B ปรากฏขึ้นอีกครั้งข้อยกเว้นจะถูกโยน:
Void Prected Checkforaliascircle (ชื่อสตริง, นามแฝงสตริง) {ถ้า (hasalias (นามแฝง, ชื่อ)) {โยน unlislessatexception ใหม่ ("ไม่สามารถลงทะเบียนนามแฝง '" + alias + "' สำหรับชื่อ '" + ชื่อ + "': การอ้างอิงวงกลม - '" + ชื่อ + "' }} public boolean hasalias (ชื่อสตริง, นามแฝงสตริง) {สำหรับ (map.entry <สตริง, สตริง> รายการ: this.aliasmap.entryset ()) {สตริง registeredName = entry.getValue (); if (registeredName.equals (ชื่อ)) {String registeredalias = entry.getKey (); return (registeredalias.equals (นามแฝง) || hasalias (registeredalias, นามแฝง)); }} return false;}ณ จุดนี้การลงทะเบียนนามแฝงเสร็จสมบูรณ์และงานต่อไปนี้เสร็จสมบูรณ์
ส่งการแจ้งเตือน
แจ้งให้ผู้ฟังแยกวิเคราะห์และลงทะเบียน
//defaultBeanDefinitionDocumentReader.javaprotected Void ProcessBeanDefinition (Element Ele, BeanDefinitionParserDelegate Delegate) {// ส่งเหตุการณ์การลงทะเบียน getReaderContext (). FireComponentErg ที่จดทะเบียน (ใหม่ BeanComponentDefinition (BDHOLDER));}วิธีการที่มีการลงทะเบียน FireComponentReg ใช้เพื่อแจ้งให้ผู้ฟังแยกวิเคราะห์และลงทะเบียนงาน การใช้งานที่นี่มีไว้สำหรับการขยายเท่านั้น เมื่อผู้พัฒนาโปรแกรมจำเป็นต้องฟังเหตุการณ์ BeanDefinition ที่ลงทะเบียนเขาสามารถลงทะเบียนผู้ฟังและเขียนตรรกะการประมวลผลลงในผู้ฟัง ปัจจุบันฤดูใบไม้ผลิไม่ได้จัดการกับเหตุการณ์นี้ในเหตุการณ์นี้
readerContext ถูกสร้างขึ้นโดยการเรียก createDerContext ในคลาส XMLBEANDEFINITIONREADER fireComponentRegistered()
การวิเคราะห์แท็กนามแฝง
สปริงให้การกำหนดค่านามแฝงสำหรับ <alias name="person" alias="p"/> ความละเอียดของแท็กจะทำในวิธีการประมวลผลการลงทะเบียน (องค์ประกอบ ELE)
คลาสสาธารณะ defaultBeanDefInitionDocumentReader {void processaliasRegistration (Element Ele) {รับ ALISA TAG NAME PROTATION NAME NAME = ELE.GETATTRIBUTE (NAME_ATTRIBUTE); // รับ ALISA TAG ALISA ALIAS ALIAS ALIAS ALIAS = Ele.GetAttribute (alias_attribute); บูลีนถูกต้อง = true; if (! stringutils.hastext (ชื่อ)) {getReaderContext (). ข้อผิดพลาด ("ชื่อต้องไม่ว่าง", ele); ถูกต้อง = เท็จ; } if (! stringUtils.hastext (นามแฝง)) {getReaderContext (). ข้อผิดพลาด ("นามแฝงจะต้องไม่ว่างเปล่า", ele); ถูกต้อง = เท็จ; } if (ถูกต้อง) {ลอง {// ลงทะเบียนนามแฝง getReaderContext (). getRegistry (). registeralias (ชื่อ, นามแฝง); } catch (Exception Ex) {getReaderContext (). ข้อผิดพลาด ("ไม่สามารถลงทะเบียนนามแฝง" " + นามแฝง" 'สำหรับถั่วที่มีชื่อ' " + ชื่อ +" '", ele, ex); } // หลังจากลงทะเบียนนามแฝงให้บอกผู้ฟังให้ทำการประมวลผลที่สอดคล้องกัน getReaderContext (). Firealiasregistered (ชื่อ, นามแฝง, ExtractSource (ELE)); -อย่างแรกคุณลักษณะแท็กนามแฝงจะถูกสกัดและตรวจสอบแล้ว หลังจากผ่านการตรวจสอบแล้วการลงทะเบียนนามแฝงจะดำเนินการ การลงทะเบียนนามแฝงและการลงทะเบียนนามแฝงในการวิเคราะห์แท็กถั่วได้ทำไปแล้ว ฉันจะไม่ทำซ้ำที่นี่
การนำเข้าการวิเคราะห์แท็ก
คลาสสาธารณะ defaultBeanDefinitionDocumentReader {void void importebeanDefinitionResource (Element Ele) {// รับแอตทริบิวต์ทรัพยากรของตำแหน่งสตริงแท็กนำเข้า = ele.getAttribute (Resource_attribute); // ถ้าไม่มีอยู่จะไม่มีการประมวลผลหาก (! stringUtils.hastext (ตำแหน่ง)) {getReaderContext (). ข้อผิดพลาด ("ตำแหน่งทรัพยากรต้องไม่ว่าง", ele); กลับ; } // รูปแบบแอตทริบิวต์ Parsing Placeholder เช่น "$ {user.dir}" ตำแหน่ง = getReaderContext (). getenVironment (). Resolverequiredlaceholders (ตำแหน่ง); ตั้งค่า <resource> actureResources = ใหม่ linkedHashSet <> (4); // ตรวจสอบว่าทรัพยากรเป็นเส้นทางสัมบูรณ์หรือเส้นทางบูลีนแบบสัมพัทธ์ Absolutelocation = False; ลอง {AbsolutElocation = ResourcePatternutils.isurl (ตำแหน่ง) || ResourceUtils.touri (ตำแหน่ง) .isabsolute (); } catch (urisyntaxexception ex) {// ไม่สามารถแปลงเป็น URI ได้โดยพิจารณาจากตำแหน่งที่เกี่ยวข้อง // เว้นแต่ว่าเป็นคำนำหน้าสปริงที่รู้จักกันดี "classpath*:"} // ถ้าเป็นเส้นทางที่สมบูรณ์ไฟล์การกำหนดค่าที่สอดคล้องกัน แหล่งที่มาจริง); if (logger.isdebugenabled ()) {logger.debug ("นำเข้า" + importCount + "คำจำกัดความถั่วจากตำแหน่ง URL [" + ตำแหน่ง + "]"); }} catch (beandefinitionstoreException ex) {getReaderContext (). ข้อผิดพลาด ("ไม่สามารถนำเข้าคำจำกัดความถั่วจากตำแหน่ง URL [" + ตำแหน่ง + "]", ele, ex); }} else {ลอง {int importCount; // โหลดทรัพยากรตามเส้นทางที่สัมพันธ์กัน relativeresource = getReaderContext (). getResource (). createrelative (ตำแหน่ง); if (relatiSource.exists ()) {importCount = getReaderContext (). getReader (). loadBeanDefinitions (relativerEsource); actureresources.add (relativeresource); } else {string baselocation = getReaderContext (). getResource (). getUrl (). toString (); importCount = getReaderContext (). getReader (). loadBeanDefinitions (stringUtils.applyRelativePath (baselocation, ที่ตั้ง), แหล่งข้อมูลจริง); } if (logger.isdebugenabled ()) {logger.debug ("นำเข้า" + importCount + "คำจำกัดความถั่วจากตำแหน่งสัมพัทธ์ [" + ตำแหน่ง + "]"); }} catch (ioexception ex) {getReaderContext (). ข้อผิดพลาด ("ไม่สามารถแก้ไขตำแหน่งทรัพยากรปัจจุบัน", ele, ex); } catch (beandefinitionstoreexception ex) {getReaderContext (). ข้อผิดพลาด ("ไม่สามารถนำเข้าคำจำกัดความถั่วจากตำแหน่งสัมพัทธ์ [" + ตำแหน่ง + "]", ele, ex); }} // หลังจากการแยกวิเคราะห์การประมวลผลการเปิดใช้งานผู้ฟังจะดำเนินการ ทรัพยากร [] actresarray = realResources.toArray (ทรัพยากรใหม่ [realResources.size ()]); getReaderContext (). FireimportProcessed (สถานที่, actresarray, ExtractSource (ELE)); - หลังจากเสร็จสิ้นการประมวลผลของแท็กนำเข้าสิ่งแรกคือการได้รับเส้นทางที่แสดงโดย <import resource="beans.xml"/> แอตทริบิวต์ทรัพยากรจากนั้นแยกวิเคราะห์ตัวยึดคุณลักษณะในเส้นทางเช่น ${user.dir} จากนั้นตรวจสอบว่าสถานที่นั้นเป็นเส้นทางที่สมบูรณ์หรือเส้นทางที่สัมพันธ์กัน หากเป็นเส้นทางที่แน่นอนกระบวนการแยกวิเคราะห์ของถั่วจะเรียกว่าซ้ำ (loadBeanDefinitions(location, actualResources);) เพื่อทำการวิเคราะห์อื่น หากเป็นเส้นทางที่สัมพันธ์กันให้คำนวณเส้นทางสัมบูรณ์และแยกวิเคราะห์ ในที่สุดแจ้งผู้ฟังและการแยกวิเคราะห์เสร็จสิ้น
สรุป
หลังจากฤดูใบไม้ร่วงฤดูใบไม้ร่วงฤดูใบไม้ผลิและฤดูร้อนทุกอย่างจะเป็นไปตามทิศทางที่คุณต้องการ ...
โอเคข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com
พูดอะไรบางอย่าง
รหัสข้อความแบบเต็ม: https://gitee.com/battcn/battcn-spring-source/tree/master/chapter1 (ดาวน์โหลดท้องถิ่น)