คำนำ
ในส่วนก่อนหน้าการถอดรหัสสปริง - การวิเคราะห์แท็กเริ่มต้นเรามุ่งเน้นไปที่การวิเคราะห์ว่าสปริงแยกวิเคราะห์แท็กเริ่มต้นได้อย่างไร ดังนั้นบทนี้ยังคงอธิบายการแยกวิเคราะห์ฉลากโดยมุ่งเน้นไปที่วิธีการแยกวิเคราะห์แท็กที่กำหนดเอง โดยไม่ต้องกังวลใจเพิ่มเติมลองมาดูการแนะนำรายละเอียด
แท็กที่กำหนดเอง
ก่อนที่จะอธิบายการวิเคราะห์แท็กที่กำหนดเองโปรดดูวิธีปรับแต่งแท็ก
กำหนดไฟล์ XSD
กำหนดไฟล์ XSD เพื่ออธิบายเนื้อหาส่วนประกอบ
<? xml version = "1.0" การเข้ารหัส = "utf-8"?> <xsd: schema xmlns = "http://www.battcn.com/schema/battcn" xmlns: xsd = "http://ww.w3.org/2001/2001/2001/2001/2001/2001/2001 xmlns: beans = "http://www.springframework.org/schema/beans" targetNamespace = "http://www.battcn.com/schema/battcn" ElementFormDefault = "attributeFormDefault = namespace = "http://www.springframework.org/schema/beans"/> <xsd: element name = "Application"> <xsd: ComplexType> <xsd: complexContent> <xsd: extension base = "Beans: identifiedtype" </xsd: ส่วนขยาย> </xsd: complexContent> </xsd: complexType> </xsd: องค์ประกอบ> </xsd: schema>
กำหนดกฎการแยกวิเคราะห์
1. สร้างคลาสเพื่อใช้งานอินเตอร์เฟส BeanDefinitionParser (ยังสามารถสืบทอดคลาสที่ให้ไว้ในฤดูใบไม้ผลิ) เพื่อแยกวิเคราะห์คำจำกัดความและคำจำกัดความส่วนประกอบในไฟล์ XSD
คลาสสาธารณะแอปพลิเคชัน BEANDEFINITIONPARSER ขยายบทคัดย่อ AbstractsingleBeanDefinitionParser {@Override คลาสที่ได้รับการป้องกัน getBeanClass (องค์ประกอบองค์ประกอบ) {// ประเภทของวัตถุที่ได้รับคือ: ชื่อสตริง = (สตริง) บริบท. getBean ("battcn"); return String.class; } @Override Void Doparse (องค์ประกอบองค์ประกอบ, BeanDefinitionBuilder Bean) {// แอตทริบิวต์ชื่อที่กำหนดไว้ในชื่อสตริง XSD = element.getAttribute ("ชื่อ"); bean.addconstructorargvalue (ชื่อ); -นี่คือ ApplicationBeanDefinitionParser ที่สืบทอด AbstractsingleBeandEfinitionParser (เป็นคลาสย่อยของ BeanDefinitionParser) โฟกัสคือการแทนที่ doparse, แยกวิเคราะห์แท็ก XML ในนั้นแล้วฉีดค่าที่แยกวิเคราะห์ (เลวิน) ลงในตัวสร้าง
2. สร้างคลาสเพื่อสืบทอดคลาสบทคัดย่อ
Public Class BattcnnamespaceHandler ขยาย NamespaceHandlersupport {@Override โมฆะสาธารณะเริ่มต้น () {registerBeanDefinitionParser ("แอปพลิเคชัน", ApplicationBeanDefinitionParser ()); - ฟังก์ชั่นของ battcnnamespaceHandler นั้นง่ายมากซึ่งก็คือการบอกคอนเทนเนอร์สปริงว่าแท็ก <battcn:application /> ควรแยกวิเคราะห์โดย parser นั้น (ที่นี่เราปรับแต่ง: ApplicationBeanDefinitionParser) ซึ่งรับผิดชอบในการลงทะเบียนส่วนประกอบไปยังคอนเทนเนอร์ฤดูใบไม้ผลิ
3. เขียน spring.handlers และ spring.schemas ไฟล์
ไดเรกทอรีที่จัดเก็บไฟล์อยู่ในแหล่งข้อมูล/meta-inf/file
Spring.handlers
http/: //www.battcn.com/schema/battcn=com.battcn.handler.battcnnamespaceHandler
Spring.schemas
http/: //www.battcn.com/schema/battcn.xsd=battcn.xsd
4. ใช้แท็กที่กำหนดเอง
ประกาศไฟล์ bean.xml ซึ่งกำหนดดังนี้
<? xml version = "1.0" การเข้ารหัส = "utf-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns: xsi = "http://ww.w3.org/2001/xml xmlns: battcn = "http://www.battcn.com/schema/battcn" xsi: schemalocation = "http://www.springframework.org/schema/beans http://www.battcn.com/schema/battcn http://www.battcn.com/schema/battcn.xsd "> <battcn: application id =" battcn "name =" levin "/> </epeans>
สร้างคลาสทดสอบ หากคุณเห็นคำพูดของคอนโซล Levin Word นั่นหมายความว่าฉลากที่กำหนดเองเป็นเรื่องปกติ
แอปพลิเคชันคลาสสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {applicationcontext context = ใหม่ classPathxMlApplicationContext ("bean.xml"); String name = (String) context.getBean ("battcn"); System.out.println (ชื่อ); -5. ดังแสดงในรูป
การวิเคราะห์ซอร์สโค้ด
พอร์ทัลความละเอียดแท็กที่กำหนดเอง
ระดับสาธารณะ beandefinitionparserdelegate {@nullable สาธารณะ beandefinition parsecustomelement (องค์ประกอบ ele, @nullable beandefinition containsbd) {// รับที่อยู่ namespace http://ww.battcn.com/schema/schema if (namespaceuri == null) {return null; } // NamespaceHandler เป็นแอปพลิเคชันที่ลงทะเบียนในตัวจัดการ battcnnamespaceHandler namespaceHandler ที่กำหนดเอง = this.readerContext.getNamespaceHandlerresolver (). Resolve (Namespaceuri); if (handler == null) {ข้อผิดพลาด ("ไม่สามารถค้นหาสปริง namespaceHandler สำหรับ xml schema namespace [" + namespaceuri + "]", ele); คืนค่า null; } return handler.parse (ele, parsercontext ใหม่ (this.readerContext, this, attainingbd)); - เช่นเดียวกับกฎการแก้ไขแท็กเริ่มต้นเนมสเปซจะได้รับผ่าน getNamespaceURI(Node node) ดังนั้น this.readerContext.getNamespaceHandlerResolver() ได้รับที่ไหน? เราติดตามรหัสและเราสามารถค้นหาได้ว่าเมื่อโครงการเริ่มต้นเนื้อหาไฟล์ meta-inf/spring.handles ทั้งหมดจะถูกแยกวิเคราะห์ใน XMLBeanDefinitionReader และเก็บไว้ใน Handlermappers (พร้อมกัน เมื่อมีการเรียกร้องให้ resolve(namespaceUri) เพื่อตรวจสอบเนื้อหาที่แคชจะถูกสกัดเพื่อเปรียบเทียบ
คลาสสาธารณะ XMLBEANDEFINITIONREADER {Public NamEspaceHandlerresolver getNamespaceHandlerresolver () {ถ้า (this.namespaceHandlerresolver == null) {this.namespacehandlerresolver = rectenefaultnamespacehandlerresolver (); } return this.namespacehandlerresolver; -แก้ไข
1. โหลดแผนที่ NamespaceHandler ที่ระบุและ NamespaceHandler ที่แยกออกมาจะถูกแคชแล้วกลับมา
คลาสสาธารณะ defaultNamesPaceHandLerResolver {@Override @Nullable Public NamespaceHandler Resolve (สตริง namespaceuri) {แผนที่ <สตริง, วัตถุ> handlermappings = gethandlermappings (); // Extract HandlerOrClassName จาก HandlerMAppings Object HandlerOrClassName = handlermappings.get (namespaceuri); if (handlerOrClassName == null) {return null; } else ถ้า (handlerOrClassName instanceof namespaceHandler) {return (namespaceHandler) handlerorClassName; } else {String className = (String) HandlerOrClassName; ลอง {class <?> handlerClass = classutils.forName (className, this.classloader); if (! namespaceHandler.class.isassignablefrom (handlerClass)) {โยน fatalBeanException ใหม่ ("คลาส [" + classname + "] สำหรับ namespace [" + namespaceuri + "] ไม่ได้ใช้ [" } // ค้นหาข้อมูลที่เกี่ยวข้องตาม Namespace NamespaceHandler namespaceHandler = (NamespaceHandler) beanutils.instantiateclass (handlerClass); // handler เริ่มต้น namespaceHandler.init (); handlermappings.put (namespaceuri, namespaceHandler); ส่งคืน NamespaceHandler; } catch (classnotfoundexception ex) {โยน fatalBeanException ใหม่ ("คลาส NamespaceHandler [" + classname + "] สำหรับ namespace [" + namespaceuri + "] ไม่พบ", ex); } catch (linkageERror err) {โยน fatalBeanException ใหม่ ("คลาส namespaceHandler ที่ไม่ถูกต้อง [" + classname + "] สำหรับ namespace [" + namespaceuri + "]: ปัญหากับไฟล์คลาส Handler หรือคลาสที่ขึ้นอยู่กับ", Err); -การวิเคราะห์แท็ก
หลังจากโหลด namespaceHandler แล้ว battcnnamespaceHandler ได้รับการเริ่มต้นและ battcnnamespaceHandler ยังเรียกวิธี init() เพื่อให้การเริ่มต้นทำงานให้เสร็จสมบูรณ์ ดังนั้นฉันจะดำเนินการต่อเพื่อเรียกใช้งานรหัสนี้: handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); โซลูชันแท็กเฉพาะ
คลาสสาธารณะ NamespaceHandlersupport {@Override @Nullable Public Public Public BeanDefinition Parse (องค์ประกอบองค์ประกอบ, parsercontext parsercontext) {beanDefinitionParser parser = findParserForElement (องค์ประกอบ, parsercontext); return (parser! = null? parser.parse (องค์ประกอบ, parsercontext): null); } @Nullable ส่วนตัว BeanDefinitionParser findParSerForElement (องค์ประกอบองค์ประกอบ, parsercontext parsercontext) {// แยกวิเคราะห์แอปพลิเคชันสตริง localName ใน <battcn: แอปพลิเคชัน /> .getDelegate (). getLocalName (องค์ประกอบ); beanDefinitionParser parser = this.parsers.get (localName); if (parser == null) {parsercontext.getReaderContext (). fatal ("ไม่สามารถระบุตำแหน่ง beandefinitionParser สำหรับองค์ประกอบ [" + localName + "]", องค์ประกอบ); } ส่งคืน parser; -พูดง่ายๆก็คือการค้นหาอินสแตนซ์ ApplicationBeanDefinitionParser จากตัวแยกวิเคราะห์และเรียกใช้วิธี Doparse ของตัวเองเพื่อการวิเคราะห์เพิ่มเติม ในที่สุดมันก็เป็นรูทีนเดียวกันของการแยกวิเคราะห์แท็กเริ่มต้น ...
สรุป
หลังจากฤดูใบไม้ร่วงฤดูใบไม้ร่วงฤดูใบไม้ผลิและฤดูร้อนทุกอย่างจะเป็นไปตามทิศทางที่คุณต้องการ ...
โอเคข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com
พูดอะไรบางอย่าง
รหัสข้อความแบบเต็ม: https://gitee.com/battcn/battcn-spring-source/tree/master/chapter2