springboot 2.0.0版本分析,總體的自動配置流程以下:html
具體配置參考官方文檔:springboot-docreact
核心註解@SpringBootConfiguration其實就是@Configuration註解,表示是個配置類;@EnableAutoConfiguration表示springboot的自動配置機制;@ComponentScan表示掃描容許註冊額外的配置類;web
@SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScanspring
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 { // 排除不會被應用的自動配置類,classes形式 @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude") Class<?>[] exclude() default {}; // 排除不會被應用的自動配置類,字符串數組形式 @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName") String[] excludeName() default {}; // 掃描基本包 @AliasFor(annotation = ComponentScan.class, attribute = "basePackages") String[] scanBasePackages() default {}; // 掃描基本類 @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") Class<?>[] scanBasePackageClasses() default {}; }
點擊@EnableAutoConfiguration
註解進入,看見@Import({AutoConfigurationImportSelector.class})是導入AutoConfigurationImportSelector類;apache
AutoConfigurationImportSelector
類是自動配置的核心類,其主要進行配置的功能是配置factory.properties
和 spring內嵌集成
引入的配置;數組
// 表示不引入配置 private static final String[] NO_IMPORTS = new String[0]; // 配置日誌 private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class); // 排除的自動配置 private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude"; // 聲明 beanFactory private ConfigurableListableBeanFactory beanFactory; // 聲明 environment (全局環境) private Environment environment; // 聲明 beanClassLoader (bean的類加載器,加載spring-autoconfigure-metadata.properties中集成類) private ClassLoader beanClassLoader; // 聲明 resourceLoader (資源加載器,加載spring的 factory.properties配置類) private ResourceLoader resourceLoader;
selectImports
這個方法的主要功能就是導入factory.properties
和 spring-autoconfigure-metadata.properties
中的配置類;springboot
public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { try { // 1 加載元數據信息,本質就是加載bean,這裏的bean是指我咱們spring-autoconfigure-metadata.properties中集成類 AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); // 2 AnnotationAttributes本質是個map AnnotationAttributes attributes = this.getAttributes(annotationMetadata); // 3 得到 spring.factories 中的配置類 List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); // 4 配置類複製用於排序不須要的配置類 configurations = this.removeDuplicates(configurations); // 優先級排序 configurations = this.sort(configurations, autoConfigurationMetadata); // 需移除配置類 Set<String> exclusions = this.getExclusions(annotationMetadata, attributes); // 校驗移除 this.checkExcludedClasses(configurations, exclusions); // 執行移除配置類 configurations.removeAll(exclusions); configurations = this.filter(configurations, autoConfigurationMetadata); this.fireAutoConfigurationImportEvents(configurations, exclusions); return StringUtils.toStringArray(configurations); } catch (IOException var6) { throw new IllegalStateException(var6); } } }
1 分析
AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);app
進入方法發現加載的元數據信息的路徑是 META-INF/spring-autoconfigure-metadata.properties
spring-boot
public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) { return loadMetadata(classLoader, "META-INF/spring-autoconfigure-metadata.properties"); }
在自動配置包底下找到spring-autoconfigure-metadata.properties
this
點進屬性文件發現都spring自動配置類名的配置信息,部分以下:
#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= ............................
咱們隨意點開其中的一個配置類,好比第一個HttpMessageConvertersAutoConfiguration
,其中的class註解以下,能夠發現其自動配置類都是經過註解配置;
// 表示配置類至關於xml中的 bean標籤 @Configuration // 斷定是否存在HttpMessageConverter.class類,若是不存在則引入 @ConditionalOnClass({HttpMessageConverter.class}) // 在這三個配置類配置以後再進行配置 @AutoConfigureAfter({GsonAutoConfiguration.class, JacksonAutoConfiguration.class, JsonbAutoConfiguration.class}) // 導入配置類至關於xml中的 import標籤 @Import({JacksonHttpMessageConvertersConfiguration.class, GsonHttpMessageConvertersConfiguration.class, JsonbHttpMessageConvertersConfiguration.class}) public class HttpMessageConvertersAutoConfiguration {
3 分析
this.getCandidateConfigurations(annotationMetadata, attributes);方法的主要功能是獲取候選配置;
進入getCandidateConfigurations方法發現裏面的主要方法是loadFactoryNames;
// 得到factory配置信息類名 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; }
進入 loadFactoryNames 方法 主要是2部分;第一個是loadSpringFactories(classLoader),第二個是getOrDefault
// 加載factory類名 public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); // 返回類名的list return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); }
第一部分:
loadSpringFactories本質就是使用spring的Resource資源調用得到 spring.factories
中的配置類;
// 加載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 { // 得到 `spring.factories` 配置類的URL Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); LinkedMultiValueMap result = new LinkedMultiValueMap(); // 將 `spring.factories` 每一個配置類的key 和 val 存儲進 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") ;中找到自動配置包中的配置以下圖:
spring.factories
裝載配置類部分信息以下,沒錯這些配置都是sping啓動須要的配置類信息,監聽器,過濾器,自動配置的start配置類,以及啓動的失敗的錯誤分析還有模板引擎的支持,詳細你們翻下配置包便可;
# Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener ....................................
第二部分:
getOrDefault是個Map集合,map中有這個key時,就使用這個key值,若是沒有就使用默認值defaultValue,返回也就是類名的list;