Die automatische Montage von Springboot ist die Grundlage für das Unboxing und die Voraussetzung für Mikrodienste. Das Hauptthema ist diesmal darin, zu sehen, wie es implementiert wird. Wir verwenden den Quellcode, um die Vor- und Nachteile der automatischen Montage zu erfassen.
1.1. Über @springbootApplication
Wenn wir ein Springboot -Projekt schreiben, ist @springbootApplication die häufigste Annotation. Wir können uns den Quellcode ansehen:
/ * * Copyright 2012-2017 Der ursprüngliche Autor oder die Autoren. * * Lizenziert unter der Apache -Lizenz, Version 2.0 (die "Lizenz"); * Sie dürfen diese Datei nur in Übereinstimmung mit der Lizenz verwenden. * Sie können eine Kopie der Lizenz unter * * http://www.apache.org/licenses/license-2.0 * * * *, sofern nach geltendem Recht oder schriftlich gefordert oder schriftlich gefordert wird, Software *, die im Rahmen der Lizenz verteilt ist, auf "As "basis * ohne Gewährleistungen oder Bedingungen jeglicher Art verteilt oder implementiert. * Siehe die Lizenz für die spezifischen Sprachregierungsberechtigungen und * Einschränkungen im Rahmen der Lizenz. */Paket org.springframework.boot.autoconfigure; import Java.lang.annotation java.lang.annotation.target; import org.springframework.boot.springbootConfiguration; import org.springframework.boot.context.typexcludeFilter; org.springframework.context.annotation.comPonentscan.filter; import org.springFramework.context.annotation.Configuration; Das deklariert ein oder mehrere * {@link bean @bean} Methoden und löst auch {@link EnableAutoConfiguration * automatisch-Konfiguration} und {@link componentscan-Komponenten Scannen} aus. Dies ist eine Komfort * Annotation, die der Deklaration {@Code @Configuration}, * {@code @enableAutoConfiguration} und {@Code @Componentscan} entspricht. * * @Author Phillip Webb * @Author Stephane Nicoll * @Since 1.2.0 */@target (elementtype.type) @retention (retentionPolicy.runtime)@documented@erben@SpringbootConfiguration@EnableAutoConfiguration@componentscan (excludeFilters = | @Filters (@Filters @Filters @Filter) (Typ = | {{@{{{{{{{{{{| TypexcludeFilter.class), @filter (type = filterType.custom, classes = autoconfigurationExcludeFilter.class)}) public @Interface SpringbootApplication { /*** SPEKTIVE Kauto-Konfigurationsklassen, die niemals angewendet werden. * @return die Klassen, die ausgeschlossen werden sollen */ @aliasfor (Annotation = EnableAutoConfiguration.class, Attribute = "exklude") Class <?> [] exklude () Standard {}; /** * Ausschließen spezifische Auto-Konfigurationsklassennamen, so dass sie niemals angewendet werden. * @return die Klassennamen, um auszuschließen * @Since 1.3.0 */ @aliasfor (Annotation = EnableAutoConfiguration.class, Attribute = "exkludeName") String [] excludename () Standard {}; /*** Basispakete zum Scannen nach kommentierten Komponenten. Verwenden Sie {@link #ScanBasepackageClasses} * für eine Typ-Safe-Alternative zu String-basierten Paketnamen. * @return Basispakete zum Scannen * @Since 1.3.0 */ @aliasfor (Annotation = componentscan.class, Attribute = "Basepackages") String [] scanBasepackages () Standard {}; /** * Typ-safe Alternative zu {@link #ScanBasepackages} zum Angeben der Pakete zu * Scan nach kommentierten Komponenten. Das Paket jeder angegebenen Klasse wird gescannt. * <p> * Erwägen Sie, in jedem Paket eine spezielle No-Op-Marker-Klasse oder -Rinformace zu erstellen, die * keinen anderen Zweck erfüllt, als von diesem Attribut verwiesen zu werden. * @return Basispakete zum Scannen * @Since 1.3.0 */ @aliasfor (Annotation = componentscan.class, Attribute = "BasepackageClasses") Klasse <?> [] ScanBasepackageClasses () Standard {};}Dies enthält @springbootConfiguration, @enableAutoConfiguration, @Componentscan. Da hier kein Scan -Paket angegeben ist, scannt es alle Klassen unter der gleichen Ebene wie die Klasse oder das gleiche Level -Paket standardmäßig. Darüber hinaus finden Sie @springbootConfiguration über den Quellcode, dass es sich um eine @Configuration handelt:
/ * * Copyright 2012-2016 Der ursprüngliche Autor oder die Autoren. * * Lizenziert unter der Apache -Lizenz, Version 2.0 (die "Lizenz"); * Sie dürfen diese Datei nur in Übereinstimmung mit der Lizenz verwenden. * Sie können eine Kopie der Lizenz unter * * http://www.apache.org/licenses/license-2.0 * * * *, sofern nach geltendem Recht oder schriftlich gefordert oder schriftlich gefordert wird, Software *, die im Rahmen der Lizenz verteilt ist, auf "As "basis * ohne Gewährleistungen oder Bedingungen jeglicher Art verteilt oder implementiert. * Siehe die Lizenz für die spezifischen Sprachregierungsberechtigungen und * Einschränkungen im Rahmen der Lizenz. */Paket org.springframework.boot; import Java.lang.annotation.documented; Import Java.lang.Annotation.Elementtype; Import Java.Lang.annotation.Retention; org.springFramework.context.annotation.Configuration;/** * Zeigt an, dass eine Klasse Spring -Boot -Anwendung enthält * {@link configuration @Configuration}. Kann als Alternative zur Federes * Standard {@Code @Configuration} Annotation verwendet werden, damit die Konfiguration automatisch gefunden werden kann (z. B. in Tests). * <p> * Die Anwendung sollte immer nur <em> ein </em> {@code @springbootConfiguration} und * Die meisten idiomatischen Spring -Startanwendungen erben. * * @Author Phillip Webb * @Since 1.4.0 */@target (elementtype.type) @retention (retentionPolicy.Runtime)@documented@configurationPublic @Interface SpringbootConfiguration {}Daraus können wir schließen, dass @springbootApplication @Configuration @Componentscan @enableAutoConfiguration entspricht
1.2. @EnableAutoConfiguration
Sobald diese Annotation hinzugefügt wurde, wird die automatische Montagefunktion aktiviert. Einfach ausgedrückt wird der Frühling versucht, alle konfigurierten Bohnen unter Ihrem Klassenpfad zu finden und sie dann zusammenzustellen. Natürlich wird sie beim Zusammenbau einer Bohne gemäß mehreren (bedingten) Anpassungsregeln initialisiert. Schauen wir uns den Quellcode an:
/ * * Copyright 2012-2017 Der ursprüngliche Autor oder die Autoren. * * Lizenziert unter der Apache -Lizenz, Version 2.0 (die "Lizenz"); * Sie dürfen diese Datei nur in Übereinstimmung mit der Lizenz verwenden. * Sie können eine Kopie der Lizenz unter * * http://www.apache.org/licenses/license-2.0 * * * *, sofern nach geltendem Recht oder schriftlich gefordert oder schriftlich gefordert wird, Software *, die im Rahmen der Lizenz verteilt ist, auf "As "basis * ohne Gewährleistungen oder Bedingungen jeglicher Art verteilt oder implementiert. * Siehe die Lizenz für die spezifischen Sprachregierungsberechtigungen und * Einschränkungen im Rahmen der Lizenz. */Paket org.springframework.boot.autoconfigure; import Java.lang.annotation java.lang.annotation.target; import org.springframework.boot.autoconfigure.condition.conditionalonbean; org.springframework.boot.autoconfigure.condition.conditionalonmissingbean; import org.springframework.boot.context.embedded.embeddedServletContainerFactory; org.springframework.context.annotation.Conditional; import org.springFramework.context.annotation.Configuration; import org.springframework.context.Annotation.import; Versuch, Bohnen zu erraten und zu konfigurieren, die Sie wahrscheinlich benötigen. Auto-Konfigurationsklassen werden normalerweise * angewendet, basierend auf Ihrem Klassenpfad und den Bohnen, die Sie definiert haben. Wenn Sie beispielsweise {@Code tomcat-embedded.jar} auf Ihrem Klassenpfad haben, möchten Sie wahrscheinlich einen * {@link tomcatembeddedServletContainerFactory} (es sei denn, Sie haben Ihre eigene * {@link eingebetteteservletContainerFactory} bean definiert). * <p> * Bei Verwendung {@link SpringbootApplication} ist die automatische Konfiguration des Kontextes * automatisch aktiviert, und das Hinzufügen dieser Annotation hat daher keinen zusätzlichen Effekt. * <p> * Auto-Configuration versucht, so intelligent wie möglich zu sein und wird zurückgehalten, wenn Sie mehr von Ihrer eigenen Konfiguration definieren. Sie können immer manuell {@link #Exclude ()} jede Konfiguration, die Sie nie anwenden möchten (verwenden Sie {@link #Excludename ()}, wenn Sie nicht * Zugriff auf sie haben). Sie können sie auch über die Eigenschaft * {@code spring.autoconfigure.Exclude} ausschließen. Auto-Konfiguration wird immer angewendet. * Nachdem benutzerdefinierte Bohnen registriert wurden. * <p> * Das Paket der Klasse, das mit {@code @enableAutoConfiguration} kommentiert wird, * normalerweise über {@Code @springbootApplication}, hat eine spezifische Bedeutung und wird häufig als 'Standard' verwendet. Zum Beispiel wird es beim Scannen nach {@code @Entity} -Klasse verwendet. * Es wird allgemein empfohlen, dass Sie {@code @enableAutoConfiguration} (wenn Sie * nicht {@code @SpringbootApplication} verwenden) in einem Stammpaket platzieren, damit alle Unterpackungen * und Klassen durchsucht werden können. * <p> * Auto-Configuration-Klassen sind reguläre Spring {@link-Konfiguration} Beans. Sie befinden sich * mit dem Mechanismus {@link SpringFactoriesloader} (gegen diese Klasse). * Im Allgemeinen sind automatische Konfigurationsbohnen {@link Conditional @Conditional} Beans (meistens * häufig {@link ConditionalonClass @conditionalonClass} und * {@link Conditionalonmissingbean @Conditionalonmissingbean} Annotationen). * * @Author Phillip Webb * @Author Stephane Nicoll * @see Conditionalonbean * @see Conditionalonmissingbean * @see ConditionalOnClass * @see Autoconfigure * @see SpringbootApplication */@SuppressWarnings("deprecation")@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(EnableAutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "Spring.boot.EnableAutoconfiguration"; /*** Ausschließen spezifische Auto-Konfigurationsklassen, so dass sie niemals angewendet werden. * @return die Klassen, die ausgeschlossen werden sollen */ class <?> [] exclude () default {}; /** * Ausschließen spezifische Auto-Konfigurationsklassennamen, so dass sie niemals angewendet werden. * @return die Klassennamen zu ausschließen * @Since 1.3.0 */ string [] excludeName () Standard {};}Obwohl die Dokumentationskommentare hervorgeht, führt es uns zu EnableAutoConfigurationImportSelector. Die Klasse ist jedoch in der Version von Springboot1.5.x veraltet. Schauen wir uns also die AutoconfigurationImportSelector der Elternklasse an:
/ * * Copyright 2012-2017 Der ursprüngliche Autor oder die Autoren. * * Lizenziert unter der Apache -Lizenz, Version 2.0 (die "Lizenz"); * Sie dürfen diese Datei nur in Übereinstimmung mit der Lizenz verwenden. * Sie können eine Kopie der Lizenz unter * * http://www.apache.org/licenses/license-2.0 * * * *, sofern nach geltendem Recht oder schriftlich gefordert oder schriftlich gefordert wird, Software *, die im Rahmen der Lizenz verteilt ist, auf "As "basis * ohne Gewährleistungen oder Bedingungen jeglicher Art verteilt oder implementiert. * Siehe die Lizenz für die spezifischen Sprachberechtigungen und * Einschränkungen im Rahmen der Lizenz. */Paket org.springframework.boot.autoconfigure; import Java.io.ioException; import Java.util.ArrayList; Import Java.util.Arrays; Import Java.util.Collections; Import Java.util.hashset; java.util.map; import Java.util.set; import Java.util.concurrent.TimeUnit; org.springframework.beans.factory.beanClassloaderaware; import org.springframework.bean.factory.beanfactory; import org.springFramework.bean.factory.beanFactoryAware; Import org. organ. org.springframework.context.annotation.DeferredimportSelector; import org.springframework.core.Orded; org.springframework.core.env.environment; import org.springframework.core.io.resourceloader; import org.springframework.core.io.support.springfactoriesloader; org.springframework.core.type.classReading.cachingMetAdatAraderFactory; import org.springframework.core.type.ClassReading.metadatAreaderfactory; import org.springframework.util. org.springFramework.util.StringUtils;/** * {@link DeferredImportSelector}, um {@link EnableAutoConfiguration * automatisch-Konfiguration} zu handhaben. Diese Klasse kann auch unterklassifiziert werden, wenn eine benutzerdefinierte Variante von * {@link EnableAutoConfiguration @enableAutoConfiguration}}. ist benötigt. * * @Author Phillip Webb * @Author Andy Wilkinson * @Author Stephane Nicoll * @Author Madhura Bhave * @Since 1.3.0 * @see EnableAutoConfiguration */öffentliche Klasse AutokonfigurationImportselector Deferredimportlector, BeancladerAware, BeancladerAware, BeancladerAware, BeancladerAware, Ressourcen -Class -Ladera -, - Bestellt {private statische endgültige String [] no_imports = {}; private statische endgültige log -logger = logFactory .getLog (AutoconfigurationImportSelector.Class); private configurablelistableBeanFactory Beanfactory; privates Umfeld; private Classloader BeanClassloader; Private Resourceloader Resourceloader; @Override public String [] selektimports (AnnotationMetadata AnnotationMetadata) {if (! ISenabled (AnnotationMetadata)) {return no_imports; } try {autoconfigurationMetadata autoconfigurationMetadata = autoconfigurationMetadataloader .loadMetAdata (this.beanClassloader); AnnotationAttributes Attribute = getAtTributes (AnnotationMetadata); List <String> configurations = getCandidateConfigurations (AnnotationMetadata, Attribute); configurations = remedUplicates (Konfigurationen); configurations = sort (configurations, autoconfigurationmetadata); Set <string> exclusions = getExclusions (AnnotationMetadata, Attribute); checkexcludedClasses (Konfigurationen, exklus); configurations.removeall (Ausschlüsse); configurations = filter (configurations, autoconfigurationmetadata); fireAutoconfigurationImaPents (Konfigurationen, exklus); return configurations.toArray (neue String [configurations.size ()]); } catch (ioException ex) {werfen Sie neue IllegalStateException (Ex); }} Protected Boolean isenabled (AnnotationMetadata metadata) {return true; } /** * Gibt die entsprechende {@link AnnotationAttributes} aus dem * {@link AnnotationMetadata} zurück. Standardmäßig gibt diese Methode Attribute für * {@link #getAnnotationClass ()} zurück. * @param metadata Die Annotationsmetadaten * @return Annotation Attribute */ Protected AnnotationAttributes getAtTributes (AnnotationMetadata metadata) {String name = getAnnotationClass (). getName (); AnnotationAttributes Attribute = AnnotationAttributes .Frommap (metadata.getAnnotationAttributes (Name, true)); Assert.notnull (Attribute, "Keine automatischen Konfigurationsattribute gefunden. IS" + metadata.getClassName () + "Annotiert mit" + clasutils.getShortName (Name) + "?"); Rückgabeattribute; } /*** Geben Sie die vom Selektor verwendete Quellanschlagsklasse zurück. * @return die Annotationsklasse */ Protected Class <?> getAnnotationClass () {return EnableAutoConfiguration.class; } /*** Geben Sie die Namen der automatischen Konfigurationsklassen zurück, die berücksichtigt werden sollten. Standardmäßig * lädt diese Methode Kandidaten mit {@link SpringFactoriesloader} mit * {@link #getSpringFactorysloaderFactoryClass ()}. * @param metadata the source metadata * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation * attributes} * @return a list of candidate configurations */ protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoresloader.loadfactoryNames (GetSPringFactoresOladerFactoryClass (), getBeanClassloader ()); Assert.notEmpty (Konfigurationen, "Keine Autokonfigurationsklassen in meta-inf/fing.factores. Wenn Sie" + "eine benutzerdefinierte Verpackung verwenden, stellen Sie sicher, dass die Datei korrekt ist."). Rückgabekonfigurationen; } /** * Gibt die von {@link Springfactoresloader} verwendete Klasse zurück, um die Konfiguration zu laden * Kandidaten. * @return die Werksklasse */ Protected Class <?> GetSpringFactoriesloaderFactoryClass () {return EnableAutoConfiguration.class; } private void CheckkexCludedClasses (Liste <String> Konfigurationen, set <string> exklus) {list <string> Invalidexcludes = new ArrayList <string> (exklusions.size ()); für (String exclus: exclus) {if (clasutils.ispresent (Ausschluss, getClass (). getClassLoader ()) &&! configurations.contains (Ausschluss)) {IngareSxcludes.add (Ausschluss); }} if (! InvalidExcludes.isempty ()) {HandleInvalidexcludes (Invalidexcludes); }} /*** Behandeln Sie alle angegebenen ungültigen Ausschlüsse. * @param invalidexcludes Die Liste der ungültigen Ausschlüsse (hat immer mindestens ein * Element) */ Protected void HandleInvalidexcludes (List <String> InvalidExCludes) {StringBuilder Message = new StringBuilder (); für (String Exclude: Invalidexcludes) {message.Append ("/t-") .Append (ausschließen) .Append (string.format ("%n")); } neue IllegalStateException werfen (String .Format ("Die folgenden Klassen konnten nicht ausgeschlossen werden, weil sie" + "nicht automatisch konfigurieren:%n%s", Nachricht)); } /*** Geben Sie alle Ausschlüsse zurück, die die Kandidatenkonfigurationen einschränken. * @param metadata Die Quellmetadaten * @param ordnungsgemäß Die {@link #getAtTributes (AnnotationMetadata) Annotation * Attribute} * @return exclusions oder ein leerer Satz */ Protected Set <string> getExclusions (AnnotationMetAdaTa metadata, Annotationattributes) {set <stringmetaDaData, New -Strash -Attributs) {{set <strichs ausschließend. ausgeschlossen.addall (ASLIST (Attribute, "ausschließen")); ausgeschlossen.addall (arrays.aSlist (Attribute.getStringArray ("ausschließend"))); ausgeschlossen.addall (getExcludeAutoconfigurationsProperty ()); Rückgabe ausgeschlossen; } private list <string> getExcludeAutoconfigurationsProperty () {if (Getenvironment () Instanz der Konfigurationsumwelt) {entspanntePropertyresolver Resolver = new Relpa. Map <string, Object> properties = resolver.getSubproperties ("ausschließt"); if (Properties.isempty ()) {return Collectionss.EmptyList (); } List <string> excludes = new ArrayList <string> (); für (map.entry <String, Objekt> Eintrag: Properties.EntrySet ()) {String name = Eintrag.getKey (); Object value = Eintrag.getValue (); if (name.isempty () || name.startsWith ("[") && value! }} return ausschließt; } EntspanntePropertyresolver Resolver = neuer entspanntesPropertyresolver (Getenvironment (), "Spring.autoconfigure"); String [] exclude = resolver.getProperty ("exklude", String []. Klasse); return (arrays.aSlist (exklude == null? New String [0]: exklude)); } private Liste <string> sortieren (Liste <string> Konfigurationen, AutoconfigurationMetadata AutoconfigurationMetadata) löst IOException aus {configurations = new Autoconfigurationsorter (getMetAdatAreArtory (), AutoconfigurationMetadata). Rückgabekonfigurationen; } private list <string> filter (list <string> Konfigurationen, AutoconfigurationMetadata AutoconfigurationMetadata) {Long startTime = System.nanotime (); String [] candidates = configurations.toArray (neue String [configurations.size ()]); boolean [] slip = new boolean [kandidaten.length]; boolean übersprungen = false; für (AutoconfigurationImportFilter -Filter: GetAutoConfigurationImportFilters ()) {invokeAwaremethods (Filter); boolean [] match = filter.match (Kandidaten, AutoconfigurationMetadata); für (int i = 0; i <match.length; i ++) {if (! Match [i]) {überspringen [i] = true; übersprungen = wahr; }}}} if (! übersprungen) {return configurations; } List <string> result = new ArrayList <string> (candidaten.length); für (int i = 0; i <candidaten.length; i ++) {if (! überspringen [i]) {result.add (Kandidaten [i]); }} if (logger.istaceEnabled ()) {int numberFiltered = configurations.size () - result.size (); logger.trace ("filtred" + numberFiltered + "Auto -Konfigurationsklasse in" + TimeUnit.nanoseconds.tomillis (System.Nanotime () - StartTime) + "MS"); } NeuarrayList <string> (Ergebnis) zurückgeben; } Protected List <AutoConfigurationImportFilter> getAutoConfigurationImportFilters () {return SpringFactorysloader.loadfactores (AutoConfigurationImportFilter.class, this.beanclassloader); } private metadaDatAraderFactory getMetAdaDaReAderFactory () {try {return getBeAnfactory (). getBean (SharedMetAdatAraderFactoryContextInitializer.bean_Name, metadatareAeArfactory.class); } catch (NoSuchbeandeFinitionException ex) {return New CachingMetAdatAraderFactory (this.resourceloader); }} geschützte endgültige <T> List <T> Remeduplicates (Liste <T> Liste) {Neue ArrayList <T> zurückgeben (neu LinkedHashset <T> (Liste)); } geschützte endgültige Liste <string> ASList (AnnotationAtTributes -Attribute, String -Name) {String [] value = Attribute.getStringArray (Name); return arrays.aslist (value == null? Neue Zeichenfolge [0]: Wert); } private void fireAutoconfigurationImaPortEvents (Liste <string> Konfigurationen, set <string> excclusions) {list <AutoConfigurationImportListener> listener = getAutoConfigurationImaMportListener (); if (! hörer für (AutoconfigurationImaPortListener -Listener: Hörer) {invokeAwaremethods (Hörer); Hörer. }}} Protected List <AutoConfigurationImportListener> getAutoConfigurationImportListener () {return Springfactsloader.loadfactores (AutoConfigurationImportListener.Class, this.beanClassloader); } private void invokeAwaremethods (Objektinstanz) {if (Instance InstanceOf AWARE) {if (Instanzinstanz beanclassloaderaware) {((BeanClassloaderaware) Instanz) .setBeanClassloader (this.beanClassloader); } if (Instanzinstanz von BeanFactoryAWare) {((beanfactoryAware). } if (Instanzinstanz von EnvironmentAware) {((EnvironmentAware) Instanz). } if (Instanzinstanz von ResourceloaderAWare) {((ressourcenoaderAware). }}} @Override public void setbeanfactory (beanfactory beanfactory) löst beansexception {assert.issinstanceof (configurablelistableBeanFactory.class, beanfactory) aus; this.beanfactory = (configurablelistableBeanFactory) beanfactory; } geschützte endgültige configurableListableBeArtory getBeanFactory () {return this.beanFactory; } @Override public void setBeanClassloader (classloader classloader) {this.beanClassloader = classloader; } Protected Classloader getBeanClassLoader () {return this.beanClassloader; } @Override public void setEnvironment (Umweltumgebung) {this.Environment = Umgebung; } geschützte endgültige Umgebung Getenvironment () {return this. -Environment; } @Override public void setResourceloader (Resourceloader Resourceloader) {this.resourceloader = Resourceloader; } Protected Final Resourceloader getResourceloader () {return this.resourceloader; } @Override public int getOrder () {return ordned.lowest_precedence - 1; }}Zunächst implementiert diese Klasse die referedimportSelector -Schnittstelle, die den ImportSelector erbt:
/ * * Copyright 2002-2013 Der ursprüngliche Autor oder Autoren. * * Lizenziert unter der Apache -Lizenz, Version 2.0 (die "Lizenz"); * Sie dürfen diese Datei nur in Übereinstimmung mit der Lizenz verwenden. * Sie können eine Kopie der Lizenz unter * * http://www.apache.org/licenses/license-2.0 * * * *, sofern nach geltendem Recht oder schriftlich gefordert oder schriftlich gefordert wird, Software *, die im Rahmen der Lizenz verteilt ist, auf "As "basis * ohne Gewährleistungen oder Bedingungen jeglicher Art verteilt oder implementiert. * Siehe die Lizenz für die spezifischen Sprachberechtigungen und * Einschränkungen im Rahmen der Lizenz. */Paket org.springFramework.context.annotation; import org.springframework.core.type.annotationMetadata;/** * Schnittstelle, die nach Typen implementiert werden soll, die bestimmen, die @{ @link -Konfiguration} * Klasse (ES) importiert werden sollten, basierend auf einer bestimmten Auswahlkriterien, normalerweise ein oder mehr oder mehr oder mehr oder mehr oder mehr oder mehr oder mehr oder mehr oder mehr oder mehr oder mehr oder mehr oder mehr Attributen. * * <p> Ein {@link importSelector} kann die folgenden * {@link org.springFramework.bean.factory.Aware aware} Schnittstellen implementieren, und ihre jeweiligen * Methoden werden vor {@link #Selectimports}: * <ul> * <li> {@@@@link.sping.spramework.Contework.Contework. EnvironmentAware}</li> * <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}</li> * <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}</li> * <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}</li> * </ul> * <p>ImportSelectors are usually processed in the same way as regular {@code @Import} * annotations, however, it is also possible to defer selection of imports until all * {@code @Configuration} classes have been processed (see {@link DeferredImportSelector} * für Einzelheiten). * * @Author Chris Beams * @Since 3.1 * @see DeferredImportSelector * @see import * @see ImportbeandeFinitionRegistrar * @see configuration * /public interface ImportSelector { /** * SELECT Die Namen der Klasse (ES) sollten basierend auf der { @ @ @@link -AnnotationMetation importiert werden. */ String [] selectImports (AnnotationMetadata ImportingClassMetadata);}Diese Schnittstelle wird hauptsächlich zum Importieren der Konfigurationselemente von @Configuration verwendet, und DeferredImportSelector ist ein aufgeschobener Import und wird erst ausgeführt, nachdem alle @Configurations verarbeitet wurden.
Werfen wir einen Blick auf die SelectImport -Methode der AutoconfigurationImportSelector:
@Override public String [] selektimports (AnnotationMetadata AnnotationMetadata) {if (! ISenabled (AnnotationMetadata)) {return no_imports; } try {autoconfigurationMetadata autoconfigurationMetadata = autoconfigurationMetadataloader .loadMetAdata (this.beanClassloader); AnnotationAttributes Attribute = getAtTributes (AnnotationMetadata); List <String> configurations = getCandidateConfigurations (AnnotationMetadata, Attribute); configurations = remedUplicates (Konfigurationen); configurations = sort (configurations, autoconfigurationmetadata); Set <String> excclusions = getExclusions (AnnotationMetadata, Attribute); checkexcludedClasses (Konfigurationen, exklus); configurations.removeall (Ausschlüsse); configurations = filter (configurations, autoconfigurationmetadata); fireAutoconfigurationImaPents (Konfigurationen, Excclusionen); return configurations.toArray (neue String [configurations.size ()]); } catch (ioException ex) {werfen Sie neue IllegalStateException (Ex); }}
Zu Beginn bestimmt diese Methode zuerst, ob automatische Montage durchgeführt werden soll, und lesen dann die relevanten Eigenschaften von Metadaten und Metadaten von Meta-inf/Spring-Autoconfigure-Metadata.Properties und rufen Sie dann die Methode GetCandidatEconfigurations auf:
/*** Geben Sie die Namen der automatischen Konfigurationsklassen zurück, die berücksichtigt werden sollten. Standardmäßig * lädt diese Methode Kandidaten mit {@link SpringFactoriesloader} mit * {@link #getSpringFactorysloaderFactoryClass ()}. * @param metadata the source metadata * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation * attributes} * @return a list of candidate configurations */ protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoresloader.loadfactoryNames (GetSPringFactoresOladerFactoryClass (), getBeanClassloader ()); Assert.notEmpty (Konfigurationen, "Keine Autokonfigurationsklassen in meta-inf/fing.factores. Wenn Sie" + "eine benutzerdefinierte Verpackung verwenden, stellen Sie sicher, dass die Datei korrekt ist."). Rückgabekonfigurationen; } /** * Gibt die von {@link Springfactoresloader} verwendete Klasse zurück, um die Konfiguration zu laden * Kandidaten. * @return die Werksklasse */ Protected Class <?> GetSpringFactoriesloaderFactoryClass () {return EnableAutoConfiguration.class; }Hier traf ich unseren alten Bekannten - SpringFactoryiesloader, der die Konfiguration von EnableAutoConfiguration unter meta -inf/fing.factores lautet und dann Ausschluss und Filterung durchführt, um die Klasse zu erhalten, die zusammengestellt werden muss. Lassen Sie alle AutoconfigurationImportListener, die unter meta-inf/spring konfiguriert sind. FACTORES. Führen Sie das AutoConfigurationImPorpent-Ereignis aus, der Code lautet wie folgt:
private void fireAutoconfigurationImaPortEvents (Liste <string> Konfigurationen, Set <String> Excclusions) {Liste <AutoConfigurationImportListener> Hörer = getAutoConfigurationImaMportListener (); if (! hörer für (AutoconfigurationImaPortListener -Listener: Hörer) {invokeAwaremethods (Hörer); Hörer. }}} Protected List <AutoConfigurationImportListener> getAutoConfigurationImportListener () {return Springfactsloader.loadfactores (AutoConfigurationImportListener.Class, this.beanClassloader); }Im vorherigen Link müssen wir nur feststellen, welche Klassen zusammengestellt werden müssen, und wann werden diese automatisch zusammengestellten Klassen im Springboot verarbeitet? Lassen Sie es uns kurz analysieren:
2.1. Aktualisierungsmethode der AbstractApplicationContext:
Diese Methode ist ein Klischee. Bitte achten Sie auf diese Methode:
// in den Kontext als Bohnen eingerichtet auf Fabrikprozessoren aufzurufen. InvokeBeArfactoryPostProcessors (Beanfactory);
Hier ist der Prozess des BeanfactoryPostProcessors. Schauen wir uns also diese Schnittstelle an.
/ * * Copyright 2002-2010 Der ursprüngliche Autor oder Autoren. * * Lizenziert unter der Apache -Lizenz, Version 2.0 (die "Lizenz"); * Sie dürfen diese Datei nur in Übereinstimmung mit der Lizenz verwenden. * Sie können eine Kopie der Lizenz unter * * http://www.apache.org/licenses/license-2.0 * * * *, sofern nach geltendem Recht oder schriftlich gefordert oder schriftlich gefordert wird, Software *, die im Rahmen der Lizenz verteilt ist, auf "As "basis * ohne Gewährleistungen oder Bedingungen jeglicher Art verteilt oder implementiert. * Siehe die Lizenz für die spezifischen Sprachberechtigungen und * Einschränkungen im Rahmen der Lizenz. */Paket org.springframework.beans.factory.Support; import org.springframework.beans.beansexception; import org.springframework 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. Ich hoffe, es wird Ihnen hilfreich sein. Wenn Sie Fragen haben, hinterlassen Sie mir bitte eine Nachricht und der Editor wird Ihnen rechtzeitig antworten!