概念:可以在咱們添加jar包依賴的時候,自動爲咱們配置一些組件的相關配置,咱們無需配置或者只須要少許配置就能運行編寫的項目java
問題:Spring Boot究竟是如何進行自動配置的,都把哪些組件進行了自動配置?spring
Spring Boot應用的啓動入口是@SpringBootApplication註解標註類中的main()方法, @SpringBootApplication可以掃描Spring組件並自動配置Spring Boot springboot
下面,查看@SpringBootApplication內部源碼進行分析 ,核心代碼具體以下框架
@SpringBootApplication public class SpringbootDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringbootDemoApplication.class, args); } }
@Target({ElementType.TYPE}) //註解的適用範圍,Type表示註解能夠描述在類、接口、註解或枚舉中 @Retention(RetentionPolicy.RUNTIME) //表示註解的生命週期,Runtime運行時 @Documented //表示註解能夠記錄在javadoc中 @Inherited //表示能夠被子類繼承該註解 @SpringBootConfiguration // 標明該類爲配置類 @EnableAutoConfiguration // 啓動自動配置功能 @ComponentScan( // 包掃描器 excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication { ... }
從上述源碼能夠看出,@SpringBootApplication註解是一個組合註解,前面 4 個是註解的元數據信息, 咱們主要看後面 3 個註解:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三個核心註解,關於這三個核心註解的相關說明具體以下:工具
1.@SpringBootConfiguration註解源碼分析
@SpringBootConfiguration註解表示Spring Boot配置類。查看@SpringBootConfiguration註解源碼,核心代碼具體以下。url
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration //配置IOC容器 public @interface SpringBootConfiguration { }
從上述源碼能夠看出,@SpringBootConfiguration註解內部有一個核心註解@Configuration,該註解是Spring框架提供的,表示當前類爲一個配置類(XML配置文件的註解表現形式),並能夠被組件掃描器掃描。因而可知,@SpringBootConfiguration註解的做用與@Configuration註解相同,都是標識一個能夠被組件掃描器掃描的配置類,只不過@SpringBootConfiguration是被Spring Boot進行了從新封裝命名而已 spa
2.@EnableAutoConfiguration註解code
@EnableAutoConfiguration註解表示開啓自動配置功能,該註解是Spring
Boot框架最重要的註解,也是實現自動化配置的註解。一樣,查看該註解內部查看源碼信息,核心代碼具體以下 對象
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-0iesyK1X-1591594952790)(./images/image-20191226121755878.png)]
能夠發現它是一個組合註解,Spring 中有不少以Enable開頭的註解,其做用就是藉助@Import來收集並註冊特定場景相關的bean,並加載到IoC容器。@EnableAutoConfiguration就是藉助@Import來收集全部符合自動配置條件的bean定義,並加載到IoC容器。
下面,對這兩個核心註解分別講解 :
(1)@AutoConfigurationPackage註解
查看@AutoConfigurationPackage註解內部源碼信息,核心代碼具體以下:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import({Registrar.class}) // 導入Registrar中註冊的組件 public @interface AutoConfigurationPackage { }
從上述源碼能夠看出,@AutoConfigurationPackage註解的功能是由@Import註解實現的,它是spring框架的底層註解,它的做用就是給容器中導入某個組件類,例如@Import(AutoConfigurationPackages.Registrar.class),它就是將Registrar這個組件類導入到容器中,可查看Registrar類中registerBeanDefinitions方法,這個方法就是導入組件類的具體實現 :
從上述源碼能夠看出,在Registrar類中有一個registerBeanDefinitions()方法,使用Debug模式啓動項目, 能夠看到選中的部分就是com.lagou。也就是說,@AutoConfigurationPackage註解的主要做用就是將主程序類所在包及全部子包下的組件到掃描到spring容器中。
所以 在定義項目包結構時,要求定義的包結構很是規範,項目主程序啓動類要定義在最外層的根目錄位置,而後在根目錄位置內部創建子包和類進行業務開發,這樣纔可以保證定義的類可以被組件掃描器掃描
(2)@Import({AutoConfigurationImportSelector.class}):將AutoConfigurationImportSelector這個類導入到spring容器中,AutoConfigurationImportSelector能夠幫助springboot應用將全部符合條件的@Configuration配置都加載到當前SpringBoot建立並使用的IoC容器(ApplicationContext)中
繼續研究AutoConfigurationImportSelector這個類,經過源碼分析這個類中是經過selectImports這個方法告訴springboot都須要導入那些組件:
[
深刻研究loadMetadata方法
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-LudWoPn0-1591594952801)(./images/image-20200119172325325.png)]
深刻getCandidateConfigurations方法
個方法中有一個重要方法loadFactoryNames,這個方法是讓SpringFactoryLoader去加載一些組件的名字。
繼續點開loadFactory方法
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { //獲取出入的鍵 String factoryClassName = factoryClass.getName(); return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } 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 { //若是類加載器不爲null,則加載類路徑下spring.factories文件,將其中設置的配置類的全路徑信息封裝 爲Enumeration類對象 Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); LinkedMultiValueMap result = new LinkedMultiValueMap(); //循環Enumeration類對象,根據相應的節點信息生成Properties對象,經過傳入的鍵獲取值,在將值切割爲一個個小的字符串轉化爲Array,方法result集合中 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(); String factoryClassName = ((String)entry.getKey()).trim(); String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); int var10 = var9.length; for(int var11 = 0; var11 < var10; ++var11) { String factoryName = var9[var11]; result.add(factoryClassName, factoryName.trim()); } } } cache.put(classLoader, result); return result;
會去讀取一個 sprin g.factories 的文件,讀取不到會表這個錯誤,咱們繼續根據會看到,最終路徑的長這樣,而這個是spring提供的一個工具類
public final class SpringFactoriesLoader { public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; }
它實際上是去加載一個外部的文件,而這文件是在
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-jxnhPKHT-1591594952805)(./images/image-20191226162644636.png)]
@EnableAutoConfiguration就是從classpath中搜尋META-INF/spring.factories配置文件,並將其中org.springframework.boot.autoconfigure.EnableutoConfiguration對應的配置項經過反射(Java Refletion)實例化爲對應的標註了@Configuration的JavaConfig形式的配置類,並加載到IOC容器中
以剛剛的項目爲例,在項目中加入了Web環境依賴啓動器,對應的WebMvcAutoConfiguration自動配置類就會生效,打開該自動配置類會發現,在該配置類中經過全註解配置類的方式對Spring MVC運行所需環境進行了默認配置,包括默認前綴、默認後綴、視圖解析器、MVC校驗器等。而這些自動配置類的本質是傳統Spring MVC框架中對應的XML配置文件,只不過在Spring Boot中以自動配置類的形式進行了預先配置。所以,在Spring Boot項目中加入相關依賴啓動器後,基本上不須要任何配置就能夠運行程序,固然,咱們也能夠對這些自動配置類中默認的配置進行更改
總結
所以springboot底層實現自動配置的步驟是:
5.
@Import(AutoConfigurationImportSelector.class):它經過將AutoConfigurationImportSelector類導入到容器中,AutoConfigurationImportSelector類做用是經過selectImports方法執行的過程當中,會使用內部工具類SpringFactoriesLoader,查找classpath上全部jar包中的META-INF/spring.factories進行加載,實現將配置類信息交給SpringFactory加載器進行一系列的容器建立過程
3. @ComponentScan註解
@ComponentScan註解具體掃描的包的根路徑由Spring Boot項目主程序啓動類所在包位置決定,在掃描過程當中由前面介紹的@AutoConfigurationPackage註解進行解析,從而獲得Spring
Boot項目主程序啓動類所在包的具體位置
總結:
@SpringBootApplication 的註解的功能就分析差很少了, 簡單來講就是 3 個註解的組合註解:
|- @SpringBootConfiguration |- @Configuration //經過javaConfig的方式來添加組件到IOC容器中 |- @EnableAutoConfiguration |- @AutoConfigurationPackage //自動配置包,與@ComponentScan掃描到的添加到IOC |- @Import(AutoConfigurationImportSelector.class) //到META-INF/spring.factories中定義的bean添加到IOC容器中 |- @ComponentScan //包掃描