El ensamblaje automático de SpringBoot es la base para la unboxing y el requisito previo para los microservicios. El tema principal esta vez es ver cómo se implementa. Utilizamos el código fuente para comprender los entresijos del ensamblaje automático.
1.1. Acerca de @SpringBootApplication
Cuando estamos escribiendo el proyecto SpringBoot, @SpringBootApplication es la anotación más común. Podemos echar un vistazo al código fuente:
/ * * Copyright 2012-2017 El autor o autores originales. * * Licenciado bajo la licencia Apache, versión 2.0 (la "licencia"); * No puede usar este archivo, excepto de conformidad con la licencia. * Puede obtener una copia de la licencia en * * http://www.apache.org/licenses/license-2.0 * * A menos que sea requerido por la ley aplicable o acordado por escrito, el software * distribuido bajo la licencia se distribuye sobre una base "como es", * sin garantías o condiciones de ningún tipo, ya sea expresa o implícita. * Consulte la licencia para los permisos de gobernanza del idioma específicos y * limitaciones bajo la licencia. */paquete org.springframework.boot.autoconfigure; import java.lang.annotation.documented; import java.lang.annotation.elementType; import java.lang.annotation.inherited; import java.lang.annotation.cretention; import java.lang.annotation.retentionpolicy; java.lang.annotation.target; import org.springframework.boot.springbootconfiguration; import org.springframework.boot.context.typeExCludeFilter; importar org.springframework.context.annotation.bean; import org.springframework.conteNtet.annotation org.springframework.context.annotation.componentscan.filter; import org.springframework.context.annotation.configuration; import org.springframework.context.Annotation.filterType; importación de Org.sPringFringframeWork.core.annotation.aliasfor;/*** indica una configuración; Clase que declara uno o más métodos * {@link bean @bean} y también desencadena {@link habilitaneutoconfiguration * autoconfiguración} y {@link Componentscan Component Scanning}. Esta es una anotación de conveniencia * que es equivalente a declarar {@code @configuration}, * {@code @enableAutoconfiguration} y {@code @ComponentsCan}. * * @author Phillip Webb * @author Stephane Nicoll * @Since 1.2.0 */@Target (elementType.type) @Retention (retentionPolicy.runTime)@documented@inherited@springbootconfiguration@enableAutoconfiguration@componentScan (excludfilter TypeExCludeFilter.Class), @filter (type = filtreType.custom, classes = AutoconfigurationExCludeFilter.class)}) public @interface SpringBootApplication { /*** excluye clases específicas de configuración automática de tal manera que nunca se aplicarán. * @return las clases para excluir */ @aliasfor (annotation = EnableAutOconfiguration.class, attribute = "excluir") class <?> [] excluir () predeterminado {}; /** * Excluir nombres específicos de clases de configuración automática de modo que nunca se apliquen *. * @return los nombres de clases para excluir * @since 1.3.0 */ @aliasfor (annotation = EnleaToconfiguration.class, attribute = "excludename") string [] excludeName () predeterminado {}; /*** Paquetes base para escanear los componentes anotados. Use {@link #ScanBasePackAgECLasses} * para una alternativa de tipo seguro a los nombres de paquetes basados en cadenas. * @return paquetes base para escanear * @since 1.3.0 */ @aliasfor (annotation = componentscan.class, attribute = "basepackages") string [] scanBasepackages () predeterminado {}; /** * Alternativa de tipo a prueba de {@link #ScanBasepackages} para especificar los paquetes para * escanear para componentes anotados. El paquete de cada clase especificado será escaneado. * <P> * Considere crear una clase o interfaz de marcador no-op-op en cada paquete que * no tenga otro propósito que no sea referenciar este atributo. * @return paquetes base para escanear * @since 1.3.0 */ @aliasfor (annotation = componentscan.class, attribute = "basepackageClasses") class <?> [] ScanBasePackageClasses () predeterminado {};}Esto contiene @SpringBootConfiguration, @enableAutoconfiguration, @ComponentsCan. Aquí, dado que no hay un paquete de escaneo especificado, escanea todas las clases bajo el mismo nivel que la clase o el mismo paquete de nivel de forma predeterminada. Además, @springbootconfiguration, puede averiguar a través del código fuente que es una @configuration:
/ * * Copyright 2012-2016 El autor o autores originales. * * Licenciado bajo la licencia Apache, versión 2.0 (la "licencia"); * No puede usar este archivo, excepto de conformidad con la licencia. * Puede obtener una copia de la licencia en * * http://www.apache.org/licenses/license-2.0 * * A menos que sea requerido por la ley aplicable o acordado por escrito, el software * distribuido bajo la licencia se distribuye sobre una base "como es", * sin garantías o condiciones de ningún tipo, ya sea expresa o implícita. * Consulte la licencia para los permisos de gobernanza del idioma específicos y * limitaciones bajo la licencia. */paquete 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; importget; importación; org.springframework.context.annotation.configuration;/** * Indica que una clase proporciona aplicación de arranque de primavera * {@link configuración @configuration}. Se puede usar como una alternativa a la anotación de Spring * Standard {@code @configuration} para que la configuración se pueda encontrar * automáticamente (por ejemplo en las pruebas). * <p> * La aplicación solo debe incluir <em> one </em> {@code @springbootconfiguration} y * las aplicaciones de arranque de primavera más idiomáticas lo heredarán desde * {@code @springbootapplication}. * * @author Phillip Webb * @since 1.4.0 */@Target (elementType.type) @Retention (retenciónPolicy.Runtime)@documentado@configurationPublic @Interface SpringBootConfiguration {}A partir de esto, podemos inferir que @SpringBootApplication es equivalente a @Configuration @ComponentsCan @enableAutoconfiguration
1.2. @Enableautoconfiguration
Una vez que se agrega esta anotación, la función de ensamblaje automático estará habilitada. En pocas palabras, Spring intentará encontrar todos los frijoles configurados debajo de su classpath y luego ensamblarlos. Por supuesto, al ensamblar un frijol, se inicializará de acuerdo con varias reglas de personalización (condicionales). Echemos un vistazo a su código fuente:
/ * * Copyright 2012-2017 El autor o autores originales. * * Licenciado bajo la licencia Apache, versión 2.0 (la "licencia"); * No puede usar este archivo, excepto de conformidad con la licencia. * Puede obtener una copia de la licencia en * * http://www.apache.org/licenses/license-2.0 * * A menos que sea requerido por la ley aplicable o acordado por escrito, el software * distribuido bajo la licencia se distribuye sobre una base "como es", * sin garantías o condiciones de ningún tipo, ya sea expresa o implícita. * Consulte la licencia para los permisos de gobernanza del idioma específicos y * limitaciones bajo la licencia. */paquete org.springframework.boot.autoconfigure; import java.lang.annotation.documented; import java.lang.annotation.elementType; import java.lang.annotation.inherited; import java.lang.annotation.cretention; import java.lang.annotation.retentionpolicy; java.lang.annotation.target; import org.springframework.boot.autoconfigure.condition.conditiononbean; importar org.springframework.boot.autoconfigure.condition.conditiononbean; importación org.springframework.boot.autoconfigure.condition.conditionalonmissingbean; import org.springframework.boot.context.embedded.embeddedservletContainerFactory; importar org.springframework.boot.context.embedded.tomcat.tomcatembeddedservletContainerFactory; importar org.springframework.context.annotation.conditional; import org.springFramework.context.annotation.configuration; import og.springframe.contetatation org.springframework.core.io.support.springfactoriesloader;/** * Habilite la configuración automática del contexto de la aplicación Spring, intentando adivinar y * configurar los granos que es probable que necesite. Las clases de configuración automática generalmente se aplican * en función de su classpath y qué frijoles ha definido. Por ejemplo, si * tiene {@Code TomCat-Embedded.jar} en su classpath, es probable que desee un * {@link TomCatembeddedServletContainerFactory} (a menos que haya definido su propio * {@link embedida de servicio de servicio de información). * <p> * Cuando se usa {@link springbootapplication}, la configuración automática del contexto está * habilitada automáticamente y agregando esta anotación, por lo tanto, no tiene ningún efecto adicional. * <P> * La configuración automática intenta ser lo más inteligente posible y retrocederá a medida que * defina más de su propia configuración. Siempre puede {@link #exclude ()} cualquier * configuración que nunca desee aplicar (use {@link #excludeName ()} si no tiene acceso a ellos). También puede excluirlos a través de la propiedad * {@code spring.autoconfigure.exclude}. La configuración automática siempre se aplica * después de que se han registrado frijoles definidos por el usuario. * <p> * El paquete de la clase que se anota con {@code @enableAutoconfiguration}, * generalmente a través de {@code @springbootapplication}, tiene un significado específico y a menudo se usa * como 'predeterminado'. Por ejemplo, se usará al escanear las clases {@code @Entity}. * Generalmente se recomienda que coloque {@code @enableAutoconfiguration} (si * no está usando {@code @springbootapplication}) en un paquete raíz para que se puedan buscar todos los sub-paquetes * y las clases. * <p> * Las clases de configuración automática son frijoles de primavera regular {@link}. Están * ubicados utilizando el mecanismo {@link SpringFactoriesLoader} (con llave contra esta clase). * En general, los frijoles de configuración automática son {@link condicional @conditional} frijoles (la mayoría * a menudo usando {@link condicionalOnclass @conditionalonclass} y * {@link condicionalonMissingBean @conditionalonmissingbean} annotations). * * @author Phillip Webb * @author Stephane Nicoll * @see condicionalonbean * @see condicionalonmissingbean * @see condicionalonclass * @see autoconfiguricter * @see springbootapplication */@Supresswarnings ("deprecation")@target (elementtype.type) @retention (retentionPolicy.runtime)@documented@heredero@autoconfigurationPackage@import (enlableutoconfigurationImportselector.class) public @interface Enleautoconfiguration {String_override_Propertyy "Spring.Boot.enableAutoconfiguration"; /*** Excluya clases específicas de configuración automática de modo que nunca se apliquen. * @return las clases para excluir */ class <?> [] excluir () predeterminado {}; /** * Excluir nombres específicos de clases de configuración automática de modo que nunca se apliquen *. * @return los nombres de clases para excluir * @since 1.3.0 */ string [] excludename () predeterminado {};}Aunque de acuerdo con los comentarios de la documentación, nos guía para ver habilitado el Importselector. Pero la clase está desactualizada en la versión SpringBoot1.5.x, así que echemos un vistazo a su clase principal AutoconfigurationImportSelector:
/ * * Copyright 2012-2017 El autor o autores originales. * * Licenciado bajo la licencia Apache, versión 2.0 (la "licencia"); * No puede usar este archivo, excepto de conformidad con la licencia. * Puede obtener una copia de la licencia en * * http://www.apache.org/licenses/license-2.0 * * A menos que sea requerido por la ley aplicable o acordado por escrito, el software * distribuido bajo la licencia se distribuye sobre una base "como es", * sin garantías o condiciones de ningún tipo, ya sea expresa o implícita. * Consulte la licencia para los permisos de gobierno específicos que rigen el idioma y * limitaciones bajo la licencia. */paquete org.springframework.boot.autoconfigure; import java.io.ioexception; import java.util.arrayList; import java.util.arrays; import java.util.collections; import java.util.hashset; import java.util.linkedhashset; import java.util.list; import java.util.map; import java.util.set; import java.util.concurrent.timeUnit; import org.apache.commons.logging.log; importar org.apache.commons.logging.logfactory; importar org.springingwork.beans.beansexception; importar orgfringframwork.aweAs.aweRfactory; org. org. org.springframework.context.annotation.deferredImportSelector; import org.springframework.core.ordered; import org.springframework.core.annotation.annotationAttributes; import org.springframework.core.env.configurableenvirment; importación; org.springframework.core.env.environment; import org.springframework.core.io.resourceloader; import org.springframework.core.io.support.springfactoriesloader; import og.springfframework.core.type.annotationmetata; org.springframework.core.type.classreading.cachingmetadAdatareaderFactory; import org.springframework.core.type.classreading.metadatareaderFactory; importar org.springframework.util.assert; import org.springframework.util.stringutils;/** * {@link DeferRedImportSelector} para manejar {@link habilitaneutoconfiguration * autoconfiguración}. Esta clase también se puede subclasificar si es una variante personalizada de * {@link habilitaneutoconfiguration @enableAutoconfiguration}. es necesario. * * @author Phillip Webb * @author Andy Wilkinson * @author Stephane Nicoll * @author Madhura Bhave * @since 1.3.0 * @see EnableAutoConfiguration */public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { cadena final estática privada [] no_imports = {}; Private static final log logger = logFactory .getLog (autoconfigurationImportSelector.class); privado configuraciónListableBeanFactory BeanFactory; entorno privado entorno; Cargador de clase privado BeanClassLoader; Resourceloader privado Resourceloader; @Override public String [] SelectImports (annotationMetadata AnnotationMetadata) {if (! IsEnabled (annotationMetadata)) {return no_imports; } try {autoconfigurationMetadata AutoconfigurationMetadata = AutoconfigurationMetadataloader .LoadMetadata (this.BeanClassLoader); AnotationAttributes atributes = getAttributes (annotationmetadata); Lista <String> configuraciones = getCandidateConfigurations (annotationMetadata, atributos); configuraciones = removedUpplate (configuraciones); configuraciones = sort (configuraciones, autoconfigurationMetadata); Establecer <string> exclusions = getExClusions (annotationMetadata, atributos); checkexCludedClasses (configuraciones, exclusas); configurations.removeAll (exclusiones); configuraciones = filtro (configuraciones, autoconfigurationMetadata); FireUtoconfigurationImportEvents (configuraciones, exclusas); return configurations.toarray (new String [configurations.size ()]); } Catch (ioException ex) {tirar nueva ilegalstateException (ex); }} boolean protegido isEnabled (annotationmetadata metadata) {return true; } /** * Devuelve el apropiado {@link anotationAtTributes} de * {@link anotationMetadata}. Por defecto, este método devolverá los atributos para * {@link #getAnnotationClass ()}. * @param metadatos los metadatos de anotación * @treturn atributos de anotación */ protegido anotationattributes getAttributes (AnnotationMetadata metadata) {String name = getAnnotationClass (). getName (); AnnotationAttributes atributes = annotationAttributes .FromMAP (metadata.getAnnotationAttributes (nombre, true)); Afirmar.notnull (atributos, "no se encuentran atributos de configuración automática. ¿" + Metadata.getClassName () + "anotado con" + classUtils.getShortName (nombre) + "?"); atributos de retorno; } /*** Devuelve la clase de anotación de origen utilizada por el selector. * @return la clase de anotación */ Class protegida <?> getAnnotationClass () {return EnableautOconfiguration.class; } /*** Devuelve los nombres de clase de configuración automática que deben considerarse. Por defecto * este método cargará candidatos usando {@link SpringFactoriesLoader} con * {@link #getSpringFactoriesloaderFactoryClass ()}. * @param metadata los metadatos de origen * @param atribuye el {@link #getAttributes (annotationMetadata) anotación * atributos} * @return una lista de configuraciones candidatas */ listecting list <string> getCandiDateConfigurations (annotationMetadata metadata, annotationAtTributes atributes) {list <string <string> striEdategurations SpringFactoriesLoader.LoadFactoryNames (GetSpringFactoriesLoaderFactoryClass (), getBeanClassLoader ()); Afirmar.notempty (configuraciones, "no hay clases de configuración automática que se encuentren en meta-inf/spring.factories. Si" + "está utilizando un empaque personalizado, asegúrese de que el archivo sea correcto"); configuraciones de devolución; } /** * Devuelve la clase utilizada por {@link SpringFactoriesLoader} para cargar la configuración * Candidatos. * @return la clase de fábrica */ protegida clase <?> getSpringFactoriesloaderFactoryClass () {return enableautOconfiguration.class; } private void checkExCludedClasses (List <String> Configuraciones, establecer <string> Exclus) {List <String> InvalidExCludes = new ArrayList <Strusion> (exclusions.size ()); for (string exclus: exclus) {if (classUtils.esPresent (exclusión, getClass (). getClassLoader ()) &&! Configuración.contains (exclusión)) {invalidExCludes.Add (exclusión); }} if (! InvalidExCludes.IsEmpty ()) {HandleInValidExCludes (InvalidExCludes); }} /*** Manejar cualquier exclusión inválida que se haya especificado. * @param InvalidExCluye la lista de excluyentes inválidos (siempre tendrá al menos un * elemento) */ protegido nuloinValidExCludes (List <String> InvalidExCludes) {StringBuilder Mensaje = nuevo StringBuilder (); for (String Exclute: InvalidExCludes) {Message.Append ("/T-") .Append (excluir) .Append (String.Format ("%n")); } Lanzar nueva ilegalStateException (String .Format ("Las siguientes clases no pueden excluirse porque son" + "no clases de configuración automática:%n%s", mensaje)); } /*** Devuelva cualquier exclusión que limite las configuraciones candidatas. * @param metadata the source metadata * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation * attributes} * @return exclusions or an empty set */ protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) { Set<String> excluded = new LinkedHashSet<String>(); excluido.addall (aslist (atributos, "excluir")); excluido.addall (arrays.aslist (attributes.getStringArray ("excludename"))); excluido.addall (getExCludeautoconfigurationsProperty ()); regreso excluido; } Lista privada <String> getExCludeaUtoconfigurationsProperty () {if (getenVironment () instancia de configurableenvironment) {relaxedpropertyresolver resolver = new RelleedPropertyResolver (this.environment ", Spring.Autoconfigurfigure.");; MAP <String, Object> Properties = resolver.getSubProperties ("excluir"); if (Properties.IsEmpty ()) {return Collections.EmptyList (); } List <String> excluye = new ArrayList <String> (); for (map.entry <string, object> Entry: Properties.EntrySet ()) {String name = Entry.getKey (); Valor de objeto = entry.getValue (); if (name.isEmpty () || name.startswith ("[") && value! = null) {excludes.addall (new Hashset <string> (arrays.aslist (stringUtils .TokenizetostringArray (string.ValueOf (valor), ","))); }} retorno excluye; } RelatedPropertyResolver resolver = new RelleedPropertyResolver (getenvironment (), "Spring.autoconfigure"); String [] excluir = resolver.getProperty ("excluir", string []. Class); return (arrays.aslist (excluir == null? nueva cadena [0]: excluir)); } Lista privada <String> Sort (List <String> Configuraciones, AutoconfigurationMetadata AutoconfigurationMetadata) lanza ioexception {configurations = new Autoconfigurationsorter (getMetadateAteaderFactory (), autoconfigurationMetadata) .getInPriorityOrder (configuraciones); configuraciones de devolución; } Lista privada <String> Filter (List <String> Configuraciones, AutoconfigurationMetadata AutoconfigurationMetadata) {long starttime = system.nanotime (); String [] candidates = configurations.toarray (new String [Configurations.Size ()]); booleano [] skip = nuevo booleano [candidates.length]; booleano omitido = falso; para (Filtro AutoconfigurationImportFilter: getAutoconfigurationImportFilters ()) {invokeaWaremethods (filtro); boolean [] match = filtre.match (candidatos, autoconfigurationmetadata); for (int i = 0; i <match.length; i ++) {if (! Match [i]) {skip [i] = true; omitir = verdadero; }}}} if (! Skipped) {configuraciones de retorno; } List <String> result = new ArrayList <String> (candidates.length); for (int i = 0; i <candidates.length; i ++) {if (! Skip [i]) {result.add (candidatos [i]); }} if (logger.istraceEnabled ()) {int numberFiltered = configurations.size () - resultado.size (); logger.trace ("filtrado" + numberFiltered + "clase de configuración automática en" + timeUnit.nanoseConds.tomillis (system.nanotime () - starttime) + "ms"); } return New ArrayList <String> (resultado); } Lista protegida <AutoconfigurationImportFilter> getAutoconfigurationImportFilters () {return SpringFactoriesLoader.LoadFactories (autoconfigurationImportFilter.class, this.BeanClassAnsLoader); } private metadatareaderFactory getMetadAdatareaderFactory () {try {return GetBeanFactory (). } Catch (nosuchbeanDefinitionException ex) {return new CachingMetadAdatareaderFactory (this.resourceloader); }} Final protegido <T> LIST <T> eliminados (list <t> list) {return new ArrayList <T> (new LinkedHashset <T> (List)); } Lista final protegida <String> Aslist (AnnotationAttributes Attributes, String Name) {String [] valor = atributes.getStringArray (nombre); return arrays.aslist (value == null? new String [0]: valor); } private void fireautoconfigurationImportEvents (List <String> Configuraciones, establecer <String> Excclusions) {List <AutoconfigurationImportListener> oyentes = getAutoconfigurationImportListeners (); if (! oyentes.isempty ()) {autoconfigurationImportEvent Event = new AutoconfigurationImportEvent (this, Configurations, ExcClusions); para (autoconfigurationImportListener oyente: oyentes) {invokeawaremethods (oyente); oyente.AnAutoconfigurationImportEvent (evento); }}} Lista protegida <autoconfigurationImportListener> getAutoconfigurationImportListeners () {return SpringFactoriesloader.LoadFactories (autoconfigurationImportListener.class, this.BeanClassLeSloader); } private void invokeaWaremethods (instancia de objeto) {if (instancia instancea de consciente) {if (instancia instanciaf beanClassLoadEraPaware) {((beanClassLoadErakee) instancia) .SetBeanClassLoader (this.BeanClassLoader); } if (instancia instanciaf beanFactoryaware) {((beanFactoryaware) instancia) .SetBeanFactory (this.BeanFactory); } if (instancia instanciaf ambientalaware) {((ambienteee) instancia) .setenVironment (this.environment); } if (instancia instancia de resourCelOaaderaware) {((ResourCeCelsoaderaware) instancia) .SetResourCelOaader (this.resourCelOaader); }}} @Override public void setBeanFactory (BeanFactory BeanFactory) lanza BeanSexception {Afird.IsInStanceOf (configureableListableBeanFactory.class, beanFactory); this.beanFactory = (configurureableListableBeanFactory) beanFactory; } Protegido final ConfigureableListableBeanFactory getBeanFactory () {return this.BeanFactory; } @Override public void setBeanClassLoader (classloader classloader) {this.beanClassLoader = classLoader; } Proteged ClassLoader getBeanClassLoader () {return this.beanClassLoader; } @Override public void setEnvironment (entorno ambiental) {this.environment = ambiente; } entorno final protegido getEnvironment () {return this.environment; } @Override public void setResourCelOADER (Resourceloader ResourCelOader) {this.resourCelOaader = resourceloader; } Protegido Final Resourceloader getResourCelOader () {return this.resourceloader; } @Override public int getOrder () {return ordenado.lowest_precedence - 1; }}Primero, esta clase implementa la interfaz DeferRedImportSelector, que hereda el ImportSelector:
/ * * Copyright 2002-2013 El autor o autores originales. * * Licenciado bajo la licencia Apache, versión 2.0 (la "licencia"); * No puede usar este archivo, excepto de conformidad con la licencia. * Puede obtener una copia de la licencia en * * http://www.apache.org/licenses/license-2.0 * * A menos que sea requerido por la ley aplicable o acordado por escrito, el software * distribuido bajo la licencia se distribuye sobre una base "como es", * sin garantías o condiciones de ningún tipo, ya sea expresa o implícita. * Consulte la licencia para los permisos de gobierno específicos que rigen el idioma y * limitaciones bajo la licencia. */paquete org.springframework.context.annotation; import org.springframework.core.type.annotationMetadata;/** * La interfaz para ser implementada mediante tipos que determinan qué @ @ @link Configuration} * class (es) debe importarse en función de un criterio de selección dado, generalmente uno o atributos de anotación @ @ @. * * <p> un {@link importselector} puede implementar cualquiera de las siguientes interfaces * {@link org.springframework.beans.factory.ware ADAK}, y sus interfaces * respectivos * se llamarán antes de {@link #SelectImports}: * <ul> * <li> {@Link Org.springFrame EnvironmentAware} </li> * <li> {@link org.springframework.beans.factory.beanFactoryaware beanFactoryaSaWare} </li> * <li> {@link org.springframework.beans.factory.beanClassLassLassLoaderaware beanClassLoaderaware} </li> * <li> {@@@Link Link org.springframework.context.resourceloaderaware resourcelOaaderaware} </li> * </ul> * <p> importaciones de los importadores generalmente se procesan de la misma manera que las anotaciones regulares {@code @import} *, sin embargo, también es posible deferir la selección de importaciones hasta que todos * {@code @configuration} DiferredImportSelector} * para más detalles). * * @author Chris Beams * @since 3.1 * @see DeFerredImportSelector * @see import * @see importeDefinitionRegistrar * @see Configuration * /public interface importsSelector { /** * Seleccione y devuelva los nombres de qué clase (es) debe ser importante basada en * la { @ @ @ @ @ @ @ @ @ @ @@link annotationmmetata} de la importación de la importación @ @ @ @ */ String [] SelectImports (AnnotationMetadata importingClassMetadata);}Esta interfaz se utiliza principalmente para importar los elementos de configuración de @Configuration, y DferredImportSelector es una importación diferida, y se ejecutará solo después de que se procesen todas las @Configurations.
Echemos un vistazo al método SelectImport de AutoconfigurationImportSelector:
@Override public String [] SelectImports (annotationMetadata AnnotationMetadata) {if (! IsEnabled (annotationMetadata)) {return no_imports; } try {autoconfigurationMetadata AutoconfigurationMetadata = AutoconfigurationMetadataloader .LoadMetadata (this.BeanClassLoader); AnotationAttributes atributes = getAttributes (annotationmetadata); Lista <String> configuraciones = getCandidateConfigurations (annotationMetadata, atributos); configuraciones = removedUpplate (configuraciones); configuraciones = sort (configuraciones, autoconfigurationMetadata); Establecer <String> excclusions = getExClusions (annotationMetadata, atributos); checkexCludedClasses (configuraciones, exclusas); configurations.removeAll (exclusiones); configuraciones = filtro (configuraciones, autoconfigurationMetadata); FireUtoconfigurationImportEvents (configuraciones, exclusiones); return configurations.toarray (new String [configurations.size ()]); } Catch (ioException ex) {tirar nueva ilegalstateException (ex); }}
Al principio, este método primero determinará si realizar un ensamblaje automático, y luego leerá las propiedades relevantes de los metadatos y los metadatos del método de Meta-INF/Spring-Autoconfigure-Metadata.Properties, y luego llame al método GetCandidateConfigurations:
/*** Devuelve los nombres de clase de configuración automática que deben considerarse. Por defecto * este método cargará candidatos usando {@link SpringFactoriesLoader} con * {@link #getSpringFactoriesloaderFactoryClass ()}. * @param metadata los metadatos de origen * @param atribuye el {@link #getAttributes (annotationMetadata) anotación * atributos} * @return una lista de configuraciones candidatas */ listecting list <string> getCandiDateConfigurations (annotationMetadata metadata, annotationAtTributes atributes) {list <string <string> striEdategurations SpringFactoriesLoader.LoadFactoryNames (GetSpringFactoriesLoaderFactoryClass (), getBeanClassLoader ()); Afirmar.notempty (configuraciones, "no hay clases de configuración automática que se encuentren en meta-inf/spring.factories. Si" + "está utilizando un empaque personalizado, asegúrese de que el archivo sea correcto"); configuraciones de devolución; } /** * Devuelve la clase utilizada por {@link SpringFactoriesLoader} para cargar la configuración * Candidatos. * @return la clase de fábrica */ protegida clase <?> getSpringFactoriesloaderFactoryClass () {return enableautOconfiguration.class; }Aquí conocí a nuestro antiguo conocido: SpringFactoryIsLoader, que leerá la configuración de EnableAutoconfiguration en Meta -Inf/Spring.Factories, y luego ejecutará exclusión y filtrado para obtener la clase que debe ensamblarse. Finalmente, deje que todos los autoconfigurationImportListener configurados en Meta-INF/Spring.Factories ejecute el evento automático de medoconfiguración, el código es el siguiente:
Private void fireAutoconfigurationImportEvents (List <String> Configuraciones, establecer <String> Excclusions) {List <AutoconfigurationImportListener> oyentes = getAutoconfigurationImportListeners (); if (! oyentes.isempty ()) {autoconfigurationImportEvent Event = new AutoconfigurationImportEvent (this, Configurations, ExcClusions); para (autoconfigurationImportListener oyente: oyentes) {invokeawaremethods (oyente); oyente.AnAutoconfigurationImportEvent (evento); }}} Lista protegida <autoconfigurationImportListener> getAutoconfigurationImportListeners () {return SpringFactoriesloader.LoadFactories (autoconfigurationImportListener.class, this.BeanClassLeSloader); }En el enlace anterior, solo necesitamos determinar qué clases deben ensamblarse, y ¿cuándo se procesarán estas clases ensambladas automáticamente en Springboot? Analicémoslo brevemente:
2.1. Actualizar el método de AbstractApplicationContext:
Este método es un cliché. Preste atención a este método:
// Invocar procesadores de fábrica registrados como frijoles en el contexto. InvokeBeanFactoryPostProcessors (BeanFactory);
Aquí está el proceso de BeanFactoryPostProcessor, así que echemos un vistazo a esta interfaz BeandefinitionRegistryPostProcessor:
/ * * Copyright 2002-2010 El autor o autores originales. * * Licenciado bajo la licencia Apache, versión 2.0 (la "licencia"); * No puede usar este archivo, excepto de conformidad con la licencia. * Puede obtener una copia de la licencia en * * http://www.apache.org/licenses/license-2.0 * * A menos que sea requerido por la ley aplicable o acordado por escrito, el software * distribuido bajo la licencia se distribuye sobre una base "como es", * sin garantías o condiciones de ningún tipo, ya sea expresa o implícita. * Consulte la licencia para los permisos de gobierno específicos que rigen el idioma y * limitaciones bajo la licencia. */paquete org.springframework.beans.factory.support; import org.springframework.beanss.beansexception; import org.springframework.beanss.factory.config.beanFactoryPscescessor;/** * Extensión a la extensión estándar de la extensión estándar {@link Behorfactory <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. Espero que te sea útil. If you have any questions, please leave me a message and the editor will reply to you in time!