บทความนี้แนะนำการอภิปรายสั้น ๆ เกี่ยวกับหลักการฉีดพึ่งพาของคอนเทนเนอร์ IOC ฤดูใบไม้ผลิและแบ่งปันกับคุณดังนี้:
ภารกิจหลักของการเริ่มต้นคอนเทนเนอร์ IOC คือการสร้างแผนที่ข้อมูล beandefinition ในคอนเทนเนอร์ IOC ฉันไม่เห็นคอนเทนเนอร์ IOC ที่ฉีดความสัมพันธ์การพึ่งพาถั่ว
สมมติว่าคอนเทนเนอร์ IOC ปัจจุบันได้โหลดข้อมูลถั่วที่ผู้ใช้กำหนดไว้การฉีดพึ่งพาส่วนใหญ่เกิดขึ้นในสองขั้นตอน
ภายใต้สถานการณ์ปกติจะถูกทริกเกอร์เมื่อผู้ใช้ขอถั่วจากคอนเทนเนอร์ IOC เป็นครั้งแรก
อย่างไรก็ตามเราสามารถควบคุมแอตทริบิวต์ Lazy-init ในข้อมูล beandefinition เพื่อให้คอนเทนเนอร์ได้รับการปรับปรุงไว้ล่วงหน้าของถั่วนั่นคือกระบวนการของการฉีดพึ่งพาถั่วบางชนิดเสร็จสมบูรณ์ในระหว่างกระบวนการเริ่มต้น
1. การฉีดพึ่งพา
ในอินเทอร์เฟซคอนเทนเนอร์ IOC พื้นฐานมีคำจำกัดความอินเตอร์เฟสสำหรับ GetBean การใช้งานอินเทอร์เฟซนี้เป็นที่ที่การฉีดขึ้นอยู่กับการทริกเกอร์เกิดขึ้น เพื่อให้เข้าใจถึงกระบวนการฉีดพึ่งพาอาศัยกันต่อไปเราเริ่มต้นด้วยคลาสพื้นฐาน AbstractBeanfactory ของ defaultlistablebeanfactory เพื่อดูการดำเนินการของ GetBean
// นี่คือการใช้งานอินเทอร์เฟซ BeanFactory เช่นวิธีการเชื่อมต่อของ GetBean // วิธีการอินเทอร์เฟซ getBean เหล่านี้จะถูกนำไปใช้ในที่สุดโดยการเรียก DogetBean @Override วัตถุสาธารณะ getBean (ชื่อสตริง) โยน beansexception {return dogetBean } @Override สาธารณะ <t> t getBean (ชื่อสตริง, คลาส <t> ที่ต้องการ type) พ่น beansexception {return dogetBean (ชื่อ, leadedType, null, false); } @Override วัตถุสาธารณะ getBean (ชื่อสตริง, วัตถุ ... args) พ่น beansexception {return dogetBean (ชื่อ, null, args, false); } สาธารณะ <t> t getBean (ชื่อสตริง, คลาส <t> ที่ต้องการ tType, วัตถุ ... args) พ่น beansexception {return dogetBean (ชื่อ, leadedType, args, false); } // นี่คือที่ได้รับถั่วจริงนั่นคือที่ซึ่งการฉีดพึ่งพานั้นถูกกระตุ้น @Suppresswarnings ("ไม่ได้ตรวจสอบ") ป้องกัน <t> t dogetBean (ชื่อสตริงสุดท้าย, คลาสสุดท้าย <t> ที่ต้องการ ถั่ววัตถุ; // ตรวจสอบแคช Singleton อย่างกระตือรือร้นสำหรับซิงเกิลที่ลงทะเบียนด้วยตนเอง // ตรวจสอบแคช Singleton อย่างกระตือรือร้นสำหรับซิงเกิลที่ลงทะเบียนด้วยตนเอง // ตรวจสอบแคช Singleton อย่างกระตือรือร้นสำหรับการลงทะเบียนด้วยตนเอง Singletons // ดึงถั่วจากแคชก่อนและประมวลผลถั่วซิงเกิลเหล่านั้นที่ถูกสร้างขึ้น อย่าสร้าง Object SharedInstance ซ้ำ ๆ = GetSingleton (ชื่อ Beanname); if (SharedInstance! = null && args == null) {ถ้า (logger.isdebugenabled ()) {ถ้า (issingletoncurrentlyincreation (Beanname)) {logger.debug ( } else {logger.debug ("การส่งคืนอินสแตนซ์แคชของ Singleton Bean '" + Beanname + "'"); }} // getObjectForBeanInstance ที่นี่เสร็จสิ้นการประมวลผลที่เกี่ยวข้องของโรงงานเบียนเพื่อให้ได้การประมวลผลที่เกี่ยวข้องของโรงงานเบียนเพื่อให้ได้ผลการผลิตของโรงงานเบียน ความแตกต่างระหว่าง Beanfactory และ FactoryBean ได้รับการกล่าวถึงก่อนหน้านี้ กระบวนการนี้จะถูกวิเคราะห์ในรายละเอียดในภายหลัง = getObjectForBeanInstance (SharedInstance, ชื่อ, Beanname, Null); } else {// ล้มเหลวหากเรากำลังสร้างอินสแตนซ์ถั่วนี้แล้ว: // เราสันนิษฐานว่าอยู่ในการอ้างอิงแบบวงกลม if (isprototypecurrentlyIncreation (BeanName)) {โยน beancurrentlyIncreationException ใหม่ (BeanName); } // // ตรวจสอบว่ามีการเปลี่ยนแปลงในคอนเทนเนอร์ IOC หรือไม่ หากไม่มีอยู่ในโรงงานปัจจุบันให้ทำตามห่วงโซ่ Beanfactory หลักและมองขึ้นไปที่ Beanfactory ParentBeanFactory = GetParentBeanFactory (); if (parentBeanFactory! = null &&! containsBeanDefinition (BeanName)) {// ไม่พบ -> ตรวจสอบผู้ปกครอง สตริง nametolookup = OriginalBeanName (ชื่อ); if (args! = null) {// การมอบหมายให้ผู้ปกครองด้วย args ที่ชัดเจน return (t) ParentBeanFactory.getBean (Nametolookup, Args); } else {// no args -> มอบหมายให้วิธี GetBean มาตรฐาน ส่งคืน ParentBeanFactory.getBean (Nametolookup, ต้องการประเภท); }} if (! typecheckonly) {markbeanascreated (Beanname); } ลอง {// รับ beandefinition สุดท้าย rootBeanDefinition mbd = getMergedLocalBeanDefinition (BeanName); CheckMergedBeanDefinition (MBD, Beanname, Args); // รับประกันการเริ่มต้นของถั่วที่ถั่วปัจจุบันขึ้นอยู่กับ // ได้รับถั่วทั้งหมดที่ถั่วปัจจุบันขึ้นอยู่กับสตริง (ถ้ามี) [] ขึ้นอยู่กับ = mbd.getDepedson (); if (ผู้อยู่อาศัย! = null) {สำหรับ (String dep: edcedson) {ถ้า (isdependent (beanname, dep)) {โยน beancreationexception ใหม่ (mbd.getResourcedescription (), Beanname, "วงกลมขึ้นอยู่กับความสัมพันธ์ระหว่าง '" + beanname + " } registerDependentBean (dep, beanname); getBean (dep); }} // สร้างอินสแตนซ์ถั่วซิงเกิลโดยเรียกเมธอด createBean ถ้า (mbd.issingleton ()) {SharedInstance = getSingleton (Beanname, ObjectFactory ใหม่ <jobch> () {@Override วัตถุสาธารณะ getObject () throws beansexception ถอดอินสแตนซ์ออกจากแคช Singleton อย่างชัดเจน: มันอาจจะมี // อย่างกระตือรือร้นโดยกระบวนการสร้างเพื่อให้ความละเอียดอ้างอิงเป็นวงกลม Bean = getObjectForBeanInstance (SharedInstance, ชื่อ, Beanname, MBD); } // นี่คือสถานที่ในการสร้างต้นแบบถั่วอื่นถ้า (mbd.isprototype ()) {// มันเป็นต้นแบบ -> สร้างอินสแตนซ์ใหม่ Object Prototypeinstance = null; ลอง {beforePrototypecReation (Beanname); Prototypeinstance = CreateBean (Beanname, MBD, Args); } ในที่สุด {afterprototypecreation (Beanname); } Bean = getObjectForBeanInstance (Prototypeinstance, ชื่อ, Beanname, MBD); } else {string scopename = mbd.getScope (); ขอบเขตขอบเขตสุดท้าย = this.scopes.get (scopename); if (scope == null) {โยนใหม่ unlilelStateException ("ไม่มีขอบเขตที่ลงทะเบียนสำหรับชื่อขอบเขต '" + scopename + "'"); } ลอง {Object scopedInstance = scope.get (beanname, ObjectFactory ใหม่ <jobch> () {@Override วัตถุสาธารณะ getObject () พ่น beansexception {beforeprotypecreation (beanname); ลอง {return createBean (beanname, mbd, args); - Bean = getObjectForBeanInstance (scopedInstance, ชื่อ, Beanname, MBD); } catch (unglegalstateException ex) {โยน beancreationexception ใหม่ (Beanname, "ขอบเขต" " + scopename +" 'ไม่ได้ใช้งานสำหรับกระทู้ปัจจุบันพิจารณา " +" การกำหนดพร็อกซีที่มีขอบเขตสำหรับถั่วนี้หากคุณตั้งใจจะอ้างถึงจากซิงเกิล " }}} catch (beansexception ex) {cleanupafterbeancreationfailure (Beanname); โยนอดีต; }} // ตรวจสอบว่าประเภทที่ต้องการตรงกับประเภทของอินสแตนซ์ถั่วจริงหรือไม่ // การตรวจสอบประเภทจะดำเนินการบนถั่วที่สร้างขึ้นที่นี่ หากไม่มีปัญหาถั่วที่สร้างขึ้นใหม่จะถูกส่งคืน ถั่วนี้เป็นถั่วที่มีการพึ่งพาถ้า (ต้องการ type! = null && Bean! = null &&! NULTYTYPE.ISASSIGNABLEFROM (bean.getClass ())) {ลอง {กลับ getTypeconverter () } catch (typemismatchexception ex) {ถ้า (logger.isdebugenabled ()) {logger.debug ("ล้มเหลวในการแปลงถั่ว '" + ชื่อ + "' เป็นประเภทที่ต้องการ '" + classutils.getqualifiedName } โยน beannotofrequiredTypeException ใหม่ (ชื่อ, NeveyType, Bean.getClass ()); }} return (t) ถั่ว; -การฉีดพึ่งพาอาศัยกันถูกกระตุ้นที่นี่ การฉีดพึ่งพาอาศัยกันเกิดขึ้นเมื่อมีการสร้างข้อมูล beandefinition ในคอนเทนเนอร์ แม้ว่าเราสามารถอธิบายคอนเทนเนอร์ IOC ในวิธีที่ง่ายที่สุดนั่นคือถือว่าเป็นแฮชแมป แต่เราสามารถพูดได้ว่า HashMap นี้เป็นโครงสร้างข้อมูลพื้นฐานที่สุดของคอนเทนเนอร์ไม่ใช่คอนเทนเนอร์ IOC ทั้งหมด
กระบวนการฉีดพึ่งพาการพึ่งพานี้จะอธิบายรายละเอียดด้านล่าง รูปที่ 1.1 แสดงกระบวนการทั่วไปของการฉีดพึ่งพา
รูปที่ 1.1 กระบวนการฉีดพึ่งพา
GetBean เป็นจุดเริ่มต้นของการฉีดพึ่งพา หลังจากนั้น CreateBean ใน AbstractautautowirecapableBeanFactory จะถูกเรียกให้ผลิตถั่วที่จำเป็นและการเริ่มต้นถั่วก็ถูกประมวลผลเช่นการใช้คำจำกัดความของแอตทริบิวต์เริ่มต้นใน beandefinition ถั่วโพสต์โปรเซสเซอร์ ฯลฯ
@Override วัตถุที่ได้รับการป้องกัน createBean (String BeanName, RootBeanDefinition MBD, Object [] args) พ่น beancreationException {ถ้า (logger.isdebugenabled ()) {logger.debug ("การสร้างอินสแตนซ์ของถั่ว '" + beanname + ""); } rootBeanDefinition mbdTouse = mbd; // ตรวจสอบให้แน่ใจว่าคลาสถั่วได้รับการแก้ไขจริง ณ จุดนี้และ // โคลนคำจำกัดความของถั่วในกรณีของคลาสที่ได้รับการแก้ไขแบบไดนามิก // ซึ่งไม่สามารถเก็บไว้ในคำจำกัดความของถั่วที่รวมเข้าด้วยกัน // ที่นี่เราตรวจสอบว่าถั่วที่จะสร้างสามารถสร้างอินสแตนซ์ไม่ว่าคลาสนี้สามารถโหลดผ่านคลาสโหลดเดอร์คลาส <?> redentClass = ResolveBeanClass (MBD, BeanName); if (ResolvedClass! = null &&! mbd.hasbeanclass () && mbd.getBeanClassName ()! = null) {mbdTouse = ใหม่ rootBeanDefinition (MBD); mbdtouse.setBeanClass (ResolvedClass); } // เตรียมวิธีการแทนที่ ลอง {mbdtouse.prepeReMethodoverRides (); } catch (beandefinitionValidationexception ex) {โยน beandefinitionstoreexception ใหม่ (mbdtouse.getResourcedescription (), Beanname, "การตรวจสอบวิธีการแทนที่ล้มเหลว", Ex); } ลอง {// ให้โอกาส BeanPostProcessors ในการส่งคืนพร็อกซีแทนอินสแตนซ์ถั่วเป้าหมาย // ถ้าถั่วได้กำหนดค่า postprocessor แล้ว Bean Object พร็อกซีที่ส่งคืน = ResolveBeBeBeforeinstantiation (BeanName, MBDTouse); ถ้า (ถั่ว! = null) {return bean; }} catch (throwable ex) {โยน beancreationexception ใหม่ (mbdtouse.getResourcedescription (), Beanname, "BeanPostProcessor ก่อนการสร้างอินสแตนซ์ของถั่วล้มเหลว", Ex); } ลอง {Object beaninstance = docreateBean (Beanname, Mbdtouse, args); if (logger.isdebugenabled ()) {logger.debug ("เสร็จสิ้นการสร้างอินสแตนซ์ของถั่ว '" + beanname + "'"); } return beaninstance; } catch (beancreationexception ex) {// ข้อยกเว้นที่ตรวจพบก่อนหน้านี้พร้อมบริบทการสร้างถั่วที่เหมาะสมแล้ว ... โยน EX; } catch (implateLyPearedSingleTonexception ex) {// unleegalStateException ที่จะสื่อสารจนถึงค่าเริ่มต้น refailsingletonBeanRegistry ... โยน EX; } catch (throwable ex) {โยน beancreationexception ใหม่ (mbdtouse.getResourcedescription (), Beanname, "ข้อยกเว้นที่ไม่คาดคิดระหว่างการสร้างถั่ว", อดีต); }} // ถัดจาก Docreate เพื่อดูว่าถั่วถูกสร้างขึ้นมาอย่างไรวัตถุ docreateBean (สตริงสุดท้าย Beanname, rootbeanDefinition สุดท้าย, mbd, วัตถุสุดท้าย [] args) {// อินสแตนติสถั่ว // ใช้เพื่อถือ bean beanwrapper instantwrapper = null; // ถ้าเป็นซิงเกิลตันก่อนอื่นให้ล้างถั่วที่มีชื่อเดียวกันในแคชถ้า (mbd.issingleton ()) {อินสแตนซ์ whapper = this.factoryBeanInstancecache.remove (Beanname); } // นี่คือสถานที่ในการสร้างถั่วและทำโดย createBeanInstance ถ้า (instanceWrapper == null) {// สร้างอินสแตนซ์ใหม่ตามถั่วที่ระบุโดยใช้กลยุทธ์ที่สอดคล้องกันเช่น: วิธีโรงงาน } วัตถุสุดท้าย Bean = (InstantWrapper! = null? InstantWrapper.getWrappingInstance (): null); คลาส <s?> beanTepe = (อินสแตนซ์ wrapper! = null? instantwrapper.getWrappedclass (): null); // อนุญาตให้โพสต์โปรเซสเซอร์ปรับเปลี่ยนคำจำกัดความถั่วที่ผสาน ซิงโครไนซ์ (mbd.postprocessinglock) {ถ้า (! mbd.postprocessed) {applymergedebeandefinitionpostprocessors (MBD, Beantype, Beanname); mbd.postprocessed = true; }} // Cache Singletons อย่างกระตือรือร้นเพื่อให้สามารถแก้ไขการอ้างอิงแบบวงกลม // แม้เมื่อถูกเรียกโดยอินเทอร์เฟซวงจรชีวิตเช่น BeanFactoryAware // จำเป็นหรือไม่ที่จะต้องเปิดเผยล่วงหน้า: Singleton & อนุญาตให้มีการพึ่งพาแบบวงจรและถั่วปัจจุบันถูกสร้างขึ้นตรวจจับการพึ่งพาวงจรบูลีน EarlysingleTonexPosure = (MBD.ISSINGLETON () && this if (ournsingletonexposure) {ถ้า (logger.isdebugenabled ()) {logger.debug ("การแคชถั่วอย่างกระตือรือร้น '" + beanname + "' เพื่ออนุญาตให้แก้ไขการอ้างอิงแบบวงกลมที่อาจเกิดขึ้น"); } // เพื่อหลีกเลี่ยงการพึ่งพาช่วงเวลาปลายทางวัตถุที่สร้างอินสแตนซ์สามารถเพิ่มเข้าไปในโรงงานก่อนที่จะเริ่มต้นถั่วเสร็จแล้ว AddsingletonFactory (Beanname, New ObjectFactory <Object> () {@Override วัตถุสาธารณะ getObject () โยน beansexception {// พึ่งพาการอ้างอิงถึงถั่วอีกครั้ง GetearlyBeanReference (Beanname, MBD, Bean); } // เริ่มต้นอินสแตนซ์ถั่ว // นี่คือการเริ่มต้นของถั่วและการฉีดพึ่งพามักจะเกิดขึ้นที่นี่ การเปิดเผยความเสียใจนี้กลับมาเป็นถั่วหลังจากประมวลผลการเริ่มต้น Object ExposedObject = ถั่ว; ลอง {// ใส่ถั่วและฉีดแต่ละค่าแอตทริบิวต์ ในหมู่พวกเขาอาจมีคุณลักษณะที่ขึ้นอยู่กับถั่วอื่น ๆ ถั่วพึ่งพาจะเริ่มต้น populatebean ซ้ำ (Beanname, MBD, InstanceWrapper); if (encosedObject! = null) {// การเรียกใช้วิธีการเริ่มต้นเช่น init-method encosedObject = InitializeBean (BeanName, ExposedObject, MBD); }} catch (throwable ex) {if (ex instanceof beancreationexception && beanname.equals (((BeancreationException) Ex) .getBeanName ())) {โยน (BeancreationException) อดีต; } else {โยน beancreationexception ใหม่ (mbd.getResourcedescription (), Beanname, "การเริ่มต้นของถั่วล้มเหลว", ex); }} if (ournsingletonexposure) {Object EarlySingLetOnReference = GetSingleton (BeanName, False); // EarlySingleTonReference นั้นไม่ว่างเปล่าเฉพาะในกรณีที่ตรวจพบการพึ่งพาแบบวงกลมถ้า (EarlySingleTonReference! = NULL) {ถ้า (encosedObject == Bean) {// ถ้า encosedObject ไม่เปลี่ยนแปลงในวิธีการเริ่มต้น } อื่นถ้า (! this.allowrawinjectedDespitewrapping && hasdependentBean (beanname)) {String [] ขึ้นอยู่กับ Beans = getDependentBeans (BeanName); ตั้งค่า <String> realDependentBeans = new LinkedHashSet <String> (ขึ้นอยู่กับความยาว); สำหรับ (String adperentbean: ขึ้นอยู่กับ) {// การตรวจจับการพึ่งพาถ้า (! ลบออก onifcreatedfortypecheckonly (ขึ้นอยู่กับ)) {realderentbeans.add (ขึ้นอยู่กับ); }} // เนื่องจากถั่วที่มันขึ้นอยู่กับหลังจากที่ถั่วถูกสร้างขึ้นจะต้องถูกสร้างขึ้นจริงแล้วพึ่งพาอาศัยกันไม่ได้ว่างเปล่าซึ่งหมายความว่าถั่วที่มันขึ้นอยู่กับหลังจากที่ถั่วปัจจุบันถูกสร้างขึ้นไม่ได้ถูกสร้างขึ้นนั่นคือการพึ่งพาวงกลม ได้รับการฉีดเข้าไปในถั่วอื่น ๆ [" + stringutils.collectiontocommadeLimitedString (จริงพึ่งพาอาศัย) +"] ในเวอร์ชันดิบของมันเป็นส่วนหนึ่งของการอ้างอิงแบบวงกลม แต่ในที่สุดก็เป็น " +" การปิดธง 'lewloweagerinit' เช่น "); }}}}} // ลงทะเบียนถั่วเป็นทิ้ง ลอง {// ลงทะเบียน bean ตามขอบเขต registerDisposableBeanifnitary (Beanname, Bean, MBD); } catch (beandefinitionValidationException ex) {โยน beancreationException ใหม่ (mbd.getResourcedescription (), Beanname, "ลายเซ็นการทำลายล้างที่ไม่ถูกต้อง", Ex); } return encosedObject; -การฉีดขึ้นอยู่กับการพึ่งพานั้นเกี่ยวข้องกับสองกระบวนการหลัก
จากข้างต้นเราจะเห็นได้ว่าวิธีการที่เกี่ยวข้องอย่างใกล้ชิดโดยเฉพาะอย่างยิ่งกับการฉีดพึ่งพา
CreateBeanInstance
สร้างวัตถุ Java ที่มีอยู่ในถั่ว
PopulateBean
การประมวลผลกระบวนการประมวลผลคุณสมบัติของวัตถุถั่วต่าง ๆ (เช่นกระบวนการประมวลผลการพึ่งพา)
มาดูซอร์สโค้ด createBeanInstance ก่อน
/** * สร้างอินสแตนซ์ใหม่สำหรับถั่วที่ระบุโดยใช้กลยุทธ์อินสแตนซ์ที่เหมาะสม: * วิธีโรงงาน, ตัวสร้างอัตโนมัติหรืออินสแตนซ์ง่าย ๆ * @param beanname ชื่อของถั่ว * @param mbd คำจำกัดความถั่วสำหรับถั่ว * @param args อาร์กิวเมนต์ที่ชัดเจนเพื่อใช้สำหรับตัวสร้างหรือวิธีการเรียกใช้โรงงาน * @return a beanwrapper สำหรับอินสแตนซ์ใหม่ ณ จุดนี้ // ยืนยันว่าคลาสของอินสแตนซ์ถั่วที่คุณต้องการสร้างสามารถเป็นคลาสอินสแตนซ์ <?> beanClass = ResolveBeanClass (MBD, BeanName); if (beanclass! = null &&! modifier.ispublic (beanclass.getModifiers ()) &&! mbd.isnonpublicaccessallowed ()) {โยน beancreationexception ใหม่ } ซัพพลายเออร์ <?> InstancesUpplier = mbd.getInstancesUpplier (); if (InstancesUpplier! = null) {return obtaInFromSUpplier (InstancesUpplier, BeanName); } // หากวิธีการโรงงานไม่ว่างให้ใช้กลยุทธ์วิธีการโรงงานเพื่อสร้างอินสแตนซ์ถั่วถ้า (mbd.getFactoryMethodname ()! = null) {ส่งคืน InstantiateAsingFactoryMethod (Beanname, MBD, Args); } // ทางลัดเมื่อสร้างถั่วเดียวกันอีกครั้ง ... บูลีนแก้ไข = เท็จ; บูลีน AutoWirenary = false; if (args == null) {ซิงโครไนซ์ (mbd.constructorargumentLock) {// คลาสมีตัวสร้างหลายตัวสร้างแต่ละตัวสร้างมีพารามิเตอร์ที่แตกต่างกันดังนั้นก่อนที่จะเรียกคุณต้องล็อคตัวสร้างหรือวิธีการที่สอดคล้องกัน AutoWirEnsure = MBD.ConstructorArgumentsResolved; }}} // ถ้ามันถูกแยกวิเคราะห์ให้ใช้วิธีการสร้างที่แยกวิเคราะห์โดยไม่ต้องล็อคอีกครั้งถ้า (แก้ไข) {ถ้า (AutoWirEnSeCHE) {// constructor โดยอัตโนมัติจะส่งคืน AutoWireConstructor (Beanname, MBD, NULL); } else {// constructor โดยใช้ตัวสร้างเริ่มต้นเพื่อสร้าง Instructor InstantiateBean (Beanname, MBD); }} // จำเป็นต้องกำหนดตัวสร้าง ... // อินสแตนซ์ถั่วโดยใช้ตัวสร้างคอนสตรัคเตอร์ <?> [] cTors = deconeconstructorsFrombeanPostProcessors (BeanClass, BeanName); if (ctors! = null || mbd.getResolvedautowiremode () == rootbeanDefinition.autowire_constructor || mbd.hasconstructorargumentValues () ||! } // ไม่มีการจัดการพิเศษ: เพียงแค่ใช้ตัวสร้าง No-Arg // อินสแตนซ์ถั่วโดยใช้ตัวสร้างเริ่มต้น } /*** อินสแตนซ์ถั่วที่กำหนดโดยใช้ตัวสร้างเริ่มต้น * @param beanname ชื่อของถั่ว * @param mbd คำจำกัดความถั่วสำหรับถั่ว * @return a beanwrapper สำหรับอินสแตนซ์ใหม่ */// antantiatebean ที่พบมากที่สุดในการป้องกัน Beanwrapper Instantiatebean กลยุทธ์การสร้างอินสแตนซ์เริ่มต้นคือ // CGLIBSUBCLASSINGINSTANTIATIONSTRATEGY นั่นคืออินสแตนซ์ถั่วโดยใช้ CGLIB ลอง {Object beaninstance; ผู้ปกครอง beanfactory สุดท้าย = สิ่งนี้; if (system.getSecurityManager ()! = null) {beaninstance = accessController.doprivileged (ใหม่ PrivilegedAction <jobch> () {@Override วัตถุสาธารณะ Run () {return getinstantiationstrategy () } else {beaninstance = getInstantiationstrategy (). อินสแตนซ์ (mbd, beanname, parent); } beanwrapper bw = ใหม่ beanwrapperimpl (beaninstance); InitBeanWrapper (BW); กลับ BW; } catch (throwable ex) {โยน beancreationexception ใหม่ (mbd.getResourcedescription (), Beanname, "การสร้างอินสแตนซ์ของถั่วล้มเหลว", อดีต); -CGLIB ใช้ที่นี่เพื่อสร้างอินสแตนซ์ถั่ว CGLIB เป็นไลบรารีคลาสสำหรับเครื่องกำเนิดไฟฟ้า bytecode ซึ่งให้ชุดของ APIs เพื่อให้ฟังก์ชั่นของการสร้างและแปลงจาวาไบต์
ในฤดูใบไม้ผลิ AOP CGLIB ยังใช้เพื่อปรับปรุงจาวาไบต์ ในคอนเทนเนอร์ IOC เพื่อทำความเข้าใจวิธีการใช้ CGLIB เพื่อสร้างวัตถุถั่วคุณต้องดูคลาส SimpleInstantiationstrategy เป็นคลาสเริ่มต้นที่ใช้โดยสปริงเพื่อสร้างวัตถุถั่ว มันมีสองวิธีในการสร้างอินสแตนซ์วัตถุถั่ว
คลาสสาธารณะ SimpleInstantiationStrategy ใช้ InstantiationStrategy {@Override วัตถุสาธารณะอินสแตนซ์ (RootBeanDefinition BD, String BeanName, เจ้าของ BeanFactory) {// อย่าแทนที่คลาสด้วย cGLIB หากไม่มีการแทนที่ if (bd.getMethodoverrides (). isempty ()) {// ที่นี่คุณจะได้รับตัวสร้างหรือวิธีการที่ระบุจากโรงงานเพื่อสร้างอินสแตนซ์ beanConstructor <?> constructOrtouse; ซิงโครไนซ์ (bd.constructorargumentLock) {constructortouse = (ตัวสร้าง <?>) bd.resolvedconstructororofactorymethod; if (constructOrtouse == null) {คลาสสุดท้าย <?> clazz = bd.getBeanClass (); if (clazz.isinterface ()) {โยน beaninstantiationexception ใหม่ (clazz, "คลาสที่ระบุเป็นอินเทอร์เฟซ"); } ลอง {if (system.getSecurityManager ()! = null) {constructOrtouse = AccessController.doprivileged (ใหม่ PrivilegedExceptionAction <Constructor <? >> () {@Override Public Constructor <?> Run () } else {constructortouse = clazz.getDeclaredConstructor ((คลาส []) null); } bd.resolvedConstructororFactoryMethod = ConstructOrtouse; } catch (throwable ex) {โยน beaninstantiationexception ใหม่ (clazz, "ไม่พบตัวสร้างเริ่มต้น", ex); }}} // อินสแตนซ์ผ่าน beanutils การสร้างอินสแตนซ์ของ beanutils นี้อินสแตนซ์ถั่วผ่านตัวสร้าง ใน beanutils คุณสามารถเห็นการโทรเฉพาะ ctor.newinstance (args) return beanutils.instantiateclass (constructortouse); } else {// อินสแตนซ์วัตถุส่งคืน InstantiAtewithMethodinject (bd, Beanname, เจ้าของ); -การจัดการการพึ่งพาระหว่างถั่ว
การเข้าสู่การประมวลผลการพึ่งพาเป็นวิธีการของ PopulateBean ที่กล่าวถึงข้างต้น เนื่องจากมีหลายแง่มุมที่เกี่ยวข้องฉันจะไม่โพสต์รหัสที่นี่ การแนะนำสั้น ๆ เกี่ยวกับกระบวนการประมวลผลการพึ่งพา: ในวิธีการ PopulateBean
ก่อนอื่นให้ได้ค่าคุณสมบัติที่ตั้งไว้ใน beandefinition จากนั้นเริ่มกระบวนการฉีดพึ่งพา
ก่อนอื่นการฉีด AutoWire สามารถประมวลผลได้โดยชื่อหรือ bytype จากนั้นแอตทริบิวต์จะถูกฉีด
จากนั้นคุณต้องแยกวิเคราะห์การอ้างอิงถั่ว หลังจากการแยกวิเคราะห์ผู้จัดการ, Manageset, managemap ฯลฯ คุณได้เตรียมเงื่อนไขสำหรับการฉีดพึ่งพา นี่คือที่ที่คุณตั้งค่าวัตถุถั่วเป็นคุณสมบัติถั่วอื่นที่ขึ้นอยู่กับและคุณสมบัติที่ประมวลผลนั้นมีความหลากหลาย
การฉีดขึ้นอยู่กับการพึ่งพาเกิดขึ้นใน setPropertyValues ของ beanwrapper แต่ความสมบูรณ์ที่เฉพาะเจาะจงถูกนำไปใช้ใน subclass beanwrapper beanwrapperimpl มันจะเสร็จสิ้นการฉีดค่าทรัพย์สินของถั่วรวมถึงการฉีดอาร์เรย์การฉีดคลาสการรวบรวมเช่นรายการและการฉีดคลาสที่ไม่ใช่การสะสม
หลังจากชุดของการฉีดแล้วกระบวนการฉีดพึ่งพาของคุณสมบัติถั่วต่างๆจะเสร็จสมบูรณ์
ในระหว่างกระบวนการสร้างถั่วและการฉีดพึ่งพาวัตถุการฉีดขึ้นอยู่กับการพึ่งพาจะต้องเสร็จสิ้นการทำซ้ำตามข้อมูลใน beandefinition
จากกระบวนการเรียกซ้ำก่อนหน้านี้เราจะเห็นว่าการเรียกซ้ำเหล่านี้ทั้งหมดพกพาได้ด้วย GetBean
การเรียกซ้ำคือการหาถั่วที่จำเป็นและสร้างการเรียกซ้ำไปยังถั่วในระบบบริบท
การเรียกซ้ำอีกประการหนึ่งคือการเรียกวิธีการ getbean ของคอนเทนเนอร์ซ้ำในระหว่างการฉีดพึ่งพาเพื่อให้ได้ถั่วพึ่งพาถั่วในปัจจุบันและยังกระตุ้นการสร้างและการฉีดถั่วพึ่งพา
เมื่อทำการฉีดพึ่งพาคุณสมบัติของถั่วกระบวนการแยกวิเคราะห์ก็เป็นกระบวนการเรียกซ้ำ ด้วยวิธีนี้ตามการพึ่งพาการสร้างและการฉีดถั่วจะเสร็จสิ้นเลเยอร์โดยเลเยอร์จนกว่าการสร้างถั่วปัจจุบันจะเสร็จสมบูรณ์ในที่สุด ด้วยการสร้างถั่วระดับบนสุดนี้และความสมบูรณ์ของการฉีดขึ้นอยู่กับการพึ่งพาแอตทริบิวต์หมายความว่าการแก้ปัญหาการฉีดของห่วงโซ่การพึ่งพาทั้งหมดที่เกี่ยวข้องกับถั่วปัจจุบันเสร็จสมบูรณ์
หลังจากการสร้างถั่วและการฉีดพึ่งพาเสร็จสมบูรณ์ชุดของถั่วที่เชื่อมโยงโดยการพึ่งพาจะถูกสร้างขึ้นในภาชนะ IOC ถั่วนี้ไม่ใช่วัตถุ Java ที่เรียบง่ายอีกต่อไป หลังจากความสัมพันธ์แบบพึ่งพาระหว่างซีรีย์ถั่วและถั่วถูกสร้างขึ้นแล้วมันสามารถใช้งานได้อย่างสะดวกสำหรับแอปพลิเคชันระดับบนผ่านวิธีการเชื่อมต่อที่เกี่ยวข้องของ IOC
2. แอตทริบิวต์ขี้เกียจและล่วงหน้า
ในวิธีการรีเฟรชก่อนหน้านี้เราจะเห็นได้ว่า FinishBeanFactoryInitialization ถูกเรียกให้ประมวลผลถั่วที่กำหนดค่าด้วย Lazy-init
ในความเป็นจริงในวิธีนี้การประมวลผลของแอตทริบิวต์ขี้เกียจจะถูกห่อหุ้มและการประมวลผลจริงจะทำในวิธี preinstantiatesingleton ของคอนเทนเนอร์พื้นฐานของ defaultlistablebeanfactory วิธีนี้เสร็จสิ้นถั่วซิงเกิลที่ได้รับการสนับสนุนล่วงหน้าและความสำเร็จล่วงหน้านี้ได้รับการมอบหมายอย่างชาญฉลาดไปยังคอนเทนเนอร์เพื่อนำไปใช้ หากจำเป็นต้องมีการปรับปรุงล่วงหน้าจะใช้ GetBean ที่นี่เพื่อกระตุ้นการฉีดขึ้นอยู่กับการพึ่งพา เมื่อเปรียบเทียบกับทริกเกอร์การฉีดพึ่งพาการพึ่งพาปกติเวลาที่ทริกเกอร์และโอกาสแตกต่างกันเท่านั้น ที่นี่การฉีดขึ้นอยู่กับการพึ่งพาเกิดขึ้นในระหว่างกระบวนการรีเฟรชของคอนเทนเนอร์นั่นคือในระหว่างกระบวนการเริ่มต้นของคอนเทนเนอร์ IOC ซึ่งแตกต่างจากการฉีดขึ้นอยู่กับการพึ่งพาสามัญเมื่อคอนเทนเนอร์ร้องขอถั่วเป็นครั้งแรกหลังจากที่คอนเทนเนอร์ IOC เริ่มต้นผ่าน Getbean
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น