| 每次問到 Spring Boot, 面試官非常喜歡問這個問題:“講述一下 SpringBoot 自動裝配原理?”。 我覺得我們可以從以下幾個方面回答: 
 篇幅問題,這篇文章并沒有深入,小伙伴們也可以直接使用 debug 的方式去看看 SpringBoot 自動裝配部分的源代碼。 前言使用過 Spring 的小伙伴,一定有被 XML 配置統(tǒng)治的恐懼。即使 Spring 后面引入了基于注解的配置,我們在開啟某些 Spring 特性或者引入第三方依賴的時候,還是需要用 XML 或 Java 進(jìn)行顯式配置。 舉個例子。沒有 Spring Boot 的時候,我們寫一個 RestFul Web 服務(wù),還首先需要進(jìn)行如下配置。 @Configurationpublic class RESTConfiguration{    @Bean
    public View jsonTemplate() {
        MappingJackson2JsonView view = new MappingJackson2JsonView();
        view.setPrettyPrint(true);        return view;
    }    @Bean
    public ViewResolver viewResolver() {        return new BeanNameViewResolver();
    }
}
 <beans xmlns="http://www./schema/beans" xmlns:xsi="http://www./2001/XMLSchema-instance" xmlns:context="http://www./schema/context" xmlns:mvc="http://www./schema/mvc" xsi:schemaLocation="http://www./schema/beans http://www./schema/beans/spring-beans.xsd http://www./schema/context/ http://www./schema/context/spring-context.xsd http://www./schema/mvc/ http://www./schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="com.howtodoinjava.demo" /> <mvc:annotation-driven /> <!-- JSON Support --> <bean name="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"/> <bean name="jsonTemplate" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/></beans> 但是,Spring Boot 項目,我們只需要添加相關(guān)依賴,無需配置,通過啟動下面的  @SpringBootApplicationpublic class DemoApplication {    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}并且,我們通過 Spring Boot 的全局配置文件  為什么 Spring Boot 使用起來這么酸爽呢? 這得益于其自動裝配。自動裝配可以說是 Spring Boot 的核心,那究竟什么是自動裝配呢? 什么是 SpringBoot 自動裝配?我們現(xiàn)在提到自動裝配的時候,一般會和 Spring Boot 聯(lián)系在一起。但是,實際上 Spring Framework 早就實現(xiàn)了這個功能。Spring Boot 只是在其基礎(chǔ)上,通過 SPI 的方式,做了進(jìn)一步優(yōu)化。 
 沒有 Spring Boot 的情況下,如果我們需要引入第三方依賴,需要手動配置,非常麻煩。但是,Spring Boot 中,我們直接引入一個 starter 即可。比如你想要在項目中使用 redis 的話,直接在項目中引入對應(yīng)的 starter 即可。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency> 引入 starter 之后,我們通過少量注解和一些簡單的配置就能使用第三方組件提供的功能了。 在我看來,自動裝配可以簡單理解為:通過注解或者一些簡單的配置就能在 Spring Boot 的幫助下實現(xiàn)某塊功能。 SpringBoot 是如何實現(xiàn)自動裝配的?我們先看一下 SpringBoot 的核心注解  @Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited<1.>@SpringBootConfiguration<2.>@ComponentScan<3.>@EnableAutoConfigurationpublic @interface SpringBootApplication {
}@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Configuration //實際上它也是一個配置類public @interface SpringBootConfiguration {
}大概可以把  
 
 @EnableAutoConfiguration:實現(xiàn)自動裝配的核心注解
 @Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage //作用:將main包下的所欲組件注冊到容器中@Import({AutoConfigurationImportSelector.class}) //加載自動裝配類 xxxAutoconfigurationpublic @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    Class<?>[] exclude() default {};
    String[] excludeName() default {};
}我們現(xiàn)在重點(diǎn)分析下 AutoConfigurationImportSelector:加載自動裝配類
 public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {}public interface DeferredImportSelector extends ImportSelector {
}public interface ImportSelector {
    String[] selectImports(AnnotationMetadata var1);
}可以看出, private static final String[] NO_IMPORTS = new String[0];public String[] selectImports(AnnotationMetadata annotationMetadata) {        // <1>.判斷自動裝配開關(guān)是否打開
        if (!this.isEnabled(annotationMetadata)) {            return NO_IMPORTS;
        } else {          //<2>.獲取所有需要裝配的bean
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }這里我們需要重點(diǎn)關(guān)注一下 該方法調(diào)用鏈如下: 現(xiàn)在我們結(jié)合 private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();
AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {        //<1>.
        if (!this.isEnabled(annotationMetadata)) {            return EMPTY_ENTRY;
        } else {            //<2>.
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);            //<3>.
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);            //<4>.
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.filter(configurations, autoConfigurationMetadata);            this.fireAutoConfigurationImportEvents(configurations, exclusions);            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }第 1 步: 判斷自動裝配開關(guān)是否打開。默認(rèn) 第 2 步 : 用于獲取 第 3 步 獲取需要自動裝配的所有配置類,讀取 spring-boot/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories 從下圖可以看到這個文件的配置內(nèi)容都被我們讀取到了。 不光是這個依賴下的 所以,你可以清楚滴看到, druid 數(shù)據(jù)庫連接池的 Spring Boot Starter 就創(chuàng)建了 如果,我們自己要創(chuàng)建一個 Spring Boot Starter,這一步是必不可少的。 第 4 步 : 到這里可能面試官會問你:“ 很明顯,這是不現(xiàn)實的。我們 debug 到后面你會發(fā)現(xiàn), 因為,這一步有經(jīng)歷了一遍篩選, @Configuration// 檢查相關(guān)的類:RabbitTemplate 和 Channel是否存在// 存在才會加載@ConditionalOnClass({ RabbitTemplate.class, Channel.class })@EnableConfigurationProperties(RabbitProperties.class)@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
}有興趣的童鞋可以詳細(xì)了解下 Spring Boot 提供的條件注解 
 如何實現(xiàn)一個 Starter光說不練假把式,現(xiàn)在就來擼一個 starter,實現(xiàn)自定義線程池 第一步,創(chuàng)建 第二步,引入 Spring Boot 相關(guān)依賴 第三步,創(chuàng)建 第四步,在 
 最后新建工程引入 
 測試通過?。。?/p> 
 總結(jié)Spring Boot 通過 | 
|  |