在Spring Boot 中咱們想要使用某個功能只須要在POM文件中添加對應的依賴。而後整個應用程序便具有了這個功能。那麼這是如何實現的呢?html
經過分析Spring Boot 示例程序來分析Spring Boot 自動配置原理。java
Spring Boot 應用啓動的時候,須要傳入一個標註@SpringBootApplication
註解,該註解是一個組合註解。spring
@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 { //省略 }
該註解是Spring Boot 對Spring 的@Configuration註解的一個包裝,它的做用就是表名被標註的類是一個配置類!這裏就不在過多描述,須要瞭解能夠經過查看官方文檔。springboot
該註解開啓了自動配置功能,它也是一個組合註解。app
@AutoConfigurationPackage @Import(EnableAutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
@AutoConfigurationPackage註解 配和 @ComponentScan 來決定Spring Boot 從那個包開始掃描組件,有怎樣的掃描規則等等。 咱們如今主要關心@Import(EnableAutoConfigurationImportSelector.class)
給應用帶來了什麼ide
@Import
註解的做用,已經在給IOC容器添加組件的幾種方式總結 作過介紹分析。 直接點擊EnableAutoConfigurationImportSelector
觀察,該類繼承了AutoConfigurationImportSelector
,關注這個類的selectImports
方法spring-boot
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } try { AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); AnnotationAttributes attributes = getAttributes(annotationMetadata); //獲取全部的候選配置信息 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); configurations = sort(configurations, autoConfigurationMetadata); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return configurations.toArray(new String[configurations.size()]); } catch (IOException ex) { throw new IllegalStateException(ex); } }
觀察getCandidateConfigurations
方法this
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); return configurations; }
觀察getSpringFactoriesLoaderFactoryClass
方法,該方法返回了EnableAutoConfiguration
的類類型url
protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }
返回到getCandidateConfigurations
這個方法,觀察loadFactoryNames
方法.net
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { //獲取EnableAutoConfiguration全限定名稱 String factoryClassName = factoryClass.getName(); try { //加載 類路徑下 META-INF文件夾中的spring.factories文件 Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); List<String> result = new ArrayList<String>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); //將spring.factories文件轉爲Properties文件 Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); //讀取key爲EnableAutoConfiguration全限定名稱對應的全部值 String factoryClassNames = properties.getProperty(factoryClassName); result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames))); } return result; } catch (IOException ex) { } }
這個常量FACTORIES_RESOURCE_LOCATION的值爲:META-INF/spring.factories
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\ org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\ org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\ org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\ ## 省略
再返回到selectImports
方法。實際上就是將這個配置文件中org.springframework.boot.autoconfigure.EnableAutoConfiguration
對應的值,按照必定的過濾規則,最後把他們交給了容器。 每個這樣的xxxAutoConfiguration類都是容器中的一個組件,而且它們都是一個配置類,當這些組件交給Spring容器管理,也就使得應用程序完成了自動配置。
分析完上述內容,就能夠自定義一個應用場景啓動器。具體步驟以下
spring.factories
文件。org.springframework.boot.autoconfigure.EnableAutoConfiguration
=自定義配置類的全限定名稱