A montagem automática do Springboot é a base para o Unboxing e o pré -requisito para microsserviços. O tópico principal desta vez é ver como é implementado. Utilizamos o código -fonte para entender os detalhes da montagem automática.
1.1. Sobre @springbootApplication
Quando estamos escrevendo o projeto Springboot, o @SpringBootApplication é a anotação mais comum. Podemos dar uma olhada no código -fonte:
/ * * Copyright 2012-2017 O autor original ou autores. * * Licenciado sob a licença Apache, versão 2.0 (a "licença"); * Você não pode usar esse arquivo, exceto em conformidade com a licença. * Você pode obter uma cópia da licença em * * http://www.apache.org/license/license-2.0 * *, a menos que exigido pela lei aplicável ou acordada por escrito, o software * distribuído sob a licença seja distribuído em uma base "como é" *, sem garantia ou condição de qualquer tipo, seja expresso ou implícito. * Consulte a licença para as permissões de governança de idiomas específicas e * limitações sob a licença. */pacote org.springframework.boot.autoconfigure; importar java.lang.annotation.documented; importar java.lang.annotation.ElementType; importação java.lang.annotation.Irited; Immon.Lang.annotation.retEntent; java.lang.annotation.target; importar org.springframework.boot.springbootconfiguration; importar org.springframework.boot.context.typeexcludefilter; import org.springframework.text.tenxtation.bean; importação ou org.springframework.context.annotation.comONENTSCAN.FILTER; importar org.springframework.context.annotation.configuration; importar org.springframework.context.annotation.filtertype; import org.springframework.core.annotation.als.alTation.filtertype; importação; Configuration} classe que declara um ou mais * {@link Bean @bean} Métodos e também aciona {@link enableautoconfiguration * Auto-Configuration} e {@link ComponentsCon Component Digponent}. Esta é uma anotação * que é equivalente a declarar {@code @configuration}, * {@code @enableautoconfiguration} e {@code @componentscan}. * * @author phillip webb * @author stephane nicoll * @since 1.2.0 */@Target (elementType.Type) @retention (retentionPolicy.Runtime)@documentado@herded@shalgherbootconfiguration@enableoToConfiguration@ComponentsCan (excludeFilters = { TypeexcludeFilter.class), @Filter (type = filterType.custom, Classes = AutoConfigurationExcludeFilter.class)}) Public @Interface SpringBootApplication { /*** exclua classes específicas de configuração automática que nunca serão aplicadas. * @RETURN As classes para excluir */ @aliasfor (anotação = enabaAutoconfiguration.class, attribute = "exclude") classe <?> [] exclude () padrão {}; /** * Exclua nomes específicos de classe de configuração automática, de modo que eles nunca sejam * aplicados. * @RETURN Os nomes da classe para excluir * @since 1.3.0 */ @aliasfor (anotação = enabaAutoconfiguration.class, attribute = "excludename") string [] excludename () padrão {}; /*** Pacotes básicos para digitalizar para componentes anotados. Use {@link #scanBasePackageClasses} * para uma alternativa de tipo de tipo para nomes de pacotes baseados em string. * Pacotes de base @return para digitalizar * @since 1.3.0 */ @aliasfor (anotação = componentscan.class, attribute = "bashepackages") string [] scanBasePackages () default {}; /** * alternativa de tipo-tipo a {@link #scanBasePackages} para especificar os pacotes para * digitalizar componentes anotados. O pacote de cada classe especificado será digitalizado. * <p> * Considere a criação de uma classe ou interface especial de marcador não OP em cada pacote que * não serve a não ser referenciado por esse atributo. * Pacotes básicos @return para digitalizar * @since 1.3.0 */ @aliasfor (anotação = componentscan.class, attribute = "bashepackageclasses") classe <?> [] scanBasepackageclasses () default {};}Isso contém @springbootconfiguration, @enableautoconfiguration, @ComponentsCan. Aqui, como não há pacote de varredura especificado, ele digitaliza todas as classes no mesmo nível da classe ou do mesmo pacote de nível por padrão. Além disso, @springbootconfiguration, você pode descobrir através do código -fonte que é uma @configuration:
/ * * Copyright 2012-2016 O autor original ou autores. * * Licenciado sob a licença Apache, versão 2.0 (a "licença"); * Você não pode usar esse arquivo, exceto em conformidade com a licença. * Você pode obter uma cópia da licença em * * http://www.apache.org/license/license-2.0 * *, a menos que exigido pela lei aplicável ou acordada por escrito, o software * distribuído sob a licença seja distribuído em uma base "como é" *, sem garantia ou condição de qualquer tipo, seja expresso ou implícito. * Consulte a licença para as permissões de governança de idiomas específicas e * limitações sob a licença. */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;import org.springframework.context.annotation.configuration;/** * Indica que uma classe fornece um aplicativo de inicialização de primavera * {@link Configuration @configuration}. Pode ser usado como uma alternativa à anotação * padrão * {@code @configuration} para que a configuração possa ser encontrada * automaticamente (por exemplo, nos testes). * <p> * O aplicativo deve incluir apenas <em> um </em> {@code @springbootconfiguration} e * os aplicativos de inicialização da mola mais idiomáticos o herdarão de * {@code @springbootapplication}. * * @author phillip webb * @since 1.4.0 */@Target (ElementType.Type) @retention (retentionPolicy.Runtime)@documentado@ConfigurationPublic @Interface SpringbootConfiguration {}A partir disso, podemos inferir que @springbootApplication é equivalente a @configuration @componentscan @enableautoconfiguration
1.2. @Enableautoconfiguration
Depois que essa anotação for adicionada, a função de montagem automática será ativada. Para simplificar, a primavera tentará encontrar todos os feijões configurados sob o seu caminho de classe e depois montá -los. Obviamente, ao montar um feijão, ele será inicializado de acordo com várias regras (condicionais) de personalização. Vamos dar uma olhada em seu código -fonte:
/ * * Copyright 2012-2017 O autor original ou autores. * * Licenciado sob a licença Apache, versão 2.0 (a "licença"); * Você não pode usar esse arquivo, exceto em conformidade com a licença. * Você pode obter uma cópia da licença em * * http://www.apache.org/license/license-2.0 * *, a menos que exigido pela lei aplicável ou acordada por escrito, o software * distribuído sob a licença seja distribuído em uma base "como é" *, sem garantia ou condição de qualquer tipo, seja expresso ou implícito. * Consulte a licença para as permissões de governança de idiomas específicas e * limitações sob a licença. */pacote org.springframework.boot.autoconfigure; importar java.lang.annotation.documented; importar java.lang.annotation.ElementType; importação java.lang.annotation.Irited; Immon.Lang.annotation.retEntent; java.lang.annotation.target; importar org.springframework.boot.autoconfigure.condition.conditionalonbean; importar org.springframework.boot.autoconfigure.condition.conditiononBean; importação 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.condicional; importar org.springframework.context.annotation.configuration; importação org.springframework.context.annotation.importflestring; significativa; Tentando adivinhar e * configurar feijões que você provavelmente precisará. As classes de configuração automática são geralmente * aplicadas com base no seu caminho de classe e em que feijão você definiu. Por exemplo, se você * tiver {@code tomcat-embited.jar} no seu caminho de classe, provavelmente deseja um * {@link tomcatembeddedservletContainerFactory} (a menos que você tenha definido o seu próprio * {@link incorporadoServletContAnerFactory} Bean). * <p> * Ao usar {@link SpringbootApplication}, a configuração automática do contexto é * ativada automaticamente e a adição dessa anotação, portanto, não tem efeito adicional. * <p> * A configuração automática tenta ser o mais inteligente possível e voltará à medida que você * define mais de sua própria configuração. Você sempre pode manualmente {@link #exclude ()} qualquer * configuração que você nunca deseja aplicar (use {@link #excludename ()} se você não * tem acesso a eles). Você também pode excluí -los através da propriedade * {@code spring.autoconfigure.exclude}. A configuração automática é sempre aplicada * depois que os feijões definidos pelo usuário foram registrados. * <p> * O pacote da classe que é anotado com {@code @enableautoconfiguration}, * geralmente via {@code @springbootapplication}, tem significância específica e é frequentemente usada * como um 'default'. Por exemplo, ele será usado quando digitalizar as classes {@code @entity}. * Geralmente, é recomendável que você coloque {@code @enableautoconfiguration} (se você * não está usando {@code @springbootapplication}) em um pacote root para que todos os sub-pacotes * e classes possam ser pesquisados. * <p> * As classes de configuração automática são mola regular {@link Configuration} Beans. Eles estão * localizados usando o mecanismo {@link SpringFacoriesLoader} (digitado nessa classe). * Geralmente, os feijões de configuração automática são {@link condicional @condicional} beans (a maioria * frequentemente usando {@link condicionalOnclass @conditionalonClass} e * {@link condicionalonMissingBean @conditiononmissingBean} anotações). * * @author phillip webb * @author stephane nicoll * @see condicionalonBean * @see condicionalonMissingBean * @see condicionalonClass * @see AUTOCONFIGUREAFTER * @SEE SpringBoTApplication */@Supressornings ("depreciação")@Target (ElementType.Type) @retention (retentionPolicy.Runtime)@documentado@herded@autoConfigurationPackage@import (enableAtoconfigurationImportSelector.class) public @Interface "spring.boot.enableautoconfiguration"; /*** Exclua classes específicas de configuração automática para que elas nunca sejam aplicadas. * @return as classes para excluir */ class <?> [] exclude () padrão {}; /** * Exclua nomes específicos de classe de configuração automática, de modo que eles nunca sejam * aplicados. * @return os nomes da classe para excluir * @since 1.3.0 */ string [] excludename () padrão {};}Embora, de acordo com os comentários da documentação, ele nos guia para ver o enableautoconfigurationImportSelector. Mas a aula está desatualizada na versão SpringBoot1.5.x, então vamos dar uma olhada em sua classe pai AutoConfigurationImportSelector:
/ * * Copyright 2012-2017 O autor original ou autores. * * Licenciado sob a licença Apache, versão 2.0 (a "licença"); * Você não pode usar esse arquivo, exceto em conformidade com a licença. * Você pode obter uma cópia da licença em * * http://www.apache.org/license/license-2.0 * *, a menos que exigido pela lei aplicável ou acordada por escrito, o software * distribuído sob a licença seja distribuído em uma base "como é" *, sem garantia ou condição de qualquer tipo, seja expresso ou implícito. * Consulte a licença para as permissões e limitações do idioma específico e * sob a licença. */pacote org.springframework.boot.autoconfigure; importar java.io.ioException; importar java.util.ArrayList; importar java.util.arrays; import java.util.Link.Linklections; import java.util.hashset; java.util.map; importar java.util.set; importar java.util.concurrent.timeunit; importar org.apache.commons.logging.log; import org.apache.commons.Logging.LogFactory; import.springFramework.BeanSception; org.springframework.beans.factory.beanclassloadraWare; importar org.springframework.beans.factory.beanfactory; importação org.springframework.bean.factory.beanfactorye; org.springframework.beans.factory.config.configurableListableBeanFactory; importar org.springframework.boot.bind.relaxedPropertyResolver; importação org.springframework.Context.EnvironmentAlare; importação; org.springframework.context.annotation.deferredImportSelector; importar org.springframework.core.ordered; importar org.springframework.core.annotation.annotationAttributes; importar org.springframework.core.env.conotationAttributes; org.springframework.core.env.environment; importar org.springframework.core.io.resourcelOader; importar org.springframework.core.io.supPtort.springFacoriesLoader; import org.springframework.core.typet.annotationMetmetsMoadr; org.springframework.core.type.classReading.cachingMetAdArATArtFactory; importar org.springframework.core.type.classReading.metadArAradeRFactory; import org.springframework.utilassert; importação; org.springframework.util.stringutils;/** * {@link DeferredImportSelector} para lidar com {@link enableautoconfiguration * auto-configuração automática}. Esta classe também pode ser subclassificada se uma variante personalizada de * {@link EnableAutoconfiguration @enableAutoconfiguration}. é necessário. * * @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, Ordenado {private static final string [] no_imports = {}; Logger final estático privado = logFactory .GetLog (AutoConfigurationImportSelector.class); ConfigurableListableBeanFactory Factário; Ambiente Privado Ambiente; carregador de classe privado BeanClassLoader; ResourceLoader privado ResourceLoader; @Override public String [] SelectImports (anoTationMetadata AnoTationMetadata) {if (! IsEnabled (anoTationMetadata)) {return No_imports; } tente {AutoConfigurationMetadata AutoConfigurationMetadata = AutoConfigurationMetadatalOader .loadMetAdata (this.BeanClassLoader); AnoTationAttributes Attributes = getAttributes (ANNOTATIONMETADATA); List <String> Configurações = getCandidateConfigurações (AnotationMetadata, atributos); configurações = removeduplicates (configurações); Configurações = classificação (configurações, AutoConfigurationMetadata); Set <string> exclusões = getExclusions (anoTationMetadata, atributos); checkexcludedclasses (configurações, exclus); configurações.removeall (exclusões); Configurações = filtro (configurações, AutoConfigurationMetadata); fireautoconfigurationImportEvents (configurações, exclus); retornar configurações.toArray (new String [Configurações.size ()]); } catch (ioexception ex) {lança new ilegalStateException (ex); }} boolean protegido isenabled (anotationMetadata Metadata) {return true; } /** * Retorne o {@link AnoTationAttributes} do * {@link anoTationMetadata}. Por padrão, este método retornará atributos para * {@link #getannotationClass ()}. * Metadados @param Os metadados da anotação * @return Anotation Atributos */ anotação protegidaAttributes getAttributes (anotationMetadata metadados) {Nome da String = getAnnotationClass (). getName (); AnoTationAttributes Atributos = ANNOTATIONATTRIBUTOS .FROMAP (metadados.getAnnoTationAttributes (nome, true)); Assert.NotNull (atributos, "Nenhum atributo de configuração automática encontrada. Is" + metadata.getclassName () + "ANOTADO COM" + classutils.getShortName (nome) + "?"); atributos de retorno; } /*** Retorne a classe de anotação de origem usada pelo seletor. * @RETURN A classe de anotação */ Classe protegida <?> getAnnotationClass () {return enableAutoconfiguration.class; } /*** Retorne os nomes da classe de configuração automática que devem ser considerados. Por padrão * Este método carregará candidatos usando {@link SpringFacoriesLoader} com * {@link #getspringFacoriesLoaderFactoryClass ()}. * @param metadados Os metadados da origem * @param atribuem o {@link #getAttributes (anotationMetadata) anotação * atributos} * @return Uma lista de configurações de candidatos */ Lista protegida <string> getCandidatEnTações (AnnotationMetata Metadata Metadata, Configurações = SpringFacoriesLoader.LoadFactoryNames (getSpringFacoriesLoaderFactoryClass (), getBeanClassLoader ()); Assert.NotEmpty (Configurações, "Nenhuma classe de configuração automática encontrada no meta-inf/spring.factories. Se você" + "estiver usando uma embalagem personalizada, verifique se o arquivo está correto."); retornar configurações; } /** * Retorne a classe usada por {@link SpringFacoriesLoader} para carregar a configuração *. * @RETURN A classe de fábrica */ classe protegida <?> getSpringFactoriesLoaderFactoryClass () {return enableAutoconfiguration.class; } private void checkexcludedclasses (list <string> configurações, set <tring> excls) {list <string> invalidexcludes = new ArrayList <string> (exclusões.size ()); para (String exclus: excls) {if (classutils.ispresent (exclusão, getClass (). getClassLoader ()) &&! Configurações.Contains (exclusão)) {InvalidexCludes.add (exclusão); }} if (! InvalidexCludes.isEmpty ()) {handleInvalidexcludes (invalidexcludes); }} /*** Lidar com qualquer exclusão inválida que tenha sido especificada. * @param invalidexcludes A lista de exclusão inválida (sempre terá pelo menos um * elemento) */ Protected void handleInValidexCludes (list <string> invalidexcludes) {stringbuilder message = new StringBuilder (); para (String exclude: invalidexcludes) {message.append ("/t-") .append (exclude) .append (string.format ("%n")); } lançar novas IllegalStateException (String .Format ("As classes a seguir não puderam ser excluídas porque são" + "não classes de configuração automática:%n%s", mensagem)); } /*** Retorne quaisquer exclusões que limitem as configurações do candidato. * @param metadados Os metadados da origem * @param atribuem os atributos {@link #getAttributes (anotationMetAdata) anotation * LinkedHashSet <String> (); excludado.addall (aslist (atributos, "exclude")); exclui.addall (Arrays.aslist (atributes.getStringArray ("excludename"))); excludado.addall (getExcludeautoconfigurationsProperty ()); retorno excluído; } Lista privada <String> getExcludeAutoconfiguraçõesProperty () {if (getenvironment () instância de configurabilaburacuracuracyeNvironment) {RelaxedPropertyResolver Resolver = New RelaxedPropertyResolver (this.environment, "Spring.Autoconfigure"); Mapa <string, object> Properties = resolver.getSubProperties ("exclude"); if (Properties.isEmpty ()) {return collectionS.Emptylist (); } List <tring> excludes = new ArrayList <String> (); para (map.entry <string, object> Entrada: Properties.EntrySet ()) {String name = Entry.getKey (); Valor do objeto = Entry.getValue (); if (name.isEmpty () || name.startswith ("[") && valor! }} retornar exclui; } RelaxedProperTyResolver Resolver = new RelaxedProperTyResolver (Getenvironment (), "Spring.autoconfigure"); String [] exclude = resolver.getProperty ("exclude", string []. Classe); return (Arrays.asList (exclude == null? New String [0]: exclude)); } Lista privada <String> stat (List <String> Configurações, AutoConfigurationMetadata AutoConfigurationMetadata) lança IoException {Configurações = novo autoconfigurationsorter (getMetadArtArtFactory (), auto -figuração). retornar configurações; } Lista privada <String> filtro (list <string> Configurações, AutoConfigurationMetadata AutoConfigurationMetadata) {Long startTime = System.nanotime (); String [] candidates = configureations.toArray (new String [Configurations.size ()]); boolean [] Skip = new boolean [candidatos.length]; Boolean pulado = false; para (filtro autoconfigurationImportFilter: getAutoconfigurationImportFilters ()) {Invokeawaremethods (filtro); boolean [] MATCH = FILTER.MATCH (candidatos, AutoConfigurationMetadata); for (int i = 0; i <match.length; i ++) {if (! Match [i]) {skip [i] = true; ignorado = true; }}}} if (! Skipped) {return configurações; } List <tring> resultado = new ArrayList <String> (candidates.length); para (int i = 0; i <candidatos.Length; i ++) {if (! Skip [i]) {result.add (candidatos [i]); }} if (logger.istraceEnabled ()) {int numberFiltered = configurations.size () - result.size (); Logger.Trace ("Filtred" + NumberFiltered + "Classe de configuração automática em" + timeUnit.nanoseconds.tomillis (System.nanotime () - StartTime) + "MS"); } retornar novo ArrayList <String> (resultado); } Lista protegida <utoroConfigurationImportFilter> getAutoconfigurationImportFilters () {return springfacoriesloader.loadFactories (auto -figuratureImportFilter.class, this.beanclassloader); } private metadatareaderFactory getMetAdAradeRFactory () {try {return getBeanFactory (). getBean (sharedMetAdArateRactoryContextInitializer.Bean_Name, metradateeaderFactory.cllass); } catch (nosuchbeandEfinitionException ex) {return New CachingMetAdArArtArtFactory (this.resourcelOader); }} final protegido <t> list <t> removeduplicates (list <t> list) {retorna new ArrayList <T> (new LinkedHashSet <T> (List)); } Lista final protegida <String> ASLIST (AnoTationAttributes Atributos, Nome da String) {String [] value = attributes.getStringArray (nome); return Arrays.asList (value == null? New String [0]: valor); } private void fireautoconfigurationImportEvents (List <String> Configurações, set <tring> exclusões) {list <utoroconfigurationImportListener> ouvintes = getAutoconfiguraturationImportListeners (); if (! ouvintes.isEmpty ()) {AutoConfigurationImportEvent Event = new AutoConfigurationImportEvent (this, configurações, exclusões); para (AutoConfigurationImportListener ouvinte: ouvintes) {InvokeaWaremethods (ouvinte); ouvinte.onautoconfigurationImportEvent (evento); }}} Lista protegida <AcroconfigurationImportListener> getAutoconfigurationImportListeners () {return springfactoriesloader.loadFactories (autoconfigurationImportListener.class, this.beanclassloader); } private void InvoKeaWAREMETHODS (Instância do objeto) {if (instância da instância do consciente) {if (instância da instância do beanclassloadRaWare) {((beanclassloadRaWare) instância) .SetBeanClassLoader (this.beanclassloader); } if (Instância da instância do beanFactoryAWare) {((beanFactoryAWare) Instância) .SetBeanFactory (this.BeanFactory); } if (instância de instância do ambiente aweare) {((AmbientAcare) Instância) .setEnvironment (this.environment); } if (Instância da instânciaofforceLoaderaWare) {((ResourceLoaderaWare) Instância) .SetResourceLoader (this.resourceLoader); }}} @Override public void setBeanFactory (BeanFactory BeanFactory) lança beansexception {Assert.isInsinStanceOf (configurableListableBeanFactory.class, BeanFactory); this.BeanFactory = (ConfigurableListableBeanFactory) BeanFactory; } final protegido ConfigurableListableBeanFactory getBeanFactory () {return this.BeanFactory; } @Override public void setBeanClassLoader (classe ClassLoader) {this.beanclassloader = classloader; } classe protegida getBeanClassLoader () {return this.beanClassLoader; } @Override public void setenvironment (ambiente ambiente) {this.environment = ambiente; } Ambiente final protegido Getenvironment () {return this.environment; } @Override public void setResourceLoader (ResourceLoader ResourceLoader) {this.resourceLoader = ResourceLoader; } final protegido ResourceLoader getResourceLoader () {return this.ResourceLoader; } @Override public int getOrder () {return ordened.lowest_precedence - 1; }}Primeiro, esta classe implementa a interface de diferredimportselector, que herda o importação:
/ * * Copyright 2002-2013 O autor original ou autores. * * Licenciado sob a licença Apache, versão 2.0 (a "licença"); * Você não pode usar esse arquivo, exceto em conformidade com a licença. * Você pode obter uma cópia da licença em * * http://www.apache.org/license/license-2.0 * *, a menos que exigido pela lei aplicável ou acordada por escrito, o software * distribuído sob a licença seja distribuído em uma base "como é" *, sem garantia ou condição de qualquer tipo, seja expresso ou implícito. * Consulte a licença para as permissões e limitações do idioma específico e * sob a licença. */pacote org.springframework.context.annotation; importar org.springframework.core.type.annotationMetadata;/** * Interface a ser implementada por tipos que determinam que @{ @link configatury} * class (es) deve ser importado com base em uma determinada seleção. * * <p> um {@link importSelector} pode implementar qualquer um dos seguintes * {@link org.springframework.beans.factory.aWare consche} interfaces, e seus respectivos métodos * serão chamados anteriores a {@link #selectimports}: * <ul> EnvironmentAcare} </li> * <li> {@link org.springframework.beans.Factory.BeanFactoryWare BeanFactoryAware} </li> * <li> {@link org.springFramework.Beans.Factory.BeaRaRaWare@linkearare} org.springFramework.Context.ResoulELoaderaWare ResourceLoaderaWare} </li> * </ul> * <p> ImportSelectors são geralmente processados da mesma maneira que a seleção regular {@Code @Import} *, no entanto, é possível que a seleção de @Code @import} DeferredImportSelector} * Para detalhes). * * @Author Chris Beams * @since 3.1 * @See DeferredImportSelector * @see Import * @See ImportBeanDefinitionRegistrar * @See Configuration * /Public Interface ImportSelector {** ** * Select e retorna os nomes de qual classe (es) deve ser importada com base em @{@Link ANSTATMAMETM e retornará os nomes (es) deve ser importada com base em @{@link */ String [] SelectImports (AnnotationMetadata importingClassMetadata);}Essa interface é usada principalmente para importar os itens de configuração do @configuration, e o adteredimportSelector é uma importação diferida e será executada somente depois que todas as @configurações forem processadas.
Vamos dar uma olhada no método SelectImport de AutoConfigurationImportSelector:
@Override public String [] SelectImports (anoTationMetadata AnoTationMetadata) {if (! IsEnabled (anoTationMetadata)) {return No_imports; } tente {AutoConfigurationMetadata AutoConfigurationMetadata = AutoConfigurationMetadatalOader .loadMetAdata (this.BeanClassLoader); AnoTationAttributes Attributes = getAttributes (ANNOTATIONMETADATA); List <String> Configurações = getCandidateConfigurações (AnotationMetadata, atributos); configurações = removeduplicates (configurações); Configurações = classificação (configurações, AutoConfigurationMetadata); Set <string> exclusions = getExclusions (anoTationMetadata, atributos); checkexcludedclasses (configurações, exclus); configurações.removeall (exclusões); Configurações = filtro (configurações, AutoConfigurationMetadata); FireAutoconfigurationImportEvents (configurações, exclusões); retornar configurações.toArray (new String [Configurações.size ()]); } catch (ioexception ex) {lança new ilegalStateException (ex); }}
No início, esse método determinará primeiro se deve executar a montagem automática e depois lerá as propriedades relevantes dos metadados e metadados de meta-inf/spring----figure-metadata.properties e, em seguida, chama o método getCandidateConfiguração:
/*** Retorne os nomes da classe de configuração automática que devem ser considerados. Por padrão * Este método carregará candidatos usando {@link SpringFacoriesLoader} com * {@link #getspringFacoriesLoaderFactoryClass ()}. * @param metadados Os metadados da origem * @param atribuem o {@link #getAttributes (anotationMetadata) anotação * atributos} * @return Uma lista de configurações de candidatos */ Lista protegida <string> getCandidatEnTações (AnnotationMetata Metadata Metadata, Configurações = SpringFacoriesLoader.LoadFactoryNames (getSpringFacoriesLoaderFactoryClass (), getBeanClassLoader ()); Assert.NotEmpty (Configurações, "Nenhuma classe de configuração automática encontrada no meta-inf/spring.factories. Se você" + "estiver usando uma embalagem personalizada, verifique se o arquivo está correto."); retornar configurações; } /** * Retorne a classe usada por {@link SpringFacoriesLoader} para carregar a configuração *. * @RETURN A classe de fábrica */ classe protegida <?> getSpringFactoriesLoaderFactoryClass () {return enableAutoconfiguration.class; }Aqui, eu conheci nosso antigo conhecido - SpringFactoryiesLoader, que lerá a configuração da ativação de ativação em meta -inf/spring.factories e, em seguida, executará exclusão e filtragem para obter a classe que precisa ser montada. Finalmente, deixe todos os autoconfigurationimportListener configurados no meta-inf/spring.factories executar o evento AutoConfigurationImportEvent, o código é o seguinte:
private void fireautoconfigurationImportEvents (List <String> Configurações, set <tring> exclusões) {List <AutoconfigurationImportListener> ouvintes = getAutoconfiguratureImportListeners (); if (! ouvintes.isEmpty ()) {AutoConfigurationImportEvent Event = new AutoConfigurationImportEvent (this, configurações, exclusões); para (AutoConfigurationImportListener ouvinte: ouvintes) {InvokeaWaremethods (ouvinte); ouvinte.onautoconfigurationImportEvent (evento); }}} Lista protegida <AcroconfigurationImportListener> getAutoconfigurationImportListeners () {return springfactoriesloader.loadFactories (autoconfigurationImportListener.class, this.beanclassloader); }No link anterior, precisamos determinar apenas quais classes precisam ser montadas e quando essas classes montadas automaticamente serão processadas no Springboot? Vamos analisá -lo brevemente:
2.1. Método de atualização do abstrateApplicationContext:
Este método é um clichê. Por favor, preste atenção a este método:
// Invoca os processadores de fábrica registrados como feijões no contexto. InvokeBeanFactoryPostProcessors (BeanFactory);
Aqui está o processo de beanfactoryPostProcessor, então vamos dar uma olhada nessa interface BeandEfinitionRegistryPostProcessor:
/ * * Copyright 2002-2010 O autor original ou autores. * * Licenciado sob a licença Apache, versão 2.0 (a "licença"); * Você não pode usar esse arquivo, exceto em conformidade com a licença. * Você pode obter uma cópia da licença em * * http://www.apache.org/license/license-2.0 * *, a menos que exigido pela lei aplicável ou acordada por escrito, o software * distribuído sob a licença seja distribuído em uma base "como é" *, sem garantia ou condição de qualquer tipo, seja expresso ou implícito. * Consulte a licença para as permissões e limitações do idioma específico e * sob a licença. */package org.springframework.beans.factory.support; importar org.springframework.beans.beansexception; importar org.springframework.beans.factory.config.BeanFactoryPostProcessor;/** ** Extensão para o padrão {@Link BEANFACIMENTO Definições <i> Antes </i> * Regular * Detecção do Processador de BeanFactory. * * @Author Juergen Hoeller * @Since 3.0.1 * @see org.springframework.context.annotation.configurationClassPostProcessor * /interface pública BeandEfinitionReGistryPostProcessor estende o BeanFactoryProcessor {** ** * Modify BEMENTIFIZEMENTO O APLICATIVELTORENTE O APLICATIVELTORETETENDE O BEANSTORYPROCESSOR. Todas as definições regulares de feijão terão sido carregadas, * mas nenhum feijão terá sido instanciado ainda. Isso permite adicionar mais definições de bean antes da próxima fase de pós-processamento.Essa interface herda o beanfactoryPostProcessor.
2.2. ConfigurationClassPostProcessor Classe
Esta classe lida principalmente com a anotação @Configuration. Ele implementa o BeanDefinitionRegistryProcessor, e também implementa indiretamente BeanFactoryPostProcessor. O código -chave é o seguinte:
@Override public void PostprocessBeanFactory (ConfigurableListableBeanFactory BeanFactory) {int fActoryId = System.IdentityHashCode (BeanFactory); if (this.FactoriesPostproceded.Contains (FactoryId)) {lança new IllegalStateException ("PostprocessBeanFactory já chamado neste pós-processador contra" + beanFactory); } this.FactoriesPostproceded.add (FactoryId); if (! this.RegistriesPostproced.Contains (FactoryId)) {// BeandEfinitionRegistryPostProcessor Hook aparentemente não suportado ... // Simplesmente chama o processConfigurationClasses preguiçosamente neste momento. ProcessConfigBeandEfinitions ((BeandEfinitionRecistry) BeanFactory); } EMENCECONFIGURAÇÃOCLASSES (BeanFactory); beanfactory.addbeanPostProcessor (new ImportAwareBeanPostProcessor (BeanFactory)); }/** * Crie e valida um modelo de configuração com base no registro de classes * {@link Configuration}. */public void ProcessConfigBeandEfinitions (BeandEfinitionRegistry Registry) {/// ... this.ComponentsCanBeanNameGenerator, Registry); SET <SELEDefinitionHolder> Candidatos = new LinkedHashSet <SEDendEfinitionHolder> (ConfigCandidates); Set <figurationClass> alreadyparsed = new HashSet <FigurationClass> (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()); // ....Omit part of the code}其实这里注释已经很清楚了,我们可以清楚的看到解析每一个@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. Espero que seja útil para você. If you have any questions, please leave me a message and the editor will reply to you in time!