لماذا تبدأ في النظر في رمز مصدر الربيع
لقد كنت أكتب رمزًا في منتصف الطريق عبر وظائف لمدة عام ونصف تقريبًا. لقد كنت أستخدم إطار الربيع منذ أن بدأت العمل. على الرغم من أنني أستطيع استخدامه وبنشائه ، إلا أنني لا أفهم في كثير من الأحيان المبادئ التي تقف وراءها ، مثل: كيف يتحكم الربيع في معاملات ، وكيف يتعامل SpringMVC مع الطلبات ، وكيف يتم تنفيذ AOP ... وهذا يجعل الناس يشعرون بعدم الارتياح الشديد ، لذلك ابدأ في دراسة رمز الربيع المصدر ببطء أثناء قراءة الكتاب !!!
كيفية عرض رمز المصدر بكفاءة
إجابتي هي إلقاء نظرة على الكود المصدري مع أسئلة محددة ، وإلا من السهل جدًا أن تتعثر في تفاصيل الكود المصدر ، وبعد ذلك سوف تغمى. أخيرًا ، تكتشف ما كنت تقرأه لفترة طويلة.
مقدمة
Spring هو إطار عمل مفتوح المصدر على مستوى التصميم يحل مشكلة الاقتران الفضفاضة بين طبقة منطق العمل والطبقات الأخرى ، ويدمج أفكار البرمجة الموجهة نحو الواجهة عبر تطبيق النظام بأكمله. إنها أيضًا واحدة من المهارات الأساسية في عمل جافا ...
نظرًا لأنه يسجل عملية تحليل رمز مصدر الربيع ، فلن أوضح الاستخدام التفصيلي.
الكود الأساسي
<Rependency> <roupeD> org.springframework </rougeid> <StifactId> spring-context </shintifactid> <soph> 5.0.2.release </version> </sependency>
الاستخدام
تطبيق الفئة العامة {public static void main (string [] args) {BeanDefinitionregistry BeanFactory = new DefaultListableBeanFactory () ؛ XmlBeanDefinitionReader Reader = New XmlBeanDefinitionReader (BeanFactory) ؛ مورد ClassPathResource = جديد classPathResource ("Bean.xml") ؛ // نقطة الدخول لتحميل الموارد بأكمله. reader.loadBeanDefinitions (Resource) ؛ }}فك التشفير
DefaultListableBeanfactory هو التنفيذ الافتراضي لتسجيل الربيع وتحميل حبوب. يمكن أن يطلق عليه الجد في قالب الربيع IOC بأكمله.
تتبع DefaultListableBeanfactory ، يمكنك العثور على كتل التعليمات البرمجية التالية. ما هو الغرض من هذا التصميم؟
Public AbstractAutOwIreCableBeanFactory () {super () ؛ transedependencyInterface (Beannameaware.class) ؛ transuredependencyInterface (BeanFactoryAware.class) ؛ transedependencyInterface (BeanClassloaderaware.class) ؛}على سبيل المثال ، عندما تكون هناك السمة B في A ، ستقوم Spring تلقائيًا بتثبيت السمة B إذا تبين أن السمة B لم يتم إنشاء مثيل لها عند الحصول على السمة A. هذه ميزة مهمة مقدمة أيضًا في الربيع. في بعض الحالات ، لن تتم تهيئة B ، مثل تنفيذ واجهة Beannameaware.
يقدم Spring هذا: عندما يتجاهل التجميع التلقائي واجهة التبعية المحددة ، مثل تحليل تبعيات تسجيل سياق التطبيق من خلال طرق أخرى ، على غرار حقن Beanfactory من خلال Beanfactoryaware أو حقن ApplicationContext من خلال ApplicationContaware.
إدارة الموارد
يتم استخدام واجهة الموارد لإدارة الملف وعنوان URL و classpath والموارد الأخرى. المورد مسؤول عن قراءة ملف التكوين ، أي أنه يتغلف ملف التكوين في مورد ، ثم تسليمه إلى XmlBeanDefinitionReader للمعالجة.
XML تحليل
XMLBeanDefinitionReader هو تطبيق لقراءة ملفات موارد الربيع ، والتحليل ، والتسجيل ، ويجب أن نركز على هذا الفئة.
Track reader.loadBeanDefinitions(resource); ، يمكننا أن نرى الرمز الأساسي التالي (استبعاد التعليقات ورمي الاستثناءات)
int public loadbeandefinitions (encodedResource encodedResource) يلقي BeanDefinitionStoreException {try {inputStream inputStream = encodedResource.getResource (). getInputStream () ؛ جرب {inputsource inputsource = new inputsource (inputStream) ؛ if (encodedResource.getenCoding ()! = null) {inputsource.setenCoding (encodedResource.getenCoding ()) ؛ } إرجاع doloadbeandefinitions (Inputsource ، encodedResource.getResource ()) ؛ } أخيرًا {inputStream.close () ؛ }}}قام الرمز أعلاه أولاً بإجراء عملية ترميز على المورد ، بهدف القلق بشأن مشكلة الترميز في XML
إذا لاحظت InputSource inputSource = new InputSource(inputStream); ، اسم الحزمة الخاص به هو في الواقع org.xml.sax ، لذلك يمكننا أن نستنتج أن Spring يستخدم تحليل SAX ويستخدم InputSource لتحديد كيفية قراءة ملفات XML.
أخيرًا ، يتم تمرير البيانات المعدة إلى جزء المعالجة الأساسية الحقيقية من خلال المعلمات doLoadBeanDefinitions(inputSource, encodedResource.getResource())
احصل على المستند
1. doLoadBeanDefinitions(inputSource, encodedResource.getResource()); حذف العديد من المصيد والتعليقات
محمية int doloadbeandefinitions (InputSource Inputsource ، Resource Resource) يلقي BeanDefinitionStoreException {try {docum doc = doloaddocument (Inputsource ، Resource) ؛ Return RecordBeanDefinitions (DOC ، Resource) ؛ }} 2. doLoadDocument(inputSource, resource);
مستند محمي Doloaddocument (InputSource Inputsource ، Resource Resource) يلقي الاستثناء {return this.documentloader.loadDocument (Inputsource ، getentityResolver () ، this.errorHandler ، getValidationModeForresأولاً ، يمكنك الحصول على وضع التحقق (DTD أو XSD) لملف XML من خلال getValidationModeForresource. يمكنك تعيين طريقة التحقق بنفسك. افتراضيًا ، يتم تمكين Valaction_auto ، أي أن وضع التحقق يتم الحصول عليه تلقائيًا. اقرأ ملف XML من خلال InputStream وتحقق مما إذا كان يحتوي على كلمات doctype. إذا كان يحتوي على ذلك ، فهو DTD ، وإلا فإنه سيعود XSD.
أنماط التحقق من ملفات XML الشائعة هي:
يشير XMLValidationModeDetector { /**** إلى أنه ينبغي استخدام التحقق من صحة DTD (وجدنا إعلانًا "doctype"). */ Public Static Final Vality_dtd = 2 ؛ /*** يشير إلى أنه ينبغي استخدام التحقق من صحة XSD (لا يوجد أي إعلان "doctype"). */ public static Final Vality_xsd = 3 ؛ int public detectValidationMode (inputStream inputStream) يلقي ioException {}} تشارك معلمة entityResolver في this.documentLoader.loadDocument
المستند العام loadDocument (InputSource InputSource ، entityResolver entityResolver ، errorHandler errorler ، int ValidationMode ، Boolean NamesPaceare) يلقي الاستثناء {}ما هو entityResolver؟ التفسير الرسمي: إذا كان تطبيق SAX يحتاج إلى تنفيذ معالجة مخصصة للكيانات الخارجية ، فيجب عليه تنفيذ هذه الواجهة وتسجيل مثيل مع محرك SAX باستخدام طريقة setentityResolver. وهذا يعني ، من أجل تحليل XML ، ستقرأ SAX أولاً الإعلان على مستند XML ، والبحث عن تعريف DTD المقابل وفقًا للإعلان ، وذلك للتحقق من المستند ، وقواعد البحث الافتراضية (أي تنزيل الشبكة ، وتنزيل تعريف DTD من خلال عنوان DTD URI الذي تم إعلانه بواسطة XML) ، وأداء المصادقة. عملية التنزيل هي عملية طويلة ، وعندما تكون الشبكة غير متوفرة ، سيتم الإبلاغ عن خطأ هنا لأنه لم يتم العثور على DTD المقابل.
تتمثل وظيفة EntityResolver في أن المشروع نفسه يمكن أن يوفر طريقة لكيفية العثور على إعلانات DTD ، أي أن البرنامج ينفذ عملية العثور على DTDs ، والتي تتجنب إيجاد التصريحات المقابلة من خلال الشبكة.
3. EentityResolver يقبل معلمتين:
الإدخال التجريدي العام حل الحفل (سلسلة publicId ، سلسلة النظام) يلقي saxexception ، ioException ؛
3.1 حدد ملف bean.xml ، مع المحتوى كما يلي (وضع XSD)
<؟ XSI: schemalocation = "http://www.springframework.org/schema/beans.xsd"> </bans>
تم تحليلها إلى المعلمتين التاليتين:
3.2 تعريف ملف bean.xml ، مع المحتوى كما يلي (وضع DTD)
<؟
تم تحليلها إلى المعلمتين التاليتين:
3.3 يستخدم Spring ElevatingentityResolver لتحرير EntityResolver
فئة publicatingentityresolver {Override @nullable مقاطع عامة ، فإن solutionSource solveentity (سلسلة publicId ، @nullable string systemId) يلقي saxexception ، ioException {if (systemId! = null) {if (systemid.endswith (dtd_suffix)) } if if (systemId.endswith (xsd_suffix)) {return this.schemaresolver.resolveentity (publicId ، systemId) ؛ }} الإرجاع null ؛ }}يمكننا أن نرى أن المحللين المختلفون يستخدمون لأوضاع مختلفة
تسجيل الفول
بعد قراءة التحليل XML التحقق ، تابع تتبع الرمز ومعرفة كيفية تسجيلات الربيع معلومات الفاصوليا بناءً على المستند
الطبقة العامة XMLBeanDefinitionReader {public int registerBeanDefinitions (مستند المستند ، مورد المورد) يلقي beandefinitionstoreException {// Create DocumentReader BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader () ؛ // سجل عدد التعريفات قبل الإحصائيات intbefore = getRegistry (). getBeanDefinitionCount () ؛ . // سجل عدد التعريفات المحملة هذه المرة GetRegistry (). getBeanDefinitionCount () - countbefore ؛ }}عند تسجيل الفول ، استخدم أولاً فئة BeanDefinitionParserDelegate لتحديد ما إذا كانت مساحة الاسم الافتراضية. يتمثل التنفيذ في تحديد ما إذا كانت مساحة الاسم URI مساوية لـ URI الافتراضي:
الفئة العامة BeanDefinitionParserDelegate {Static Static Final String Beans_namespace_uri = "http://www.springframework.org/schema/beans" ؛ boolean public ISDefaultNamesPace (nullable string namespaceuri) {return (! stringUtils.hasLength (namespaceuri) || beans_namespace_uri.equals (namespaceuri)) ؛ }} Track documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); ، حيث يتم تحويل DOC من خلال LoadDocument في كتلة الكود السابقة. الغرض الرئيسي من هذه الطريقة هو استخراج العقد الجذرية (الفاصوليا)
الفئة العامة defaultBeanDefinitionDocumentReader {Override public void registerBeanDefinitions (docum doc ، xmlreadercontext readerContext) {this.readerContext = readerContext ؛ logger.debug ("تحميل تعريفات الفاصوليا") ؛ العنصر جذر = doc.getDocumentElement () ؛ DoregisterBeanDefinitions (الجذر) ؛ }} تتبع doRegisterBeanDefinitions(root) وسنرى تدفق المعالجة التالي
void void doregisterBeanDefinitions (element root) {// ... string profiLespec = root.getAttribute (profile_attribute) ؛ // ...// تنفيذ فارغ preprocessxml (الجذر) ؛ parsebeandefinitions (الجذر ، this.delegate) ؛ // التنفيذ الفارغ postprocessxml (الجذر) ؛ this.delegate = parent ؛}أولاً ، تحليل الملف الشخصي (الطريقة الأكثر شيوعًا للعب هي أن كائنات الفول التي تم تهيئتها بواسطة ملفات تعريف مختلفة مختلفة ، لذلك تنفذ بيئات متعددة)
يستخدم التحليل التالي وضع طريقة القالب ، حيث يعد كل من المعالجات preprocessxml و postprocessxml طريقين فارغتين ، بحيث يمكن للمادة الفرعية اللاحقة إجراء بعض المعالجة قبل وبعد التحليل. فقط تجاوز هاتين الطريقتين.
تحليل وتسجيل Beandefinition ، هذا الجزء من الكود بسيط نسبيا
الفئة العامة defaultBeanDefinitionDocumentReader { / *** حل العقد الأخرى تحت استيراد عقدة الجذر "،" الاسم المستعار "،" Bean ". root.getchildnodes () ؛ device.parsecustomElement (eLe) ؛ } if (deving.nodenameequals (eLe ، alias_element) {processAliasStration (eLe) ؛ Recurse DoregisterBeanDefinitions (ELE) ؛ null) {bdholder = devicate.decoreBeanDefinition (eLe ، bdholder) ؛ GetReaderContext (). "فشل في تسجيل تعريف الفاصوليا" + Bdholder.getBeanName () تفويض طريقة parsebeandefinitionElement لفئة BeanDefinitionParserDelegate لتحليل العناصر ، وإرجاع مثيل نوع bdholder من نوع BeandefinitionHolder (بما في ذلك السمات المختلفة لفئة ملف التكوين ، والاسم ، والمعرف ، وما إلى ذلك).
عندما لا يكون حامل BDHOND الذي تم إرجاعه فارغًا ، إذا كانت هناك سمة مخصصة في عقدة الطفل للتسمية الافتراضية ، يتم تحليل التسمية المخصصة وتحليلها مرة أخرى ، ثم BeanDefinitionReaderUtils.registerBeanDefinition(); يسجل حامل BDHOLE ويرسل حدث التسجيل ، وأبلغ الفاصوليا الاستماع ذات الصلة أن التسجيل كان ناجحًا.
لخص
بعد بضع خريف غير معروف ، الشتاء والربيع والصيف ، سيتبع كل شيء الاتجاه الذي تريده ...
حسنًا ، ما سبق هو المحتوى الكامل لهذه المقالة. آمل أن يكون لمحتوى هذه المقالة قيمة مرجعية معينة لدراسة أو عمل الجميع. إذا كان لديك أي أسئلة ، فيمكنك ترك رسالة للتواصل. شكرا لك على دعمك إلى wulin.com.
قل شيئا
رمز النص الكامل: https://gitee.com/battcn/battcn-spring-source/tree/master/chapter1 (تنزيل محلي)