構建Springboot項目時咱們會建立一個啓動類java
@SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
1. 在以前使用Spring框架時,咱們通常會建立web.xml和spring-context.xml等文件配置組件掃描、調度器、視圖解析器等。web
2. 而在SpringBoot中則簡單了不少,這裏就有自動配置發揮做用。如默認用的內嵌式容器是 Tomcat ,端口默認設置爲 8080spring
首先看@SpringBootApplication這個註解sql
@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) }) @ConfigurationPropertiesScan public @interface SpringBootApplication { }
@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 {}; }
@EnableAutoConfiguration的做用是開啓自動配置數組
這就是Spring Boot自動配置實現的核心入口,重頭戲是@Import註解,這個註解導入了AutoConfigurationImportSelector類,利用AutoConfigurationImportSelector(自動配置導入選擇器)將全部符合自動裝配條件的bean注入到IOC容器中app
Springboot應用啓動過程當中使用ConfigurationClassParser分析配置類時,發現註解中存在@Import(ImportSelector)的狀況。框架
就會建立一個相應的ImportSelector對象, 並調用其方法 public String[] selectImports(AnnotationMetadata annotationMetadata)dom
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { // 省略。。 @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { // 1 判斷是否開啓自動配置,爲false直接返回空字符數組
if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; }
// 2 loadMetadata()去加載Spring預先定義的自動配置的依賴信息,下面會具體說明
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader);
// 3 該方法返回的就是配置項信息,下面會具體說明 AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } // 省略。。。 }
2. loadMetadata()去加載Spring預先定義的自動配置的依賴信息ide
1 static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) { 2 try { 3 Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path) 4 : ClassLoader.getSystemResources(path); 5 Properties properties = new Properties(); 6 while (urls.hasMoreElements()) { 7 properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement()))); 8 } 9 return loadMetadata(properties); 10 } 11 catch (IOException ex) { 12 throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex); 13 } 14 }
path的地址是this
protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";
裏面的自動配置文件(部分)
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration.AutoConfigureBefore=org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration.ConditionalOnClass=javax.sql.DataSource,org.springframework.batch.core.launch.JobLauncher org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
2.1 根據path獲取文件的URL對象
2.2 遍歷URL節點,將spring-autoconfigure-metadata.properties中的依賴信息加載到properties對象中
2.3 調用loadMetadata()方法把properties存儲到PropertiesAutoConfigurationMetadata類中
3. 在這裏面會調用一個方法getAutoConfigurationEntry(),該方法返回的就是配置項信息,進入這個方法
1 protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, 2 AnnotationMetadata annotationMetadata) { // 3.1
3 if (!isEnabled(annotationMetadata)) { 4 return EMPTY_ENTRY; 5 } // 3.2
6 AnnotationAttributes attributes = getAttributes(annotationMetadata); // 3.3
7 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); // 3.4
8 configurations = removeDuplicates(configurations); // 3.5
9 Set<String> exclusions = getExclusions(annotationMetadata, attributes); 10 checkExcludedClasses(configurations, exclusions); 11 configurations.removeAll(exclusions); 12 configurations = filter(configurations, autoConfigurationMetadata); // 3.6
13 fireAutoConfigurationImportEvents(configurations, exclusions); // 3.7
14 return new AutoConfigurationEntry(configurations, exclusions); 15 }
3.1 判斷是否開啓自動配置
3.2 getAttributes()方法獲取@SpringBootApplication(主要是爲了獲取@EnableAutoConfiguation)註解上的屬性
3.3 加載META-INF/spring.factories文件, 這個文件配置了具備哪些自動配置類,文件內容以下 ,具體代碼以下
getCandidateConfigurations方法以下
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), 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; }
3.3.1 getSpringFactoriesLoaderFactoryClass方法返回EnableAutoConfiguration.class
3.3.2 SpringFactoriesLoader.loadFactoryNames會加載META-INF/spring.factories中EnableAutoConfiguration的值中定義的jar包,並將其封裝到一個List中返回
3.4 removeDuplicates() 用LinkedHashSet去重,在包裝成ArrayList
3.5 getExclusions()、checkExcludedClasses()、removeAll()、filter() 過濾註解中要排除的自動配置
3.6 fireAutoConfigurationImportEvents() 將自動配置導入監聽
3.7 返回配置的AutoConfigurationEntry包裝類
經過 @EnableAutoConfiguration
核心註解初始化,並掃描 ClassPath 目錄中自動配置類。根據項目中須要添加的默認配置,如springMVC,就按必定規則獲取默認配置並自動初始化所須要的 Bean。
1. 核心是@EnableAutoConfiguration
2. 裏面會經過@Import註解導入(AutoConfigurationImportSelector.class)類
3. 調用importSelect方法,進行自動配置
3.1 判斷是否開啓了自動配置
3.2 getAutoConfigurationEntry方法會使用
SpringFactoriesLoader.loadFactoryNames方法加載classpath中spring.factories文件中EnableAutoConfiguration的配置類
3.3 通過去重,排除後會把這些配置導入監聽
@EnableAutoConfiguration
@Import
AutoConfigurationImportSelector類
selectImports方法
SpringFactoriesLoader.loadFactoryNames() 核心方法讀取 ClassPath 目錄下面的 META-INF/spring.factories 文件。
spring.factories 文件中存放springBoot自動配置類, 如Servlet、jpa
在spring.factories中org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguratio
做用是:SpringBoot 自動配置DataSource
// 表示這是一個配置類 @Configuration(proxyBeanMethods = false) // 判斷當前項目classpath有沒有這兩個類 DataSource EmbeddedDatabaseType @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) // 將配置文件中對應的值和 DataSourceProperties 綁定起來,並把DataSourceProperties的屬性值放到ioc容器中 @EnableConfigurationProperties(DataSourceProperties.class) // 導入數據源註冊類、數據源初始化類 @Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class }) public class DataSourceAutoConfiguration { // 省略。。 }
查看DataSourceProperties屬性,提供的這些屬性,就能夠獲取到在application.yml中提供的值來設置數據源了
@ConfigurationProperties(prefix = "spring.datasource") public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean { private ClassLoader classLoader; /** * Name of the datasource. Default to "testdb" when using an embedded database. */ private String name; /** * Whether to generate a random datasource name. */ private boolean generateUniqueName; /** * Fully qualified name of the connection pool implementation to use. By default, it * is auto-detected from the classpath. */ private Class<? extends DataSource> type; /** * Fully qualified name of the JDBC driver. Auto-detected based on the URL by default. */ private String driverClassName; /** * JDBC URL of the database. */ private String url; /** * Login username of the database. */ private String username; /** * Login password of the database. */ private String password; /** * JNDI location of the datasource. Class, url, username & password are ignored when * set. */ private String jndiName; 。。。省略 }
Spring Boot 內部提供了不少自動化配置的類, 配置類會更加classpath下是否又相關依賴類,來判斷是否要配置字節,因此當咱們在pom中引入了相關依賴,就能夠自動配置了
====== 【多學一點,for Better】======