一、SpringBoot初體驗
一個典型的SpringBoot應用長什么樣子呢?如果我們使用http://start.spring.io/創建一個最簡單的依賴Web模塊的SpringBoot應用,一般情況下, 我們會得到一個SpringBoot應用的啟動類,如下面代碼所示:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;?SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args); }
}
所有的SpringBoot無論怎么定制,本質上與上面的啟動類代碼是一樣的,而以上代碼示例中,**Annotation定義(@SpringBootApplication)
和類定義 (SpringApplication.run)
**最為耀眼,那么要揭開SpringBoot應用的奧秘,很明顯的,我們只要先從這兩位開始就可以了。
二、@SpringBootApplication背后的秘密
@SpringBootApplication是一個"三體”結構,實際上它是一個復合 Annotation:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(...)
public @interface SpringBootApplication{
...
}
雖然定義使用了多個Annotation進行了原信息標注,但實際上重要的只有三個Annotation:
- @Configuration(@SpringBootConfiguration點開查看發現里面還是應用了@Configuration)
- @EnableAutoConfiguration
- @ComponentScan
所以,如果我們使用如下的SpringBoot啟動類,整個SpringBoot應用依然可以與之前的啟動類功能對等:
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
但每次都寫三個Annotation顯然過于繁瑣,所以寫一個@SpringBoot-Application這樣的一站式復合Annotation顯然更方便些。
1、@Configuration 創世紀
很多SpringBoot的代碼示例都喜歡在啟動類上直接標注@Configuration或者@SpringBootApplication,對于初接觸SpringBoot的開發者來說,其實這種做法不便于理解,如果我們將上面的SpringBoot啟動類拆分為兩個獨立的Java類,整個形勢就明朗了:
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class DemoConfiguration {@Beanpublic Controller controller() {return new Controller();}
}
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoConfiguration.class, args);}
}
2、@EnableAutoConfiguration的功效
@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容器。
借助于Spring框架原有的一個工具類:SpringFactoriesLoader的支持,@EnableAutoConfiguration
可以智能的自動配置功效才得以大功告成!
SpringFactoriesLoader 自動配置幕后英雄
Spring的SpringFactoriesLoader工廠的加載機制類似java提供的SPI機制一樣,是Spring提供的一種加載方式。只需要在classpath路徑下新建一個文件META-INF/spring.factories,并在里面按照Properties格式填寫好接口和實現類即可通過SpringFactoriesLoader來實例化相應的Bean。配置的格式為Key = Value形式,其中key可以是接口、注解、或者抽象類的全名。value為相應的實現類,當存在多個實現類時,用“,”進行分割。
對于 @EnableAutoConfiguration 來說,SpringFactoriesLoader 的用途稍 微不同 一些,其本意是為了提供SPI擴展的場景,而在@EnableAutoConfiguration的場景 中,它更多是提供了一種配置查找的功能支持,即根據@EnableAutoConfiguration 的完整類名 org.springframework.boot.autoconiigure.EnableAutoConfiguration 作為查找 的Key,獲取對應的一組?Configuration類。
所以,@EnableAutoConfiguration自動配置的魔法其實就變成了:從 classpath 中搜尋所有 META-INF/spring.factories 配置文件,并將其中 org.spring? framework.boot.autoconfigure.EnableAutoConfiguration 對應的配置項通過反射 (Java Reflection)實例化為對應的標注了 ?Configuration的JavaConfig形式的 IoC容器配置類,然后匯總為一個并加載到IoC容器。
3、@ComponentScan
@ComponentScan的功能其實就是自動掃描并加載符合條件的組件或bean定義,最終將這些bean定義加載到容器中。加載bean定義到Spring的IoC容器,當然我們也可以手工單個注冊
參考:
- 《SpringBoot揭秘+快速構建微服務體系》 第三章