SpringBoot的自動裝配是拆箱即用的基礎,也是爲服務化的前提。java
前面一章我講解過了《SpringBoot進階之道-@SpringBootApplication》。咱們知道@SpringBootApplication包含了@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan。spring
在上一章我講解過《SpringBoot進階之道-@Enable模塊驅動》,這種@Enabelxx的註解是開啓某一項功能的註解,其原理是藉助@Import,將全部符合自動配置條件的bean定義加載到IOC容器。具體的能夠去看看。數組
那麼@EnableAutoConfiguration這個註解會開啓springboot自動裝配功能。直白的說,Spring會試圖在你的classpath下找到全部配置的Bean而後進行裝配。咱們以springboot2.x源碼爲例:springboot
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
複製代碼
從源碼咱們得知,關鍵是@Import({AutoConfigurationImportSelector.class}),藉助AutoConfigurationImportSelector,@EnableAutoConfiguration能夠幫助springboot應用將全部符合條件的@Configuration配置都加載到當前SpringBoot建立並使用的ioc容器。那麼我爲何這麼說呢?咱們看下AutoConfigurationImportSelector源碼:bash
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
...
public AutoConfigurationImportSelector() {
}
}
複製代碼
該類實現了DeferredImportSelector接口,而DeferredImportSelector是繼承了ImportSelector:框架
public interface ImportSelector {
String[] selectImports(AnnotationMetadata var1);
}
複製代碼
ImportSelector接口主要是爲了導入@Configuration的配置項,而DeferredImportSelector是延期導入,當全部的@Configuration都處理事後纔會執行。 咱們看看AutoConfigurationImportSelector實現的selectImports方法:工具
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 判斷是否進行自動裝配
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
//1加載META-INF/spring-autoconfigure-metadata.properties文件
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
//2獲取註解的屬性及其值(PS:註解指的是@EnableAutoConfiguration註解)
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//3.在classpath下全部的META-INF/spring.factories文件中查找org.springframework.boot.autoconfigure.EnableAutoConfiguration的值,並將其封裝到一個List中返回
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
//4.對上一步返回的List中的元素去重、排序
configurations = this.removeDuplicates(configurations);
//5.依據第2步中獲取的屬性值排除一些特定的類
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
//6.對上一步中所獲得的List進行過濾,過濾的依據是條件匹配。這裏用到的過濾器是
//org.springframework.boot.autoconfigure.condition.OnClassCondition最終返回的是一個ConditionOutcome[]數組。
//(PS:不少類都是依賴於其它的類的,當有某個類時纔會裝配,因此此次過濾的就是根據是否有某個
//class進而決定是否裝配的。這些類所依賴的類都寫在META-INF/spring-autoconfigure-metadata.properties文件裏)
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
....
public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
return loadMetadata(classLoader, "META-INF/spring-autoconfigure-metadata.properties");
}
}
複製代碼
從上面的源碼得知,該方法先判斷是否進行自動裝配,而後從META-INF/spring-autoconfigure-metadata.properties讀取元數據與元數據的相關屬性,而後調用getCandidateConfigurations方法:post
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;
}
複製代碼
這個時候咱們看到個Spring框架原有的一個工具類SpringFactoriesLoader,其主要的工做是從指定的META-INF/spring.factories加載配置,即根據@EnableAutoConfiguration的完整類名"org.springframework.boot.autoconfigure.EnableAutoConfiguration"做爲查找的Key,獲取對應的配置,經過反射獲得對應的一組@Configuration類。spring.factories中EnableAutoConfiguration以下:this
# 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.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
....
複製代碼
總結:自動裝配就是利用SpringFactoriesLoader從classpath中搜索全部的META-INF/spring.factories配置文件,並將其中org.springframework.boot.autoconfigure.EnableAutoConfiguration對應的配置項經過反射實例化爲標註了@Configuration的JavaConfig形式的配置類,而後彙總並加載到ioc容器。因此,之前咱們須要本身配置的東西,自動配置類都幫咱們完成了,是否是很嗨~~~spa