How do I do spring boot auto configuration principle analysis

Preface

According to the analysis of springboot version 2.0.0, the overall automatic configuration process is as follows:

Refer to official documents for specific configuration: springboot-doc

Two @ SpringBootApplication

The core annotation @ SpringBootConfiguration is actually the @ Configuration annotation, indicating that it is a Configuration class, @ EnableAutoConfiguration indicating the automatic Configuration mechanism of springboot, @ ComponentScan indicating that scanning allows registration of additional Configuration classes;

@SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan

Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

    // Exclude autoconfig classes that will not be applied, in the form of classes
    @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude")
    Class<?>[] exclude() default {};

    // Exclude auto configuration classes that will not be applied, in the form of string array
    @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
    String[] excludeName() default {};

    // Scan basic package
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};

    // Scanning basic classes
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};

}

III. AutoConfigurationImportSelector

Click the @ enable autoconfiguration annotation to enter. You can see that @ Import({AutoConfigurationImportSelector.class}) is the import AutoConfigurationImportSelector class;

AutoConfigurationImportSelector class is the core class of automatic configuration. Its main function is to configure the configuration introduced by factory.properties and spring embedded integration;

3.1 the specific dependence chart is as follows:

3.2 member

    // Indicates no configuration is introduced
    private static final String[] NO_IMPORTS = new String[0];
    // Configuration log
    private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);
    // Excluded autoconfiguration
    private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
    // Declare beanFactory
    private ConfigurableListableBeanFactory beanFactory;
    // Declare environment (Global Environment)
    private Environment environment;
    // Declare beanClassLoader (class loader of bean, loading the integrated class in spring-autoconfigure-metadata.properties)
    private ClassLoader beanClassLoader;
    // Declare resourceLoader (resource loader, loading spring's factory.properties configuration class)
    private ResourceLoader resourceLoader;

3.3 selectImports

The main function of selectImports is to import the configuration classes in factory.properties and spring-autoconfigure-metadata.properties;

 public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            try {
              // 1. The essence of loading metadata information is loading beans. The beans here refer to our spring-autoconfigure-metadata.properties integration class
                AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
                // 2 annotation attributes is essentially a map
                AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
                // 3 get the configuration class in spring.factories
                List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
                // 4 configuration class replication is used to sort unnecessary configuration classes
                configurations = this.removeDuplicates(configurations);
                //  Prioritization
                configurations = this.sort(configurations, autoConfigurationMetadata);
                // Configuration class needs to be removed
                Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
                // Check and remove
                this.checkExcludedClasses(configurations, exclusions);
                // Execute remove configuration class
                configurations.removeAll(exclusions);
                configurations = this.filter(configurations, autoConfigurationMetadata);
                this.fireAutoConfigurationImportEvents(configurations, exclusions);
                return StringUtils.toStringArray(configurations);
            } catch (IOException var6) {
                throw new IllegalStateException(var6);
            }
        }
    }

1 Analysis
AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);

The path to enter the metadata information loaded by method discovery is META-INF/spring-autoconfigure-metadata.properties

public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
        return loadMetadata(classLoader, "META-INF/spring-autoconfigure-metadata.properties");
    }

Find spring-autoconfigure-metadata.properties under the autoconfig package


Click the property file to find the configuration information of spring auto configuration class name, as follows:

#Thu Mar 01 04:46:13 UTC 2018
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration=
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration.Configuration=
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration.ConditionalOnClass=com.datastax.driver.core.Cluster,org.springframework.data.cassandra.core.ReactiveCassandraTemplate,reactor.core.publisher.Flux
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration.ConditionalOnClass=org.apache.solr.client.solrj.SolrClient,org.springframework.data.solr.repository.SolrRepository
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration=
............................

Click one of the configuration classes at will, such as the first HttpMessageConvertersAutoConfiguration. The class annotation is as follows. It can be found that the autoconfiguration classes are all configured by annotation;

// The presentation configuration class is equivalent to the bean tag in xml
@Configuration
// Determine whether HttpMessageConverter.class class exists. If not, import
@ConditionalOnClass({HttpMessageConverter.class})
// Configure after these three configuration classes
@AutoConfigureAfter({GsonAutoConfiguration.class, JacksonAutoConfiguration.class, JsonbAutoConfiguration.class})
// The import configuration class is equivalent to the import tag in xml
@Import({JacksonHttpMessageConvertersConfiguration.class, GsonHttpMessageConvertersConfiguration.class, JsonbHttpMessageConvertersConfiguration.class})
public class HttpMessageConvertersAutoConfiguration {

3 Analysis

This. Getcandidate configurations (annotation metadata, attributes); the main function of the method is to obtain candidate configurations;

The main method found in the getCandidateConfigurations method is loadFactoryNames;

// Get the factory configuration information class name
 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

There are two parts to enter the loadFactoryNames method: the first is loadSpringFactories(classLoader), and the second is getOrDefault

// Load factory class name
 public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        //  Returns the list of class names
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

Part I:
The essence of loadspringfactors is to use spring's Resource call to obtain the configuration class in spring.factors;

// Load configuration class information in spring.factories
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                // Get the URL of 'spring.factories' configuration class
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();
                // Store the key and val of each configuration class in the map
                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        List<String> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));
                        result.addAll((String)entry.getKey(), factoryClassNames);
                    }
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var9) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);
            }
        }
    }

classLoader.getResources("META-INF/spring.factories"); the configuration in the auto configuration package is as follows:

The information of spring.factories loading configuration class is as follows. Yes, these configurations are the configuration class information needed for the start of spin, listener, filter, start configuration class of automatic configuration, error analysis of start failure and support of template engine. Please refer to the configuration package for details;

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
....................................

Part II:
getOrDefault is a map set. When there is a key in the map, the key value is used. If there is no default value, the default value is used to return the list of class names;

161 original articles published, praised 17, visited 6931
Private letter follow

Keywords: Spring Attribute SpringBoot solr

Added by Trium918 on Wed, 15 Jan 2020 12:26:23 +0200