首先咱們來看一個最簡單的例子。java
咱們先建立一個SpringBoot的工程,如何建立一個SpringBoot工程就不說了,不會請自行解決。而後寫一個controller類,經過請求路徑,返回HelloWorld在瀏覽器頁面上顯示。程序員
上面兩張圖就是程序的一個總體的結構和運行的結果,那麼問題來了,SpringBoot程序中沒有任何配置,不像Spring框架,寫一大堆配置信息在xml文件中,那麼程序是怎麼將咱們這裏的Controller類掃描到spring容器中的呢?spring
首先第一點,咱們來看一下SpringBoot的啓動類,瀏覽器
package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { //啓動SpringBoot應用 SpringApplication.run(DemoApplication.class, args); } }
其中,咱們看到一個註解@SpringBootApplication,SpringBoot應用標註在某個類上說明這個類是SpringBoot的主配置類,SpringBoot就應該運行這個類的main方法來啓動SpringBoot應用;框架
而後咱們點進去看看這個註解到底包含了什麼,ide
@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 {
其中咱們須要重點關注的就是@SpringBootConfiguration、@EnableAutoConfiguration學習
下面咱們逐個來說解:url
@SpringBootConfiguration這個註解顧名思義,標註在某個類上,這個類就是SpringBoot的配置類,咱們再點進去看看。debug
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration
原來這個註解是底層是Spring中的註解@Configuration,而@Configuration註解底層就是一個@Component,表明一個容器。xml
SpringBoot的精髓是在@EnableAutoConfiguration這個註解上,根據名字,咱們能夠知道這是一個自動配置類,也就是可以實現一些自動配置的功能,那麼具體是配置了什麼東西呢?
咱們再點進去看看
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class)
咱們看見了和這個註解有關聯的重要的兩個註解@AutoConfigurationPackage,@Import(AutoConfigurationImportSelector.class),也是分別給你們講解一下。
1.@AutoConfigurationPackage
@AutoConfigurationPackage:這是一個自動配置的包,咱們來看下在這個程序中是配置了哪一個包,點進來
@Import(AutoConfigurationPackages.Registrar.class)
再點到Register,咱們看到在大概123行的位置,有一段代碼。
@Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { register(registry, new PackageImport(metadata).getPackageName()); }
咱們看到這個方法器中一個參數metadata,表明註解的元信息,而後咱們經過這個註解的元信息來獲這個包名,咱們在這打個斷點,debug運行,能夠看見一些元信息的基本內容,最主要咱們要知道是導入了哪一個包,咱們選中new PackageImport(metadata).getPackageName(),右鍵計算一下
發現導入的包就是咱們項目的根目錄,假如咱們新建一個包叫com.controller,在裏面寫一個controller類,你們能夠運行的試一下是否能成功呢。
2.@Import(AutoConfigurationImportSelector.class)
@Import(AutoConfigurationImportSelector.class):這個註解表明的是一個自動配置的選擇器,那麼要導入哪些組件的選擇器呢?
咱們點進去,看到很是重要的一段。
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }
這裏咱們得到到了一個configurations 的list集合,咱們打個斷點看看這個集合中到底給咱們裝了些什麼東西。
咱們發現這個configurations 裏面裝配了124個自動配置類,原來咱們沒有配置的一些信息,都經過SpringBoot的自動配置類給我配置好了。
那麼我還想知道這些類SpringBoot程序給咱們放到哪了呢,咱們看到getCandidateConfigurations(annotationMetadata, attributes);
點進去,咱們看到:
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass()
那麼再點進去咱們看看到底加載的工廠名稱是啥,
try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryTypeName = ((String) entry.getKey()).trim(); for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryTypeName, factoryImplementationName.trim()); } } }
咱們看到其中類加載器給咱們獲取了資源,咱們點進去,
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
原來這些自動配置類都在類路徑下的"META-INF/spring.factories"
還有下面的autoconfigure包中的內容,咱們也看看
這裏面咱們全部所用到的配置類所有由SpringBoot給咱們配置了,因此咱們知道SpringBoot表面上是零配置的,其實底層都給咱們封裝好了,也是方便咱們程序員進行開發。
那麼有些人確定又有疑惑,SpringBoot怎麼知道給咱們自動配置哪些類呢?
欲知後事如何,請關注一下做者,純手打碼字不易,也是但願和你們多多交流,一塊兒學習,謝謝!