L'assemblage automatique de Springboot est la base du déballage et de la condition préalable aux microservices. Le sujet principal cette fois est de voir comment il est mis en œuvre. Nous utilisons le code source pour saisir les tenants et aboutissants de l'assemblage automatique.
1.1. À propos de @springbootapplication
Lorsque nous écrivons le projet Springboot, @SpringBootApplication est l'annotation la plus courante. Nous pouvons jeter un œil au code source:
/ * * Copyright 2012-2017 L'auteur ou les auteurs originaux. * * Licencié sous la licence Apache, version 2.0 (la "licence"); * Vous ne pouvez pas utiliser ce fichier sauf conforme à la licence. * Vous pouvez obtenir une copie de la licence à * * http://www.apache.org/licenses/license-2.0 * * sauf si la loi applicable ou convenu par écrit, le logiciel * distribué sous la licence est distribué sur une base "en tant que", * sans garantie ou conditions de toute nature, exprimée ou impliquée. * Voir la licence pour les autorisations de gouvernance linguistique spécifiques et les * limitations sous la licence. * / package org.springframework.boot.autoconfigure; import java.lang.annotation.documented; import java.lang.annotation.elementType; import java.lang.annotation.inherite java.lang.annotation.target; import org.springframework.boot.springbootconfiguration; import org.springframework.boot.context.typeexcludFilter; import org.springframework.context.annotation.bean; import org.springframework.context.annotation..ponentscan; org.springframework.context.annotation.componentscan.filter; import org.springframework.context.annotation.configuration; import org.springframework.context.annotation.filterType; déclare une ou plusieurs * {@link bean @bean} et déclenche également {@link perteAutoConfiguration * Auto-Configuration} et {@Link ComponentsCan Component Scanning}. Il s'agit d'une annotation de commodité * qui équivaut à déclarer {@code @configuration}, * {@code @enableAutoConfiguration} et {@code @componentscan}. * * @Author Phillip Webb * @author Stephane Nicoll * @Since 1.2.0 * / @ Target (elementType.Type) @retention (RetenderPolicy.Runtime) @ documenté @ Hérité @ SpringbootConfiguration @ @FulautoConfiguration @ componentsCan, Classes = {@filter (Type = Filtertype, Classic TypeExCludFilter.class), @Filter (Type = filterType.Custom, Classes = AutoConfigurationExcludFilter.Class)}) public @Interface SpringbootApplication {/ ** * Exclure des classes de configuration automatique spécifiques telles qu'ils ne seront jamais appliqués. * @return les classes pour exclure * / @aliasfor (annotation = perteAutoConfiguration.class, attribut = "excluaire") classe <?> [] excluaire () par défaut {}; / ** * Exclure des noms de classe de configuration automatique spécifiques de sorte qu'ils ne seront jamais * appliqués. * @return les noms de classe pour exclure * @Since 1.3.0 * / @aliasfor (annotation = perteAutoConfiguration.class, attribut = "excludeName") string [] excludeName () default {}; / ** * Packages de base pour rechercher des composants annotés. Utilisez {@Link #ScanBasEpackageClasses} * pour une alternative de type type aux noms de packages basés sur des chaînes. * @return Packages de base pour scan * @Since 1.3.0 * / @aliasfor (annotation = ComponentsCan.class, attribut = "basepackages") String [] ScanBasePackages () default {}; / ** * Alternative de type type à {@Link #ScanBasePackages} pour spécifier les packages pour * scanner des composants annotés. Le package de chaque classe spécifiée sera analysé. * <p> * Envisagez de créer une classe ou une interface de marqueur sans opération spécial dans chaque package qui * ne sert à rien d'autre que d'être référencé par cet attribut. * @return Packages de base pour scan * @Since 1.3.0 * / @aliasfor (annotation = ComponentsCan.class, attribut = "BasEpackageClasses") Class <?> [] ScanBasePackageClasses () Default {};}Cela contient @springbootconfiguration, @enableAutoConfiguration, @componentscan. Ici, comme il n'y a pas de package de numérisation spécifié, il analyse toutes les classes dans le même niveau que la classe ou le même package de niveau par défaut. De plus, @springbootconfiguration, vous pouvez découvrir via le code source qu'il s'agit d'un @configuration:
/ * * Copyright 2012-2016 L'auteur ou les auteurs originaux. * * Licencié sous la licence Apache, version 2.0 (la "licence"); * Vous ne pouvez pas utiliser ce fichier sauf conforme à la licence. * Vous pouvez obtenir une copie de la licence à * * http://www.apache.org/licenses/license-2.0 * * sauf si la loi applicable ou convenu par écrit, le logiciel * distribué sous la licence est distribué sur une base "en tant que", * sans garantie ou conditions de toute nature, exprimée ou impliquée. * Voir la licence pour les autorisations de gouvernance linguistique spécifiques et les * limitations sous la licence. * / package org.springframework.boot; import java.lang.annotation.documented; import java.lang.annotation.elementType; import java.lang.annotation.retention; import java.lang.annotation.retentionpolicy; import java.lang.annotation.target; importation; importation; org.springframework.context.annotation.configuration; / ** * indique qu'une classe fournit une application de démarrage Spring * {@link configuration @configuration}. Peut être utilisé comme alternative à l'annotation standard du Spring * standard {@code @configuration} afin que la configuration puisse être trouvée * automatiquement (par exemple dans les tests). * <p> * L'application ne devrait jamais inclure <em> une </em> {@code @springbootconfiguration} et * la plupart des applications de démarrage de ressort idiomatiques l'hériteront de * {@code @springbootapplication}. * * @author phillip webb * @Since 1.4.0 * / @ Target (elementType.type) @retention (retenderPolicy.runtime) @ documenté @ configurationPublic @Interface SpringbootConfiguration {}À partir de cela, nous pouvons en déduire que @springbootapplication est équivalent à @configuration @componentscan @enableAutoConfiguration
1.2. @EnableAutoConfiguration
Une fois cette annotation ajoutée, la fonction d'assemblage automatique sera activée. Pour le dire simplement, Spring essaiera de trouver tous les haricots configurés sous votre chemin de classe, puis de les assembler. Bien sûr, lors de l'assemblage d'un haricot, il sera initialisé en fonction de plusieurs règles de personnalisation (conditionnelle). Jetons un coup d'œil à son code source:
/ * * Copyright 2012-2017 L'auteur ou les auteurs originaux. * * Licencié sous la licence Apache, version 2.0 (la "licence"); * Vous ne pouvez pas utiliser ce fichier sauf conforme à la licence. * Vous pouvez obtenir une copie de la licence à * * http://www.apache.org/licenses/license-2.0 * * sauf si la loi applicable ou convenu par écrit, le logiciel * distribué sous la licence est distribué sur une base "en tant que", * sans garantie ou conditions de toute nature, exprimée ou impliquée. * Voir la licence pour les autorisations de gouvernance linguistique spécifiques et les * limitations sous la licence. * / package org.springframework.boot.autoconfigure; import java.lang.annotation.documented; import java.lang.annotation.elementType; import java.lang.annotation.inherite java.lang.annotation.target; import org.springframework.boot.autoconfigure.condition.conditionalonbean; import org.springframework.boot.autoconfigure.condition.conditionalbean; org.springframework.boot.autoconfigure.condition.conditionalonMissingBean; import org.springframework.boot.context.embedded.embeddedServletContainerFactory; Import org.springframework.boot.context.embedded.tomcat.tomcatembeddedServletContainerFactory; import org.springframework.context.annotation.conditional; org.springframework.core.io.support.springfactoriesloader; / ** * activer la configuration automatique du contexte de l'application Spring, en essayant de deviner et * configurer les beans dont vous avez probablement besoin. Les classes de configuration automatique sont généralement * appliquées en fonction de votre chemin de classe et des haricots que vous avez définis. Par exemple, si vous * avez {@code tomcat-embedded.jar} sur votre CLASSPATH, vous voudrez probablement un * {@Link TomCatembedDeservletContainerFactory} (sauf si vous avez défini votre propre * {@link EmbedDedServletContainerFactory} Bean). * <p> * Lorsque vous utilisez {@Link SpringbootApplication}, la configuration automatique du contexte est * automatiquement activée et l'ajout de cette annotation n'a donc pas d'effet supplémentaire. * <p> * La configuration automatique essaie d'être aussi intelligente que possible et se feras en arrière que vous * définissez davantage votre propre configuration. Vous pouvez toujours manuellement {@Link #ExClude ()} toute configuration * que vous ne souhaitez jamais appliquer (utilisez {@Link #ExCludeName ()} si vous n'en avez pas * accès). Vous pouvez également les exclure via la propriété * {@code spring.autoconfigure.exclude}. La configuration automatique est toujours appliquée * après l'enregistrement des haricots définis par l'utilisateur. * <p> * Le package de la classe qui est annoté avec {@code @enableAutoConfiguration}, * généralement via {@code @springbootapplication}, a une signification spécifique et est souvent utilisé * comme «par défaut». Par exemple, il sera utilisé lors de la numérisation des classes {@code @entity}. * Il est généralement recommandé de placer {@code @enableAutoConfiguration} (si vous n'utilisez pas {@code @springbootapplication}) dans un package racine afin que tous les sous-packages * et les classes puissent être recherchés. * <p> * Les classes de configuration automatique sont régulières Spring {@Link Configuration} Beans. Ils sont * situés à l'aide du mécanisme {@link springfactoriesloader} (clés contre cette classe). * Généralement, les beans de configuration automatique sont {@Link Conditional @conditional} Beans (la plupart * utilisant souvent {@Link ConditionalOnClass @ConditionalOnClass} et * {@Link ConditionalOnMissingBean @conditionalonMissingBean} annotations). notre * / @ Suppresswarnings ("dépréciation") @ target (elementType.type) @retention (retentionPolicy.runtime) @ documented @ hérité @ autoconfigurationpackage @ import (activeAutoConfigurationImportSellect "printemps.boot.enableAutoconfiguration"; / ** * Exclure des classes de configuration automatique spécifiques de sorte qu'elles ne seront jamais appliquées. * @return les classes pour exclure * / class <?> [] excluaire () par défaut {}; / ** * Exclure des noms de classe de configuration automatique spécifiques de sorte qu'ils ne seront jamais * appliqués. * @return les noms de classe pour exclure * @Since 1.3.0 * / String [] excludeName () par défaut {};}Bien que, selon les commentaires de la documentation, il nous guide de voir l'activation de l'Import-Sortie. Mais la classe est obsolète dans la version Springboot1.5.x, alors jetons un œil à sa classe parent autoconfigurationImportSelector:
/ * * Copyright 2012-2017 L'auteur ou les auteurs originaux. * * Licencié sous la licence Apache, version 2.0 (la "licence"); * Vous ne pouvez pas utiliser ce fichier sauf conforme à la licence. * Vous pouvez obtenir une copie de la licence à * * http://www.apache.org/licenses/license-2.0 * * sauf si la loi applicable ou convenu par écrit, le logiciel * distribué sous la licence est distribué sur une base "en tant que", * sans garantie ou conditions de toute nature, exprimée ou impliquée. * Voir la licence pour la langue spécifique régissant les autorisations et les * limitations sous la licence. * / package org.springframework.boot.autoconfigure; import java.io.ioexception; import java.util.arraylist; import java.util.arrays; import java.util.linkections java.util.map; importer java.util.set; import java.util.concurrent.timeunit; import org.apache.commons.logging.log; import org.apache.commons.logging.logfactory; import org.springframework.beans.Beansxception; Import Org.springFrameworwwork.bean.beansexception; Import Org.spring org.springframework.beans.factory.beanclassloadheraware; import org.springframework.beans.factory.beanfactory; import org.springframework.beans.factory.beanfactoryaware; org.springframework.beans.factory.config.configurableLlistableBeanfactory; import org.springframework.boot.bind.relaxedpropertyResolver; import org.springframework.context.environmentaware; import org.springframework.context.resourceLaderware; org.springframework.context.annotation.deferredimportSelector; import org.springframework.core.ordered; import org. org.springframework.core.io.resourceloader; import org.springframework.core.io.support.springfactoriesloader; import org.springframework.core.type.annotationMetadata; import org.springframework.core.type.classreding.cachingMetaDeraDerfact org.springframework.core.type.classReading.MetadataReaderFactory; import org.springframework.util.assert; import org.springframework.util.classutils; import org.springframework.util.stringutils; / ** * {@link DeferredImporTelect AutoableAutoConfiguration * Auto-Configuration}. Cette classe peut également être sous-classée si une variante personnalisée de * {@link perteAutoConfiguration @enableAutoConfiguration}. est nécessaire. * * @Author Phillip Webb * @author Andy Wilkinson * @Author Stephane Nicoll * @Author Madhura Bhave * @Since 1.3.0 * @SeE ENABLAUTOCONFIGURATION * / CLASSE PUBLIQUE AUTOCONFIGURATIONIMPORTSELLECTO {chaîne finale statique privée [] NO_IMPORTS = {}; Logger du journal final statique privé = logfactory .getLog (autoconfigurationImportSelector.class); configurableListableBeanFactory Beanfactory; environnement privé; Private Classloader BeanClassloader; ResourceLoader privé ResourceLoader; @Override public String [] selectImports (annotationMetadata annotationMetAdata) {if (! IseNabled (annotationMetadata)) {return no_imports; } essayez {autoconfigurationMetAdata autoconfigurationMetAdata = autoconfigurationMetAdataloder .LoadMetAdata (this.BeANClassloader); ANNOTATATATTRIBUTES Attributs = GetAttributes (AnnotationMetAdata); List <string> configurations = getCanDateConfigurations (annotationMetadata, attributs); configurations = supprimer les uplications (configurations); Configurations = Sort (Configurations, AutoConfigurationMetAdata); Set <string> exclusions = getExclusions (annotationMetadata, attributs); CheckExCludClasses (Configurations, exclus); configurations.removeall (exclusions); configurations = filtre (configurations, autoconfigurationMetAdata); FIREAUTOCONFIGURATIONIMPORTEVENTS (Configurations, exclus); return configurations.toArray (new String [configurations.size ()]); } catch (ioException ex) {lancer un nouveau illégalStateException (ex); }} Boolean Isenabled protégé (Metadata AnnotationMetAdata) {return true; } / ** * Renvoie le {@link annotationAttributes approprié} du * {@link annotationMetadata}. Par défaut, cette méthode renverra les attributs pour * {@link #getannotationclass ()}. * @param métadonnées Les métadonnées d'annotation * @return annotation attributs * / annotationAttributes protected getAttributes (annotationMetadata Metadata) {String name = getAntationClass (). getName (); AnnotationAtTributes Attributes = annotationAtTributes .Frommap (metadata.getannotationAtButes (name, true)); Assert.notnull (attributs, "Aucun attribution automatique de configuration trouvée. IS" + metadata.getClassName () + "Annotated avec" + classutils.getShortName (name) + "?"); attributs de retour; } / ** * Renvoie la classe d'annotation source utilisée par le sélecteur. * @return la classe d'annotation * / classe protégé <?> getAnnotationClass () {return perteAutoConfiguration.class; } / ** * Renvoyez les noms de classe de configuration automatique qui doivent être pris en considération. Par défaut * Cette méthode chargera les candidats à l'aide de {@Link SpringFactoriesLoader} avec * {@link #getsPringFactoriesLoDerFactoryClass ()}. * @param métadonnées Les métadonnées source * @param attribuent les {@link #getAttributes (annotationmetadata) annotation * attributs} * @return une liste des configurations candidates * / liste protégée <chaîne SpringFactoriesLoader.LoadFactoryNames (getSpringFactoriesLoDerFactoryClass (), getBeAclassloader ()); Assert.notempty (Configurations, "Aucune classe de configuration automatique trouvée dans Meta-inf / Spring.factories. Si vous" + "utilisez un emballage personnalisé, assurez-vous que le fichier est correct."); configurations de retour; } / ** * Renvoie la classe utilisée par {@link springfactoriesloader} pour charger la configuration * candidats. * @return la classe d'usine * / classe protégée <?> GetSpringFactoriesLoDerFactoryClass () {return perteAutoConfiguration.class; } private void checkExCludClassmes (list <string> configurations, set <string> exclus) {list <string> invalidexcludes = new ArrayList <string> (exclusions.size ()); for (String exclus: excluse) {if (classutils.ispresent (exclusion, getClass (). getClassLoader ()) &&! ConfigUrations.Contains (exclusion)) {invalidexcludes.add (exclusion); }} if (! invalidexCludes.iSempty ()) {handleInvalidexCludes (invalidexCludes); }} / ** * gérer toutes les exclusions non valides qui ont été spécifiées. * @param invalidexcluds la liste des exclusions non valides (aura toujours au moins un * élément) * / protégé vide handleInvalidexCludes (list <string> invalidexcludes) {stringBuilder message = new StringBuilder (); for (String exclure: invalidexcludes) {message.append ("/ t-") .append (exclude) .append (string.format ("% n")); } Jetez une nouvelle illégalStateException (String .Format ("Les classes suivantes n'ont pas pu être exclues car ce sont" + "pas des classes de configuration automatique:% n% s", message)); } / ** * Renvoie toutes les exclusions qui limitent les configurations candidates. * @Param Metadata Les métadonnées source * @param attribuent les {@link #getAttributes (annotationMetAdata) Annotation * Attributes} * @return exclusions ou un ensemble vide * / Protected Set <string> getExclusions (AnnotationMetadata Metadata, annotationatTRites LinkedHashSet <string> (); exclud.addall (aslist (attributs, "exclure")); exclud.addall (arrays.aslist (attributs.getStringArray ("excludeName"))); exclu.Addall (getExCludAautOConfigurationsProperty ()); retour exclu; } Liste privée <string> getExCluseAutoConFigurationsProperty () {if (getenvironment () instance de configurableenvironment) {relladPropertyResolver Resolver = new relongPropertyResolver (this.environment, "Spring.AutoConfigure."); Map <string, object> properties = résolver.getSubProperties ("exclure"); if (properties.isempty ()) {return Collection.EmptyList (); } List <string> exclut = new ArrayList <string> (); for (map.entry <string, objet> entrée: propriétés.EntrySet ()) {String name = entry.getKey (); Valeur objet = entrée.getValue (); if (name.isempty () || name.startswith ("[") && value! = null) {excluds.addall (new hashset <string> (arrays.aslist (stringUtils .TokenizetoStringArray (string.valueof (value), ",")))); }} Retour exclut; } Resolver relaxedPropertyResolver = new RelaxEdPropertyResolver (Getenvironment (), "printemps.autoconfigure."); String [] exclude = résolver.getProperty ("exclure", String []. Classe); return (arrays.aslist (exclure == null? new String [0]: excluant)); } Liste privée <string> Trie (Liste <string> Configurations, AutoConfigurationMetAdata AutoConfigurationMetAdata) lève IOException {configUrations = new AutoConfigurationsTorter (GetmetAdataReaderFactory (), autoconfigurationMetAdata) .getInPrirityOrder (Configurations); configurations de retour; } Private List <string> Filter (list <string> Configurations, AutoConfigurationMetAdata AutoConfigurationMetAdata) {Long StartTime = System.NanoTime (); String [] candidates = configUrations.toArray (new String [configUrations.size ()]); Boolean [] skip = new Boolean [candidats.length]; booléen sauté = false; pour (AutoConfigurationImportFilter Filter: GetAutoConfigurationImportFilters ()) {invokeAwareMethods (filtre); Boolean [] match = filter.match (candidats, autoconfigurationMetAdata); for (int i = 0; i <match.length; i ++) {if (! Match [i]) {skip [i] = true; sauté = true; }}}} if (! sauté) {return Configurations; } List <string> result = new ArrayList <string> (candidats.length); for (int i = 0; i <candidats.length; i ++) {if (! skip [i]) {result.add (candidats [i]); }} if (logger.istraceenabled ()) {int Logger.Trace ("Filtrée" + Numberfiltered + "Classe de configuration automatique dans" + timeunit.nanoseconds.tomillis (System.NanoTime () - StartTime) + "MS"); } return new ArrayList <string> (résultat); } Liste protégé <autoConfigurationImportFilter> getAutoConFigurationImportFilters () {return SpringFactoriesLoader.LoadFactories (AutoConfigurationImportFilter.class, this.BeANClassloader); } Private MetadataReaderFactory GetMetAdataReaderFactory () {try {return getBeanFactory (). Getbean (SharedMetAdataReaderFactoryClass); } catch (nosuchBeAnDefinitionException ex) {return new CachingMetAdataReaderFactory (this.resourceLoader); }} Final protégé <T> List <T> supprime lesUpLiques (liste <T> List) {return new ArrayList <T> (New LinkedHashSet <T> (liste)); } Final List protégé <string> aslist (annotationAtTributes Attributes, String Name) {String [] value = attributes.getStringArray (name); return arrays.aslist (value == null? new String [0]: value); } private void fireAutoConfigurationImportEvents (list <string> Configurations, set <string> excclusions) {list <autoConfigurationImportListener> auditers = getAutoConfigurationImportLailers (); if (! auditers.isempty ()) {AutoConfigurationImportEvent Event = new AutoConfigurationImportEvent (this, configurations, excclusions); pour (AutoConfigurationImportListener auditeur: écouteurs) {invokeAwareMethods (auditeur); auditeur.onautoconfigurationImportEvent (événement); }}} List protégé <autoConfigurationImportListener> getAutoConFigurationImportListeners () {return springFactoriesLoader.LoadFactories (AutoConfigurationImportListener.class, this.BeANClassloader); } private void invokeAwareMethods (objet instance) {if (instance instanceof down) {if (instance instanceof beanclassloadherAre) {((beanclassloadherare) instance) .setBeANClassLoader (this.beandloader); } if (instance instanceof beanfactoryAware) {((beanfactoryAware) instance) .setBeAnfactory (this.beanfactory); } if (instance instanceof EnvironmentAware) {((EnvironmentAware) instance) .SetEnvironment (this.environment); } if (instance instanceof ResourceLoAderAware) {((ResourceLoaderAware) instance) .setResourceLoader (this.resourceLoader); }}} @Override public void setBeanFactory (beanfactory beanfactory) lève BeanSexception {assert.isinstanceof (configurableListableBeanFactory.class, beanfactory); this.beanfactory = (configurableListableBeanFactory) beanfactory; } Final ConfigurableListableBeAnfactory Protected Final GetBeAnfactory () {return this.beanfactory; } @Override public void setBeANClassloader (classloader classloader) {this.beandlassloader = classloader; } Classloadher protégé getBeANClassLoader () {return this.BeANClassloader; } @Override public void setenvironment (Environment Environment) {this.environment = environnement; } Environnement final protégé Getenvironment () {return this.environment; } @Override public void setResourceLoader (ResourceLoader ResourceLoader) {this.resourceLoader = ResourceLoader; } Final ResourceLoader protégé getResourceLoader () {return this.resourceLoader; } @Override public int getOrder () {return ordonné.lowest_precedence - 1; }}Tout d'abord, cette classe met en œuvre l'interface DeferreDIMPortSelector, qui hérite de l'importSelector:
/ * * Copyright 2002-2013 L'auteur ou les auteurs originaux. * * Licencié sous la licence Apache, version 2.0 (la "licence"); * Vous ne pouvez pas utiliser ce fichier sauf conforme à la licence. * Vous pouvez obtenir une copie de la licence à * * http://www.apache.org/licenses/license-2.0 * * sauf si la loi applicable ou convenu par écrit, le logiciel * distribué sous la licence est distribué sur une base "en tant que", * sans garantie ou conditions de toute nature, exprimée ou impliquée. * Voir la licence pour la langue spécifique régissant les autorisations et les * limitations sous la licence. * / package org.springframework.context.annotation; import org.springframework.core.type.annotationMetadata; / ** * à implémenter par des types qui déterminent quelle classe {@ lien} * Class (ES) doit être importée en fonction d'une critère de sélection donnée, généralement un ou plus * attaque annotation. * * <p> Un {@Link ImportSelector} peut implémenter l'une des interfaces suivantes * {@link org.springframework.beans.factory.Aware Aware}, et leurs méthodes respectives * seront appelées avant de {@link #selectimpports}: * <ul> * <li> {@ link org.springFramework.Contex EnvironmentAware} </li> * <li> {@ link org.springframework.beans.factory.beanfactoryaware beanfactoryAware} </li> * <li> {@ link org.springframework.beans.factory.beanclassloadheraware beanclassloware} </li> * <li> {@ lien org.springframework.context.resourceloaderaware ResourceLoaderaware} </li> * </ul> * <p> Les importateurs sont généralement traités de la même manière que les annotations régulières {@code @import} *, cependant, les classes} ont également été procédés (@Link DeferredImportSelector} * pour plus de détails). * * @Author Chris Beams * @Since 3.1 * @see DeferRediMportSelector * @SeE Import * @SeE ImportBeAndeFinIitiongistrar * @SeE Configuration * / Interface publique ImportSelector {/ ** * Sélectionnez les noms de la classe (ES) devrait être importé en fonction de * la configuration de la classe}. * / String [] selectImports (annotationMetadata importationclassmetadata);}Cette interface est principalement utilisée pour importer les éléments de configuration de @configuration, et DeferredImportSelector est une importation différée, et il ne sera exécuté qu'après le traitement @configurations.
Jetons un coup d'œil à la méthode SelectImport de AutoConfigurationImportSelector:
@Override public String [] selectImports (annotationMetadata annotationMetAdata) {if (! IseNabled (annotationMetadata)) {return no_imports; } essayez {autoconfigurationMetAdata autoconfigurationMetAdata = autoconfigurationMetAdataloder .LoadMetAdata (this.BeANClassloader); ANNOTATATATTRIBUTES Attributs = GetAttributes (AnnotationMetAdata); List <string> configurations = getCanDateConfigurations (annotationMetadata, attributs); configurations = supprimer les uplications (configurations); Configurations = Sort (Configurations, AutoConfigurationMetAdata); Set <string> excclusions = getExclusions (annotationMetadata, attributs); CheckExCludClasses (Configurations, exclus); configurations.removeall (exclusions); configurations = filtre (configurations, autoconfigurationMetAdata); FIREAUTOCONFIGURATIONIMPORTEVENTS (configurations, excclusions); return configurations.toArray (new String [configurations.size ()]); } catch (ioException ex) {lancer un nouveau illégalStateException (ex); }}
Au début, cette méthode déterminera d'abord l'opportunité d'effectuer l'assemblage automatique, puis lira les propriétés pertinentes des métadonnées et des métadonnées de Meta-Inf / Spring-AutoConfigure-Metadata.Properties, puis appelez la méthode GetcandidateConfigurations:
/ ** * Renvoyez les noms de classe de configuration automatique qui doivent être considérés. Par défaut * Cette méthode chargera les candidats à l'aide de {@Link SpringFactoriesLoader} avec * {@link #getsPringFactoriesLoDerFactoryClass ()}. * @param métadonnées Les métadonnées source * @param attribuent les {@link #getAttributes (annotationmetadata) annotation * attributs} * @return une liste des configurations candidates * / liste protégée <chaîne SpringFactoriesLoader.LoadFactoryNames (getSpringFactoriesLoDerFactoryClass (), getBeAclassloader ()); Assert.notempty (Configurations, "Aucune classe de configuration automatique trouvée dans Meta-inf / Spring.factories. Si vous" + "utilisez un emballage personnalisé, assurez-vous que le fichier est correct."); configurations de retour; } / ** * Renvoie la classe utilisée par {@link springfactoriesloader} pour charger la configuration * candidats. * @return la classe d'usine * / classe protégée <?> GetSpringFactoriesLoDerFactoryClass () {return perteAutoConfiguration.class; }Ici, j'ai rencontré notre ancienne connaissance - SpringFactoryiesLoader, qui lira la configuration de l'emballEAutoConfiguration sous Meta-Inf / Spring.factories, puis exécutez l'exclusion et le filtrage pour obtenir la classe qui doit être assemblée. Enfin, laissez toutes les autoconfigurationImportListener configurées sous Meta-Inf / Spring.factories Exécutez l'événement AutoConfigurationImportEvent, le code est le suivant:
private void fireAutoConfigurationImportEvents (list <string> configurations, set <string> excclusions) {list <autoConfigurationImportListener> écouteurs = getAutoConfigurationImportLainers (); if (! auditers.isempty ()) {AutoConfigurationImportEvent Event = new AutoConfigurationImportEvent (this, configurations, excclusions); pour (AutoConfigurationImportListener auditeur: écouteurs) {invokeAwareMethods (auditeur); auditeur.onautoconfigurationImportEvent (événement); }}} List protégé <autoConfigurationImportListener> getAutoConFigurationImportListeners () {return springFactoriesLoader.LoadFactories (AutoConfigurationImportListener.class, this.BeANClassloader); }Dans le lien précédent, nous devons seulement déterminer quelles classes doivent être assemblées et quand ces classes assemblées automatiquement seront-elles traitées dans Springboot? Analysons-le brièvement:
2.1. Rafraîchir la méthode d'AbstractApplicationContext:
Cette méthode est un cliché. Veuillez faire attention à cette méthode:
// Invoquez des processeurs d'usine enregistrés sous forme de haricots dans le contexte. InvokeBeanFactoryPostProcessors (Beanfactory);
Voici le processus de BeanfactoryPostProcessor, alors jetons un coup d'œil à cette interface BeanDefinitionRegistryPostProcessor:
/ * * Copyright 2002-2010 L'auteur ou les auteurs originaux. * * Licencié sous la licence Apache, version 2.0 (la "licence"); * Vous ne pouvez pas utiliser ce fichier sauf conforme à la licence. * Vous pouvez obtenir une copie de la licence à * * http://www.apache.org/licenses/license-2.0 * * sauf si la loi applicable ou convenu par écrit, le logiciel * distribué sous la licence est distribué sur une base "en tant que", * sans garantie ou conditions de toute nature, exprimée ou impliquée. * Voir la licence pour la langue spécifique régissant les autorisations et les * limitations sous la licence. */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 类
该类主要处理@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. J'espère que cela vous sera utile. Si vous avez des questions, laissez-moi un message et l'éditeur vous répondra à temps!