【Spring Boot 系列 自動配置原理分析】

在Spring Boot 中咱們想要使用某個功能只須要在POM文件中添加對應的依賴。而後整個應用程序便具有了這個功能。那麼這是如何實現的呢?html

經過分析Spring Boot 示例程序來分析Spring Boot 自動配置原理。java

一、Spring Boot自動配置原理

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 {
  //省略
}

1.一、@SpringBootConfiguration註解

該註解是Spring Boot 對Spring 的@Configuration註解的一個包裝,它的做用就是表名被標註的類是一個配置類!這裏就不在過多描述,須要瞭解能夠經過查看官方文檔springboot

1.二、@EnableAutoConfiguration註解

該註解開啓了自動配置功能,它也是一個組合註解。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

1.三、分析@Import註解

@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

1.四、查看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容器管理,也就使得應用程序完成了自動配置。

1.五、擴展

分析完上述內容,就能夠自定義一個應用場景啓動器。具體步驟以下

  • 建立Maven工程,引入Spring Boot提供的最基本的配置
  • 建立自定義配置類
  • 在類路徑下建立META-INF文件夾,在該文件夾中建立spring.factories文件。
  • 在該文件中添加org.springframework.boot.autoconfigure.EnableAutoConfiguration=自定義配置類的全限定名稱
  • 打包,完成
相關文章
相關標籤/搜索