يعد التجميع التلقائي الخاص بـ Springboot الأساس للاصطناع والشرط المسبق للخدمات الدقيقة. الموضوع الرئيسي هذه المرة هو معرفة كيفية تنفيذها. نستخدم الكود المصدري لفهم خصوصيات وعموميات التجميع التلقائي.
1.1. حول springbootapplication
عندما نكتب Springboot Project ، فإن springbootapplication هو التعليق التوضيحي الأكثر شيوعًا. يمكننا إلقاء نظرة على الكود المصدر:
/ * * حقوق الطبع والنشر 2012-2017 المؤلف أو المؤلفين الأصليين. * * مرخصة بموجب ترخيص Apache ، الإصدار 2.0 ("الترخيص") ؛ * لا يجوز لك استخدام هذا الملف إلا في الامتثال للترخيص. * يمكنك الحصول على نسخة من الترخيص على * * http://www.apache.org/licenses/license-2.0 * * ما لم يكن مطلوبًا بموجب القانون المعمول به أو يتم الاتفاق عليه في الكتابة ، يتم توزيع البرمجيات * الموزعة بموجب الترخيص على أساس "كما هو" ، * دون ضمانات أو شروط من أي نوع ، إما صريحة أو ضمنية. * راجع ترخيص أذونات حوكمة اللغة المحددة والقيود * بموجب الترخيص. */package org.springframework.boot.autoconfigure ؛ import java.lang.annotation.documented ؛ import java.lang.annotation.elementtype ؛ import java.lang.annotation.inherited ؛ import java.lang.antation.antentation ؛ java.lang.annotation.target ؛ استيراد org.springframework.boot.springbootconfiguration ؛ استيراد org.springframework.boot.context.typeexcludefilter ؛ استيراد org.springframework.context.annotation.bean ؛ org.springframework.context.annotation.componentscan ؛ استيراد org.springframework.context.annotation.componentscan.filter ؛ استيراد org.springframework.context.annotation.configuration org.springframework.core.annotation.aliasfor ؛/** * يشير إلى فئة تكوين {link} التي تعلن عن واحد أو أكثر * {link bean} و {link components} هذا هو التعليق التوضيحي * الذي يعادل إعلان {codeConfiguration} و * {code enableautoconfiguration} و {codeCodeComponentscan}. * * author phillip webb * author stephane nicoll * since 1.2.0 */@target (elementType.type)@repinention (enthypolicy.runtime)@documented@mornited@springbootconfiguration enableAutOconFiguration@componentscan (iscludefilters = TypeexCludeFilter.Class) ، filter (type = filterType.custom ، الفئات = autoConFigurationExCludeFilter.class)}) public interface springbootapplication { /*** استبعاد فئات التكوين التلقائية المحددة التي لن يتم تطبيقها أبدًا. * regurn الفئات لاستبعاد */ aliasfor (annotation = enableeautoconfiguration.class ، Attribute = "Exclude") class <؟ /** * استبعاد أسماء فئة التكوين التلقائي المحددة بحيث لا يتم تطبيقها أبدًا. * return أسماء الفئة لاستبعاد * since 1.3.0 */ aliasfor (التعليقات التوضيحية = EnaLeAuToConfiguration.class ، Attribute = "ExcludEname") String [] ExcludEname () default {} ؛ /*** الحزم الأساسية للمسح للمكونات المشروحة. استخدم {link #ScanBasePackageClasses} * للحصول على بديل آمن لأسماء الحزم القائمة على السلسلة. * @Return Base Packages to Scan * @since 1.3.0 */ aliasfor (annotation = componentscan.class ، Attribute = "BasePackages") String [] ScanBasePackages () default {} ؛ /** * بديل لـ Type-Safe لـ {link #ScanBasePackages} لتحديد الحزم للمسح الضوئي للمكونات المشروحة. سيتم فحص حزمة كل فئة المحددة. * <p> * فكر في إنشاء فئة أو واجهة خاصة بدون OP في كل حزمة لا تخدم أي غرض سوى الإشارة إليها في هذه السمة. * regurn base packages to scan * @since 1.3.0 */ aliasfor (enrotation = componentscan.class ، attribute = "basepackageClasses") class <؟> []هذا يحتوي على springbootconfiguration ، enableautoconfiguration ، componentscan. هنا ، نظرًا لعدم تحديد حزمة المسح الضوئي ، فهي تقوم بمسح جميع الفئات تحت نفس مستوى الفئة أو نفس الحزمة بشكل افتراضي. بالإضافة إلى ذلك ، springbootconfiguration ، يمكنك معرفة ذلك من خلال الكود المصدري بأنه عملية تكوين:
/ * * حقوق الطبع والنشر 2012-2016 المؤلف أو المؤلفين الأصليين. * * مرخصة بموجب ترخيص Apache ، الإصدار 2.0 ("الترخيص") ؛ * لا يجوز لك استخدام هذا الملف إلا في الامتثال للترخيص. * يمكنك الحصول على نسخة من الترخيص على * * http://www.apache.org/licenses/license-2.0 * * ما لم يكن مطلوبًا بموجب القانون المعمول به أو يتم الاتفاق عليه في الكتابة ، يتم توزيع البرمجيات * الموزعة بموجب الترخيص على أساس "كما هو" ، * دون ضمانات أو شروط من أي نوع ، إما صريحة أو ضمنية. * راجع ترخيص أذونات حوكمة اللغة المحددة والقيود * بموجب الترخيص. */package org.springframework.boot ؛ import java.lang.annotation.documented ؛ import java.lang.annotation.elementtype ؛ import java.lang.annotation.renteent org.springframework.context.annotation.configuration ؛/** * يشير إلى أن الفئة توفر تطبيق Boot Spring * {link configuration @configuration}. يمكن استخدامها كبديل للشروح المعياري لـ SPRING * {CodeCodeChinFiguration} بحيث يمكن العثور على التكوين * تلقائيًا (على سبيل المثال في الاختبارات). * <p> * يجب أن يتضمن التطبيق فقط <em> واحد </em> {CodeSpringBootConfiguration} و * معظم تطبيقات التمهيد الربيعي الاصطلاحية سترثها من * {CodeSpringBootApplication}. * * author phillip webb * since 1.4.0 */@target (elementType.type) reation (attreencepolicy.runtime)@موثقة@configurationpublic@interface springbootconfiguration {}من هذا يمكننا أن نستنتج أن springbootapplication تعادل configuration @componentscan enableautoconfiguration
1.2. enableautoconfiguration
بمجرد إضافة هذا التعليق ، سيتم تمكين وظيفة التجميع التلقائي. وببساطة ، سيحاول Spring العثور على جميع الفاصوليا التي تم تكوينها أسفل ClassPath الخاص بك ثم تجميعها. بالطبع ، عند تجميع الفول ، سيتم تهيئته وفقًا لعدة قواعد تخصيص (مشروطة). لنلقي نظرة على رمز المصدر الخاص به:
/ * * حقوق الطبع والنشر 2012-2017 المؤلف أو المؤلفين الأصليين. * * مرخصة بموجب ترخيص Apache ، الإصدار 2.0 ("الترخيص") ؛ * لا يجوز لك استخدام هذا الملف إلا في الامتثال للترخيص. * يمكنك الحصول على نسخة من الترخيص على * * http://www.apache.org/licenses/license-2.0 * * ما لم يكن مطلوبًا بموجب القانون المعمول به أو يتم الاتفاق عليه في الكتابة ، يتم توزيع البرمجيات * الموزعة بموجب الترخيص على أساس "كما هو" ، * دون ضمانات أو شروط من أي نوع ، إما صريحة أو ضمنية. * راجع ترخيص أذونات حوكمة اللغة المحددة والقيود * بموجب الترخيص. */package org.springframework.boot.autoconfigure ؛ import java.lang.annotation.documented ؛ import java.lang.annotation.elementtype ؛ import java.lang.annotation.inherited ؛ import java.lang.antation.antentation ؛ java.lang.annotation.target ؛ استيراد org.springframework.boot.autoconfigure.condition.conditionalonbean ؛ استيراد org.springframework.boot.autoconfigure.condition.conditionalonbean ؛ استيراد org.springframework.boot.autoconfigure.condition.conditionalonmissingbean ؛ استيراد org.springframework.boot.context.embedded.embeddedservletcontainerfactory ؛ استيراد org.springframework.boot.context.embedded.tomcat.tomcatembeddedServletContainerFactory ؛ import org.springframework.context.annotation.conditional ؛ import org.springframework.context.annotation.configuration ؛ org.springframework.context.annotation.import ؛ استيراد org.springframework.core.io.support.SpringFactoriesLoader ؛/** * تمكين التكوين التلقائي لسياق تطبيق الربيع ، ومحاولة التخمين و * تكوين الحبوب التي من المرجح أن تحتاجها. عادةً ما يتم تطبيق فئات التكوين التلقائي * بناءً على ClassPath وما الفاصوليا التي حددتها. على سبيل المثال ، إذا كان لديك * {code tomcat-embedded.jar} على classpath ، فمن المحتمل أن ترغب في * {link tomcatembeddedservletcontainerfactory} (إلا إذا كنت قد حددت الفاصوليا الخاصة بك * {link jostedservletcontainerfactory}). * <p> * عند استخدام {link springbootapplication} ، يتم تمكين التكوين التلقائي للسياق تلقائيًا ، وبالتالي ، لا يوجد تأثير إضافي. * <p> * يحاول التكوين التلقائي أن يكون ذكيًا قدر الإمكان وسوف تتراجع كما تحدد المزيد من التكوين الخاص بك. يمكنك دائمًا يدويًا {link #exclude ()} أي تكوين * لا تريد تطبيقه أبدًا (استخدم {link #excludename ()} إذا لم يكن لديك * الوصول إليها). يمكنك أيضًا استبعادها عبر الخاصية * {code spring.autoconfigure.exclude}. يتم تطبيق التكوين التلقائي دائمًا * بعد تسجيل الفاصوليا المعرفة من قبل المستخدم. * <p> * حزمة الفئة التي تم شرحها باستخدام {code enableautoconfiguration} ، * عادةً عبر {codespringbootapplication} ، لها أهمية محددة وغالبًا ما يتم استخدامها * كـ "افتراضي". على سبيل المثال ، سيتم استخدامه عند المسح الضوئي لفئات {code entity}. * يوصى عمومًا بوضع {code enableautoConFiguration} (إذا كنت لا تستخدم {codespringbootapplication}) في حزمة الجذر بحيث يمكن البحث في جميع الحزم الفرعية * والفئات. * <p> * فئات التكوين التلقائي هي Spring {link configuration}. تقع * باستخدام آلية {Link SpringFactoriesLoader} (مفتاح ضد هذه الفئة). * عمومًا فاصوليا التكوين التلقائي هي {link شرطية @Conditional} (معظم * باستخدام {link intermonalonclass chonditionalonclass} و * {link intenalonmissingbeanconditionalonmissingbean}). * * Author Phillip Webb * Author Stephane Nicoll * see instelyalonbean * seee instrumentalonmissingbean * seee instrumentalonclass * seee autoconfigureafter * sphingbootapplication */@cumpresswarnings ("deprecation")@target (elementType.type) reentention (attreencepolicy.runtime)@موثقة@ويرث@autoConfigurationPackage@import (enableeaUtoconFigurteMportSelector) "spring.boot.enableautoconfiguration" ؛ /*** استبعاد فئات التكوين التلقائي المحددة بحيث لا يتم تطبيقها أبدًا. * regurn الفئات لاستبعاد */ class <؟> [] Explude () افتراضي {} ؛ /** * استبعاد أسماء فئة التكوين التلقائي المحددة بحيث لا يتم تطبيقها أبدًا. * @إعادة أسماء الفئة لاستبعاد * since 1.3.0 */ string [] excludename () الافتراضي {} ؛}على الرغم من ذلك وفقًا لتعليقات الوثائق ، فإنه يوجهنا إلى رؤية EnableAutoconfigurationImportSelector. لكن الفصل قديم في إصدار springboot1.5 ، لذلك دعونا نلقي نظرة على فئة الأصل التلقائية.
/ * * حقوق الطبع والنشر 2012-2017 المؤلف أو المؤلفين الأصليين. * * مرخصة بموجب ترخيص Apache ، الإصدار 2.0 ("الترخيص") ؛ * لا يجوز لك استخدام هذا الملف إلا في الامتثال للترخيص. * يمكنك الحصول على نسخة من الترخيص على * * http://www.apache.org/licenses/license-2.0 * * ما لم يكن مطلوبًا بموجب القانون المعمول به أو يتم الاتفاق عليه في الكتابة ، يتم توزيع البرمجيات * الموزعة بموجب الترخيص على أساس "كما هو" ، * دون ضمانات أو شروط من أي نوع ، إما صريحة أو ضمنية. * راجع ترخيص الأذونات اللغوية المحددة والقيود * بموجب الترخيص. */package org.springframework.boot.autoconfigure ؛ استيراد java.io.ioException ؛ استيراد java.util.arraylist ؛ استيراد java.util.arrays ؛ import java.util.collections java.util.map ؛ استيراد java.util.set ؛ استيراد java.util.concurrent.timeunit ؛ استيراد org.apache.commons.logging.log ؛ الاستيراد org.apache.commons.logging.logfactory org.springframework.beans.factory.awar ؛ استيراد org.springframework.beans.factory.beanclassloaderaware ؛ استيراد org.springframework.beans.factory.beanfactory org.springframework.beans.factory.nosuchbeanDefinitionException ؛ استيراد org.springframework.beans.factory.config.configurableListableBeanfactory ؛ استيراد org.springframework.boot.bind.relaxedpropertyropertyroperty org.springframework.context.environmentaware ؛ استيراد org.springframework.context.resourceloaderaware org.springframework.core.annotation.annotationAttributes ؛ استيراد org.springframework.core.env.configableenvironment ؛ import org.springframework.core.env.envrial ؛ org.springframework.core.io.support.SpringFactoriesLoader ؛ استيراد org.springframework.core.type.annotationmetadata ؛ import org.springframework.core.type.classReading.cachingMetadatAdataDataTory ؛ org.springframework.core.type.classreading.metadataReaderFactory ؛ استيراد org.springframework.util.assert ؛ استيراد org.springframework.util.classutils ؛ تمكين التكوين * التكوين التلقائي}. يمكن أيضًا تصنيف هذه الفئة إذا كان متغيرًا مخصصًا لـ * {link enileAuToConFiguration enableautoconFiguration}. مطلوب. * * @author Phillip Webb * @author Andy Wilkinson * @author Stephane Nicoll * @author Madhura Bhave * @since 1.3.0 * @see EnableAutoConfiguration */public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {private Static Final String [] no_imports = {} ؛ سجل السجل النهائي الثابت الخاص = logfactory .getLog (autoConfigurationImportSelector.class) ؛ private configurableListableBeanfactory Beanfactory ؛ بيئة البيئة الخاصة ؛ private classloader beanclassloader ؛ Private ResourceLoader ResourceLoader ؛ Override public string [] SelectImports (annotationMetadata annotationMetAdata) {if (! isEnabled (annotationMetadata)) {return no_imports ؛ } جرب {autoconfigurationMetAdata autoconFigurationMetAdata = autoConfigurationMetAdataloader .LoadMetAdata (this.beanclassloader) ؛ esentationAttributes سمات = getAttributes (annotationMetadata) ؛ قائمة <Tring> التكوينات = getCandidateConfigurations (enconotationMetadata ، السمات) ؛ التكوينات = إزالتها (تكوينات) ؛ التكوينات = الفرز (التكوينات ، autoConfigurationMetAdata) ؛ Set <String> issistions = getExClusions (annotationmetadata ، rectributes) ؛ checkexcludedclasses (التكوينات ، exclus) ؛ configurations.removeall (استثناءات) ؛ التكوينات = التصفية (التكوينات ، autoConfigurationMetAdata) ؛ FireautoconFigurationImportevents (التكوينات ، exclus) ؛ إرجاع تكوينات. toarray (سلسلة جديدة [configurations.size ()]) ؛ } catch (ioException ex) {refl new alficalstateException (ex) ؛ }} isenabled boolean المحمي (التعليق التوضيحي metadata) {return true ؛ } /** * إرجاع {link encontationAttributes} المناسبة} من * {link annotationmetadata}. بشكل افتراضي ، ستُرجع هذه الطريقة سمات * {link #getannotationclass ()}. * param metadata metadata التعليقات التوضيحية * سمات التعليق التوضيحية */ التعليقات التوضيحية المحمية getAttributes (التعليق التوضيحي metadata) {string name = getAnnotationClass (). getName () ؛ anotationattributes سمات = التعليقات التوضيحية. Assert.notnull (السمات ، "لا توجد سمات تكوين تلقائي موجودة." + metadata.getClassName () + "مشروح مع" + classutils.getShortName (name) + "؟") ؛ سمات العودة. } /*** إرجاع فئة شرح المصدر المستخدم من قبل المحدد. * return فئة التعليقات التوضيحية */ الفئة المحمية <؟> getAnnotationClass () {return eniTaLeAutoconFiguration.class ؛ } /*** إرجاع أسماء فئة التكوين التلقائي التي يجب مراعاتها. بشكل افتراضي * ، ستعمل هذه الطريقة على تحميل المرشحين باستخدام {link SpringFactoriesLoader} مع * {link #GetSpringFactoriesLoaderFactoryClass ()}. * param metadata المصدر metadata * param يعزى {link #getattributes (enrotationMetadata) annotation * entributes} * @REGAN SpringFactoriesLoader.LoadFactoryNames (getSpringFactoriesLoaderFactoryClass () ، getBeanClassLoader ()) ؛ Assert.Notempty (التكوينات ، "لا توجد فئات تكوين تلقائية موجودة في meta-inf/spring.factories. إذا كنت تستخدم" + "عبوة مخصصة ، فتأكد من أن الملف صحيح.") ؛ إرجاع تكوينات ؛ } /** * إرجاع الفئة المستخدمة بواسطة {link SpringFactoriesLoader} لتحميل التكوين * المرشحين. * regurn فئة المصنع */ الفئة المحمية <؟> getSpringFactoriesLoaderFactoryClass () {return enableeautoconfiguration.class ؛ } private void checkexcludedclasses (قائمة <Tring> التكوينات ، تعيين <string> exclus) {list <string> invalidexCludes = new ArrayList <String> (asscripions.size ()) ؛ لـ (String Exclus: exclus) {if (classUtils.ispresent (assact ، getClass (). getClassLoader ()) &&! configurations.contains (assact)) {invalidexCludes.add (assact) ؛ }} if (! invalidexCludes.isempty ()) {geneyInvalidexCludes (invalidexCludes) ؛ }} /*** التعامل مع أي استبعاد غير صالح تم تحديده. * param invalidexCludes قائمة الاستبعاد غير الصالح (سيكون لها دائمًا عنصر واحد * على الأقل) */ void handleinvalidexcludes (قائمة <Tring> invalidexCludes) {StringBuilder Message = new StringBuilder () ؛ لـ (string asscs: invalidexcludes) {message.append ("/t-") .Append (exclude) .Append (string.format ("٪ n")) ؛ } رمي جديد غير aluallstateException (سلسلة. } /*** إرجاع أي استثناءات تحد من تكوينات المرشح. * param metadata المصدر metadata * param يعزى {link #getattributes (annotationMetadata) annotation * entributes} * @return أو مجموعة فارغة */ مجموعة محمية <Tring> getExClusions (annotationmetada metadata ، innotationattribute) LinkedHashset <string> () ؛ expluded.addall (aslist (سمات ، "Exclude")) ؛ reveded.addall (arrays.aslist (attributes.getStringArray ("excludename"))) ؛ reveded.addall (getExCludeaUtoconFigurationSproperty ()) ؛ عائد مستبعد. } قائمة خاصة <Tring> getExCludeaUtoconFigurationSproperty () {if (getEnvironment () مثيل للتكوين القابلة للتكوين) {RelaftPropertyResolver Resolver = new ReliefPropertyResolver (this.envirial ، "spring.autoconfigure.") ؛ خريطة <سلسلة ، كائن> خصائص = resolver.getSubProperties ("Exclude") ؛ if (properties.isempty ()) {return collections.emptylist () ؛ } قائمة <Tring> excludes = new ArrayList <String> () ؛ لـ (map.entry <string ، Object> entry: properties.entryset ()) {string name = entral.getKey () ؛ قيمة الكائن = interptvalue () ؛ if (name.isempty () || name.startswith ("[[" }} يستبعد الإرجاع ؛ } RelaxedPropertyResolver Resolver = New RelaxedPropertyResolver (GetEnvironment () ، "Spring.AutoconFigure.") ؛ string [] exclude = resolver.getProperty ("Exclude" ، string []. class) ؛ return (arrays.aslist (exclude == null؟ new string [0]: explude)) ؛ } القائمة الخاصة <string> sort (قائمة <Tring> تكوينات ، autoConfigurationMetAdata autoConfigurationMetAdata) يلقي ioException {configurations = autoConFigurationSorter (getMetAdataReaderFactory () ، autoConfigurationMetAdata) .getInpriority (configurations) ؛ إرجاع تكوينات ؛ } قائمة خاصة <string> تصفية (قائمة <Tring> التكوينات ، autoConfigurationMetAdata autoConfigurationMetAdata) {long startTime = system.nanotime () ؛ string [] Coygulates = configurations.toarray (سلسلة جديدة [configurations.size ()]) ؛ Boolean [] Skip = New Boolean [Conversity.Length] ؛ تخطي منطقية = خطأ ؛ لـ (autoConfigurationImportFilter filter: getAutoconFigurationImportFilters ()) {invokeawaremethods (filter) ؛ Boolean [] match = filter.match (المرشحين ، autoConfigurationMetAdata) ؛ لـ (int i = 0 ؛ i <match.length ؛ i ++) {if (! match [i]) {skip [i] = true ؛ تخطي = صحيح ؛ }}}} إذا (! تخطي) {إرجاع تكوينات ؛ } قائمة <String> result = new ArrayList <String> (Canneridates.Length) ؛ من أجل (int i = 0 ؛ i <canliSidates.Length ؛ i ++) {if (! skip [i]) {result.add (المرشحين [i]) ؛ }} if (logger.istraceenabled ()) {int numberfiltered = configurations.size () - result.size () ؛ logger.trace ("fultled" + numberFiltered + "Configuration Auto Class في" + timeUnit.nanoseconds.tomillis (system.nanotime () - startTime) + "MS") ؛ } إرجاع ArrayList جديد <string> (النتيجة) ؛ } القائمة المحمية <AutoConFigurationImportFilter> getAutoconFigurationImportFilters () {return SpringFactoriesLoader.LoadFactories (AutoConfigurationImportFilter.class ، this.beanclassloader) ؛ } metadatareaderfactory getMetAdataReaderFactory () {try {return getBeanfactory (). getBean (shareMetAdatAdatArfactoryContextInitializer.bean_name ، metadatareaderfactory.class) ؛ } catch (nosuchbeanDefinitionException ex) {return new CachingMetAdatAreaderFactory (this.resourceloader) ؛ }} النهائي المحمي <T> القائمة <T> removeDuplicates (قائمة <T> قائمة) {return new ArrayList <T> (New LinkedHashset <T> (list)) ؛ } القائمة النهائية المحمية <String> aslist (incenotationAttributes entributes ، اسم السلسلة) {string [] value = attributes.getStringArray (name) ؛ إرجاع صفائف. } private void fireautoconFigurationImportevents (قائمة <Tring> التكوينات ، تعيين <string> exclusions) {List <UtoconFigurationImportListener> المستمعين = getautoconfigurationimportlisteners () ؛ if (! leaders.isempty ()) {AutoConFigurationImportEvent event = new AutoConfigurationImportEvent (هذا ، التكوينات ، exclusions) ؛ لـ (AutoConFigurationImportListener المستمع: المستمعين) {invokeawaremethods (مستمع) ؛ مستمع. }}} قائمة محمية <AutoConFigurationImPortListener> getAutoconFigurationImportListeners () {return SpringFactoriesLoader.loadFactories (AutoConFigurationImportListener.class ، this.beanclassloader) ؛ } private void vokeawaremethods (مثيل الكائن) {if (مثيل enchare arke) {if (مثيل beanclasslostloaderaware) {(beanclassloaderaware) مثيل) .setBeanClasslassloader (this.beanclassloader) ؛ } if (مثيل exateof beanfactoryaware) {((beanfactoryaware) مثيل) .setBeanFactory (this.beanfactory) ؛ } if (مثيل exateof eversionaware) {((البيئة) مثيل). } if (مثيل exateof resourceLoaderAware) {((resourceLoaderaware) مثيل) .setResourCeloader (this.resourceloader) ؛ }}} Override public void setBeanfactory (beanfactory beanfactory) يلقي beansexception {assert.isinstanceof (configuraBlistableBeanfactory.class ، beanfactory) ؛ this.beanfactory = (configurableListableBeanfactory) beanfactory ؛ } محمية نهائية configurablEstableBeanfactory getBeanfactory () {return this.beanfactory ؛ } Override public void setBeanClassLoader (classloader classloader) {this.beanclassloader = classLoader ؛ } classloader المحمية getBeanClassloader () {return this.beanclassloader ؛ } Override public void setenvironment (بيئة البيئة) {this.environment = البيئة ؛ } البيئة النهائية المحمية getEnvironment () {return this.environment ؛ } Override public void setResourcelOader (ResourceLoader ResourceLoader) {this.resourceloader = resourceLoader ؛ } المحمي الموارد النهائية getResourceloader () {return this.resourceloader ؛ } Override public int getorder () {return order.lowest_precedence - 1 ؛ }}أولاً ، تنفذ هذه الفئة واجهة مؤجلات apperredimportselector ، والتي ترث المستورد:
/ * * حقوق الطبع والنشر 2002-2013 المؤلف أو المؤلفين الأصليين. * * مرخصة بموجب ترخيص Apache ، الإصدار 2.0 ("الترخيص") ؛ * لا يجوز لك استخدام هذا الملف إلا في الامتثال للترخيص. * يمكنك الحصول على نسخة من الترخيص على * * http://www.apache.org/licenses/license-2.0 * * ما لم يكن مطلوبًا بموجب القانون المعمول به أو يتم الاتفاق عليه في الكتابة ، يتم توزيع البرمجيات * الموزعة بموجب الترخيص على أساس "كما هو" ، * دون ضمانات أو شروط من أي نوع ، إما صريحة أو ضمنية. * راجع ترخيص الأذونات اللغوية المحددة والقيود * بموجب الترخيص. */package org.springframework.context.annotation ؛ استيراد org.springframework.core.type.annotationMetAdata ؛/** * الواجهة التي يجب تنفيذها بواسطة أنواع تحدد @{ @ @link} * class (es) على أساس معيار اختيار معين ، وعادة ما يتم تحديده. * * <p> يجوز لـ {link expressselector} تنفيذ أي مما يلي * {link org.springframework.beans.factory.aware arke} ، وسيتم استدعاء أساليبها * قبل {link #selectimports}: * البيئة} </li> * <li> {@link org.springframework.beans.factory.beanfactoryaware beanfactoryawar org.springframework.context.resourceloaderaware resourceLoaderAware} </li> * </ul> * <p> عادة ما تتم معالجة الاستيرادات عادةً بنفس الطريقة التي يتم بها معالجة {@code}} {exed} {ens}. DeferRedImportselector} * للحصول على التفاصيل). * * Author Chris Beams * since 3.1 * seee efferredimportselector * seee import * seee importBeanDefinitionRegistrar * seee configuration * /public interface ephurtelector { /** * select and return يجب استيرادها من الفئة (es) */ string [] SelectImports (annotationMetadata ImportingClassMetadata) ؛}تُستخدم هذه الواجهة بشكل أساسي لاستيراد عناصر تكوين التكوين @، ويعتبر مؤجلات eDredImportselector استيراد مؤجل ، وسيتم تنفيذه فقط بعد معالجة جميع عمليات التكسير.
دعنا نلقي نظرة على طريقة SelectImport لـ AutoConfigurationImportselector:
Override public string [] SelectImports (annotationMetadata annotationMetAdata) {if (! isEnabled (annotationMetadata)) {return no_imports ؛ } جرب {autoconfigurationMetAdata autoconFigurationMetAdata = autoConfigurationMetAdataloader .LoadMetAdata (this.beanclassloader) ؛ esentationAttributes سمات = getAttributes (annotationMetadata) ؛ قائمة <Tring> التكوينات = getCandidateConfigurations (enconotationMetadata ، السمات) ؛ التكوينات = إزالتها (تكوينات) ؛ التكوينات = الفرز (التكوينات ، autoConfigurationMetAdata) ؛ تعيين <string> excclusions = getExClusions (annotationMetadata ، السمات) ؛ checkexcludedclasses (التكوينات ، exclus) ؛ configurations.removeall (استثناءات) ؛ التكوينات = التصفية (التكوينات ، autoConfigurationMetAdata) ؛ FireautoconFigurationImportevents (التكوينات ، الإثبات) ؛ إرجاع تكوينات. toarray (سلسلة جديدة [configurations.size ()]) ؛ } catch (ioException ex) {refl new alficalstateException (ex) ؛ }}
في البداية ، ستحدد هذه الطريقة أولاً ما إذا كان سيتم إجراء التجميع التلقائي ، ثم قراءة الخصائص ذات الصلة من البيانات الوصفية والبيانات الوصفية من meta-inf/spring-autoconfigure-metadata.properties ، ثم استدعاء طريقة getCandidateConfigurations:
/*** إرجاع أسماء فئة التكوين التلقائي التي يجب مراعاتها. بشكل افتراضي * ، ستعمل هذه الطريقة على تحميل المرشحين باستخدام {link SpringFactoriesLoader} مع * {link #GetSpringFactoriesLoaderFactoryClass ()}. * param metadata المصدر metadata * param يعزى {link #getattributes (enrotationMetAdata) annotation * entributes} * return قائمة بتكوينات المرشح */ قائمة المحمية <Tring> getCandIdateConfigurations (ennotationmetadata metadata ، SpringFactoriesLoader.LoadFactoryNames (getSpringFactoriesLoaderFactoryClass () ، getBeanClassLoader ()) ؛ Assert.Notempty (التكوينات ، "لا توجد فئات تكوين تلقائية موجودة في meta-inf/spring.factories. إذا كنت تستخدم" + "عبوة مخصصة ، فتأكد من أن الملف صحيح.") ؛ إرجاع تكوينات ؛ } /** * إرجاع الفئة المستخدمة بواسطة {link SpringFactoriesLoader} لتحميل التكوين * المرشحين. * regurn فئة المصنع */ الفئة المحمية <؟> getSpringFactoriesLoaderFactoryClass () {return enableeautoconfiguration.class ؛ }لقد قابلت هنا معارفنا القديم - springfactoryiesloader ، الذي سيقرأ تكوين تكوين التمكين تحت meta -inf/spring.factories ، ثم تنفيذ الاستبعاد والتصفية للحصول على الفصل الذي يجب تجميعه. أخيرًا ، دع جميع AutoConfigurationImportListener تم تكوينه ضمن meta-inf/spring.factories تنفيذ حدث autoConfigurationImportevent ، الرمز كما يلي:
private void fireautoconfigurationImportevents (قائمة <Tring> التكوينات ، تعيين <string> exclusions) {list <UtoConFigurationImportListener> المستمعين = getAutoconFigurationImportListeners () ؛ if (! leaders.isempty ()) {AutoConFigurationImportEvent event = new AutoConfigurationImportEvent (هذا ، التكوينات ، exclusions) ؛ لـ (AutoConFigurationImportListener المستمع: المستمعين) {invokeawaremethods (مستمع) ؛ مستمع. }}} قائمة محمية <AutoConFigurationImPortListener> getAutoconFigurationImportListeners () {return SpringFactoriesLoader.loadFactories (AutoConFigurationImportListener.class ، this.beanclassloader) ؛ }في الرابط السابق ، نحتاج فقط إلى تحديد الفئات التي يجب تجميعها ، ومتى ستتم معالجة هذه الفئات التي تم تجميعها تلقائيًا في Springboot؟ دعونا نحلله بإيجاز:
2.1. تحديث طريقة التجريدية applicationContext:
هذه الطريقة هي كليشيهات. يرجى الانتباه إلى هذه الطريقة:
// استدعاء معالجات المصنع المسجلة كفاصوليا في السياق. InvokebeanfactoryPostProcessors (Beanfactory) ؛
فيما يلي عملية BeanFactoryPostProcessor ، لذلك دعونا نلقي نظرة على هذه الواجهة BeanDefinitionregistryPostProcessor:
/ * * حقوق الطبع والنشر 2002-2010 المؤلف أو المؤلفين الأصليين. * * مرخصة بموجب ترخيص Apache ، الإصدار 2.0 ("الترخيص") ؛ * لا يجوز لك استخدام هذا الملف إلا في الامتثال للترخيص. * يمكنك الحصول على نسخة من الترخيص على * * http://www.apache.org/licenses/license-2.0 * * ما لم يكن مطلوبًا بموجب القانون المعمول به أو يتم الاتفاق عليه في الكتابة ، يتم توزيع البرمجيات * الموزعة بموجب الترخيص على أساس "كما هو" ، * دون ضمانات أو شروط من أي نوع ، إما صريحة أو ضمنية. * راجع ترخيص الأذونات اللغوية المحددة والقيود * بموجب الترخيص. */package org.springframework.beans.factory.support;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanFactoryPostProcessor;/** * Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for * the registration of further bean definitions <i>before</i> regular * BeanFactoryPostProcessor detection kicks in. In particular, * BeanDefinitionRegistryPostProcessor may register further bean definitions * which in turn define BeanFactoryPostProcessor instances. * * @author Juergen Hoeller * @since 3.0.1 * @see org.springframework.context.annotation.ConfigurationClassPostProcessor */public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor { /** * Modify the application context's internal bean definition registration after its * standard initialization. All regular bean definitions will have been loaded, * but no beans will have been instantiated yet. This allows for adding further * bean definitions before the next post-processing phase kicks in. * @param registry the bean definition registry used by the application context * @throws org.springframework.beans.BeansException in case of errors */ void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;}该接口继承了BeanFactoryPostProcessor。
2.2. ConfigurationClassPostProcessor class
该类主要处理@Configuration注解的,它实现了BeanDefinitionRegistryPostProcessor, 那么也间接实现了BeanFactoryPostProcessor,关键代码如下:
@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { int factoryId = System.identityHashCode(beanFactory); if (this.factoriesPostProcessed.contains(factoryId)) { throw new IllegalStateException( "postProcessBeanFactory already called on this post-processor against " + beanFactory); } this.factoriesPostProcessed.add(factoryId); if (!this.registriesPostProcessed.contains(factoryId)) { // BeanDefinitionRegistryPostProcessor hook apparently not supported... // Simply call processConfigurationClasses lazily at this point then. processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory); } enhanceConfigurationClasses(beanFactory); beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory)); }/** * Build and validate a configuration model based on the registry of * {@link Configuration} classes. */ public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { //.....省略部分代码// Parse each @Configuration class ConfigurationClassParser parser = new ConfigurationClassParser( this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry); Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates); Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size()); do { parser.parse(candidates); parser.validate(); Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses()); configClasses.removeAll(alreadyParsed); // Read the model and create bean definitions based on its content if (this.reader == null) { this.reader = new ConfigurationClassBeanDefinitionReader( registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry()); } this.reader.loadBeanDefinitions(configClasses); alreadyParsed.addAll(configClasses); candidates.clear(); if (registry.getBeanDefinitionCount() > candidateNames.length) { String[] newCandidateNames = registry.getBeanDefinitionNames(); Set<String> oldCandidateNames = new HashSet<String>(Arrays.asList(candidateNames)); Set<String> alreadyParsedClasses = new HashSet<String>(); for (ConfigurationClass configurationClass : alreadyParsed) { alreadyParsedClasses.add(configurationClass.getMetadata().getClassName()); } for (String candidateName : newCandidateNames) { if (!oldCandidateNames.contains(candidateName)) { BeanDefinition bd = registry.getBeanDefinition(candidateName); if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) { candidates.add(new BeanDefinitionHolder(bd, candidateName)); } } } candidateNames = newCandidateNames; } } while (!candidates.isEmpty()); // ....省略部分代码}其实这里注释已经很清楚了,我们可以清楚的看到解析每一个@ConfigurationClass的关键类是:ConfigurationClassParser,那么我们继续看一看这个类的parse方法:
public void parse(Set<BeanDefinitionHolder> configCandidates) { this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>(); for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { if (bd instanceof AnnotatedBeanDefinition) { parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } processDeferredImportSelectors(); }在这里大家留意一下最后一句processDeferredImportSelectors方法,在这里将会对DeferredImportSelector进行处理,这样我们就和AutoConfigurationSelectImporter结合到一起了:
private void processDeferredImportSelectors() { List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors; this.deferredImportSelectors = null; Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR); for (DeferredImportSelectorHolder deferredImport : deferredImports) { ConfigurationClass configClass = deferredImport.getConfigurationClass(); try { String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata()); processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); }}}请大家关注这句代码:String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());在这里deferredImport的类型为DeferredImportSelectorHolder:
private static class DeferredImportSelectorHolder { private final ConfigurationClass configurationClass; private final DeferredImportSelector importSelector; public DeferredImportSelectorHolder(ConfigurationClass configClass, DeferredImportSelector selector) { this.configurationClass = configClass; this.importSelector = selector; } public ConfigurationClass getConfigurationClass() { return this.configurationClass; } public DeferredImportSelector getImportSelector() { return this.importSelector; }}在这个内部类里持有了一个DeferredImportSelector的引用,至此将会执行自动装配的所有操作
1)自动装配还是利用了SpringFactoriesLoader来加载META-INF/spring.factoires文件里所有配置的EnableAutoConfgruation,它会经过exclude和filter等操作,最终确定要装配的类
2) 处理@Configuration的核心还是ConfigurationClassPostProcessor,这个类实现了BeanFactoryPostProcessor, 因此当AbstractApplicationContext执行refresh方法里的invokeBeanFactoryPostProcessors(beanFactory)方法时会执行自动装配
The above is the automatic assembly in SpringBoot introduced to you by the editor. آمل أن يكون ذلك مفيدًا لك. If you have any questions, please leave me a message and the editor will reply to you in time!