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;