1、SpringBoot 自動配置(裝配)
- 原理是什麼?
https://blog.csdn.net/u014745069/article/details/83820511
- 爲什麼要有?
2、SpringBoot 是如何把一些庫加入到IOC中的?
@Component、@Configuration 適用於自定義業務,而SpringBoot考慮的是如何把第三方以及自己的庫加入到IOC中
@SpringBootApplication 就是一個超級大的配置類,其中包含的註解會分解小的配置類模塊
3、@EnableAutoConfiguration :SpringBoot中最核心的註解
主要作用就是爲了加載N多的Bean,然後將其放入IOC中
部分的屬性是寫在配置文件中的,允許從配置文件中更改配置的Bean的屬性等
必須要能把Bean加入到IOC中
@Import(AutoConfigurationImportSlector.class)
AutoConfigurationImportSlector 中有一個非常重要的方法:selectImports
- 核心方法,用於加載第三方配置類
要加載的所有的配置都在spring.factories中記錄,SpringBoot 會讀取該文件所有的Bean,然後再將這些Bean加入到IOC中
spring.factories 中的配置類與SpringBoot的自動加載機制是如何關聯起來的?
- 核心就是 .factories 配置文件
4、第三方的Bean也加了 @Configuration,爲什麼還要通過 @EnabledAutoConfiguration + .factories 的機制加入到IOC中?
如果只是加了 @Configuration ,相當於直接把源碼加入到了IOC中
第三方SDK也直接將源碼加入到IOC中嗎?顯然不可能
5、以Enabled 開頭的註解,被稱之爲模塊裝配
模塊裝配:假設要注入MongoDB,那麼就加上@Configuration註解,有可能一個配置類沒辦法解決某個方向的問題,往往是很多@Configuration的類組合在一起
SpringBoot是使用Enable註解,然後再通過@import導入Selector,通過Selector讀取 .factories 文件,最終加載的Configuration
6、@EnableAutoConfiguration 最終還是要加載@Configuration
比起自定義@Configuration ,還多了一步@Import的Selector
7、
修改前面的 HeroConfiguration 類,並將所有的@Component去掉
@Configuration
public class HeroConfiguration {
//@Bean
public ISkill diana(){
return new Diana("Diana", 1);
}
@Bean
public ISkill irelia(){
return new Irelia();
}
}
但現在的結構仍然可以自動將HeroConfiguration 加載到IOC中,因爲啓動類的@SpringBootApplication包含了ComponentScan,當前包下的標註了@Component/@Configuration的都會被加入到IOC中
自定義一個 啓動類 LOLApplication,並將啓動類的@SpringBootApplication註解去掉
@ComponentScan
public class LolApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(LolApplication.class)
.run(args);
ISkill iSkill = (ISkill) context.getBean("irelia");
iSkill.r();
}
}
使用另一種@Import方式
- 最簡單的一種方式就是,將配置類傳入到Import中
@Import(HeroConfiguration.class)
此時會報錯,unable to start web service,爲什麼加@ComponentScan就可以?
在默認情況下,上下文會啓動Web服務器,如果不主動關閉Web服務器的模式,它就會自動啓動
之所以加@ComponentScan可以,是因爲該註解會掃描和web服務器相關配置的
但註釋之後使用@Import只是導入了一個配置類,所以很多SpringBoot內置的配置都是沒有導入到IOC中
增加WebApplicationType.NONE 把服務器關閉
@Import(HeroConfiguration.class)
public class LolApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(LolApplication.class)
.web(WebApplicationType.NONE)
.run(args);
ISkill iSkill = (ISkill) context.getBean("irelia");
iSkill.r();
}
}
@Import 第二個用法
- 傳入的參數增加一個Selector
新增一個Selector:LolConfigurationSelector
public class LolConfigurationSelector implements ImportSelector {
/**
* 該接口要求返回一個數組,這個數組是一個字符串類型
* @param annotationMetadata
* @return
*/
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
/**
* 其實還是在返回元類的名字,一次可以導入多個配置類
*/
return new String[] {HeroConfiguration.class.getName()};
}
}
更改啓動類 LolApplication
@Import(LolConfigurationSelector.class)
public class LolApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(LolApplication.class)
.web(WebApplicationType.NONE)
.run(args);
ISkill iSkill = (ISkill) context.getBean("irelia");
iSkill.r();
}
}
7、SpringBoot自動裝配的spring.factories文件
新建一個Enable 註解類:EnableLolConfiguration(相當於一個模塊裝配)
元註解需要標註一些註解
@Retention(RetentionPolicy.RUNTIME) :用來修飾註解,是註解的註解 @Target(ElementType.TYPE) : 被描述的註解可以用在什麼地方 @Documented : 表明這個註釋是由 javadoc記錄的
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(LolConfigurationSelector.class)
public @interface EnableLolConfiguration {
}
修改 LolApplication
@EnableLolConfiguration
public class LolApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(LolApplication.class)
.web(WebApplicationType.NONE)
.run(args);
ISkill iSkill = (ISkill) context.getBean("irelia");
iSkill.r();
}
}
8、@EnableAutoConfiguration 爲什麼要從 .factories 文件讀取?
一個模塊具體要加載哪些配置類,是一個變化的過程。
既然是變化,那麼就應該被隔離到配置文件中
但不是所有在 .factories 文件中的配置都會被導入,所以這些配置文件中的類被稱爲 候選配置類
滿足一定條件之後,配置類纔會被導入到IOC中
AutoConfigurationImportSelector中有一個很重要的方法就是:getCandidateConfigurations(獲取所有的候選配置類名)
9、Java SPI 機制解析
SpringBoot自動裝配機制其實是SPI機制/思想的應用
SPI 機制/思想:
- Service Provider Interface (服務發現機制)
SPI 就是應對變化,一個系統中往往會依賴很多模塊,這些模塊又是有各種各樣不同實現方案的,有時候需要靈活的替換實現方案
首先有調用方,再有標準服務接口,服務接口下可能會有很多不同的實現(方案A、方案B),不同的方案遵循標準的服務接口,就可以被調用方調用;換句話說就是
在Java中SPI,等同於基於接口編程。不基於Interface接口編程,無法提供標準服務接口,也無法將衆多方案的具體隱藏在抽象之後
SpringBoot自動加載機制就是SPI機制/思想的衍生
對於一個方案來說,完全可以通過修改 .factories文件去切換不同的配置類,切換不同配置類的實質就是在切換衆多的方案之一
10、再談如何解決變化?
既然有了@Primary、條件註解之後,爲什麼還要有SPI機制/思想?
首先肯定的是,無論是SPI 還是@Primary、條件註解機制,都是爲了解決變化而生
但是兩者關注模塊的細粒度是不一樣的
- @Primary、條件註解 關注的是類/對象層面的變化,關注的具體/粒度非常小
- SPI 關注的點非常抽象,是整體解決方案的切換;有時候通過簡單的類替換是沒辦法解決問題的
舉個栗子
- 裝修的時候將1木質地板換成大理石地板(@Primary、條件註解)
- 房子的整體裝修風格發生了變化(SPI)
兩者應對變化沒有明顯的界限
11、SpringBoot自動裝配到底做了一件什麼事情?
SpringBoot 較其他框架多出了一個IOC容器,SpringBoot自動裝配真正解決了如何發現這些Bean並把這些配置的Bean要能夠加入到IOC容器中,如果沒有IOC,則需要手動在XML指定