Spring Boot 自動裝配原理及 Starter 實現(xiàn)原理解析
1、Situation
傳統(tǒng) Spring 引入依賴時需要用 XML 或 Java 顯式配置,非常繁瑣。
2、Target
方便快捷地引入依賴或者配置屬性。
3、Action
3.1 @SpringBootApplication源碼解析
@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 { @AliasFor(annotation = EnableAutoConfiguration.class) Class<?>[] exclude() default {}; @AliasFor(annotation = EnableAutoConfiguration.class) String[] excludeName() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "basePackages") String[] scanBasePackages() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") Class<?>[] scanBasePackageClasses() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator") Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; @AliasFor(annotation = Configuration.class) boolean proxyBeanMethods() default true; } -------------------------------------------------------- @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration @Indexed public @interface SpringBootConfiguration { @AliasFor( annotation = Configuration.class ) boolean proxyBeanMethods() default true; } ------------------------------------------------------- @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 {}; }
主要有SpringBootConfiguration、EnableAutoConfiguration、ComponentScan三個注解構成。
- ComponentScan 注解的作用是掃描啟動類所在的包以及子包所有Bean組件并注冊到 IOC 容器中,其中 excludeFilters 指定了一個過濾器列表,通過兩個過濾器排除某些類,比如我們可以繼承 TypeExcludeFilter 并重寫 match 方法來自定義給排除哪些類。
- SpringConfiguration 注解的作用就是標記 SpringBoot 啟動類為一個配置類。
- EnableAutoConfiguration 是實現(xiàn)自動裝配的核心注解,通過@Import 注解導入 AutoConfigurationImportSelector 類
3.2 AutoConfigurationImportSelector 源碼
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { //1.判斷自動裝配開關是否打開 if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } //2.獲取所有需要裝配的bean AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { //1.再次判斷自動裝配開關是否打開 if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } //2.獲取EnableAutoConfiguration注解中的 exclude 和 excludeName AnnotationAttributes attributes = getAttributes(annotationMetadata); //3.獲取需要自動裝配的所有配置類,讀取META-INF/spring.factories //(不止讀取當前項目中的META-INF文件,所有的依賴中的META-INF文件都會被讀取) List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); //4.刪除重復依賴、過濾 exclude 的依賴 configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); } ... } ------------------------------------------------------ public interface DeferredImportSelector extends ImportSelector { } ------------------------------------------------------- public interface ImportSelector { String[] selectImports(AnnotationMetadata var1); }
AutoConfigurationImportSelector 實現(xiàn)了 ImportSelector 的selectImports 方法,顧名思義就是篩選引入的依賴,那么就需要加載所有的依賴,以及條件,再根據(jù)條件對依賴進行篩選。
4、Result
通過 Spring Boot 啟動類上的 @SpringBootApplication 注解,Spring 就可以遍歷所有 META-INF 的 spring.factories 文件中的配置類,并根據(jù) @EnableAutoConfiguration 的條件選擇是否將其注冊為 bean。
5、面試回答
啟動類的@SpringBootApplication注解由@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan三個注解組成,三個注解共同完成自動裝配;
- @SpringBootConfiguration 注解標記啟動類為配置類
- @ComponentScan 注解實現(xiàn)啟動時掃描啟動類所在的包以及子包下所有標記為bean的類由IOC容器注冊為bean
- @EnableAutoConfiguration 通過 @Import 注解導入
- AutoConfigurationImportSelector類,然后通過AutoConfigurationImportSelector 類的 selectImports
- 方法去讀取需要被自動裝配的組件依賴下的spring.factories文件配置的組件的類全名,并按照一定的規(guī)則過濾掉不符合要求的組件的類全名,將剩余讀取到的各個組件的類全名集合返回給IOC容器并將這些組件注冊為bean。
6、實現(xiàn) Starter 的步驟
創(chuàng)建 Spring Boot 工程,添加項目需要的依賴,Spring Configuration Processor 這個依賴可以幫助開發(fā)者自動生成配置的的代碼提示。
刪除 pom.xml 的 build 部分
創(chuàng)建 Config 文件
在 resources 文件夾下新建 META-INF 文件夾,然后新建 spring.factories 文件,編寫配置項為自動引入配置的類。
之后可以對這個項目打包,在其他的項目中通過pom.xml文件的坐標引入這個項目
在 AutoConfigurationImportSelector 中也可以發(fā)現(xiàn)com.example.demo.DemoConfiguration 類已經(jīng)被成功加載了。
到此這篇關于Spring Boot 自動裝配原理及 Starter 實現(xiàn)的文章就介紹到這了,更多相關Spring Boot 自動裝配內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
java 基礎之final、finally和finalize的區(qū)別
這篇文章主要介紹了java 基礎之final、finally和finalize的區(qū)別的相關資料,需要的朋友可以參考下2017-05-05Java 高并發(fā)三:Java內(nèi)存模型和線程安全詳解
本文主要介紹Java高并發(fā)內(nèi)存模型和線程安全的資料,這里整理詳細的資料及1.原子性 2.有序性 3.可見性 4.Happen-Before 5.線程安全的概念,有需要的小伙伴可以參考下2016-09-09java web中 HttpClient模擬瀏覽器登錄后發(fā)起請求
這篇文章主要介紹了java web中 HttpClient模擬瀏覽器登錄后發(fā)起請求的相關資料,需要的朋友可以參考下2017-05-05spring boot項目打包成war在tomcat運行的全步驟
這篇文章主要給大家介紹了關于spring boot項目打包成war在tomcat運行的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用spring boot具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2019-04-04java并發(fā)編程專題(五)----詳解(JUC)ReentrantLock
這篇文章主要介紹了java(JUC)ReentrantLock的的相關資料,文中講解非常詳細,實例代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下2020-07-07SpringBoot開發(fā)案例之打造私有云網(wǎng)盤的實現(xiàn)
這篇文章主要介紹了SpringBoot開發(fā)案例之打造私有云網(wǎng)盤的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-04-04淺談web服務器項目中靜態(tài)請求和動態(tài)請求處理
這篇文章主要介紹了淺談web服務器項目中靜態(tài)請求和動態(tài)請求處理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-07-07