整個springboot并沒有在spring的基礎(chǔ)上提供什么額外的功能琐鲁。
從開發(fā)人員的角度來看,springBoot的最大作用就是引入某些jar包后人灼,自動為spring上下文環(huán)境生成某些特定功能的Bean围段,這樣就可以自動提供某些相關(guān)功能。
從實現(xiàn)的角度來看投放,spring通過被標(biāo)記了@Configuration的類提供一些提前生成好的Bean提供特別的功能奈泪,而用@Contional系列的注解限制生成的條件,通常就是@ConditionalOnClass和@ConditionalOnMissingBean注解的配合使用。前者確定某些功能需要的class已經(jīng)有了涝桅,后者確定你沒有自己生成相關(guān)的bean拜姿,才提供默認(rèn)的。
可以使用@AutoConfigureBefore冯遂,@AutoConfigureAfter,@AutoconfigureOrder 來確定某個自動注冊類的生效順序。作用類比@Order容为。
自動注冊一般提供2個module:一個是autoconfigure jar包瘤礁,一個是starter jar包。其中starter這種jar里面并沒有代碼裸准,是空的儒洛。唯一的作用是將需要的各種jar寫入構(gòu)建文件,這樣引入此starter狼速,就不要再去關(guān)心相應(yīng)的其他jar了琅锻。
springboot自己的starter實現(xiàn)是這么干的。
SpringCloudNetflixZuul是將這兩者統(tǒng)一于一個module中來實現(xiàn)的
?
主要分成以下三個場景:
-
@Configuration配置類在程序可以掃描到的package里向胡,也就是@ComponentScan注解所指定的package里恼蓬。SpringBoot工程天然支持該類配置類注入方式。
最佳實踐:
//@SpringBootApplication注解中含有@ComponentScan 1 @SpringBootApplication 2 public class Application { 3 public static void main(String[] args) { 4 SpringApplication.run(Application.class, args); 5 } 6 }
-
@Configuration配置類沒有在package掃描路徑下僵芹,即不是項目開發(fā)人員自己編寫的代碼处硬。
比如制作第三方包供他人在springboot項目中使用,如RPC框架拇派、starter工程荷辕、spring-cloud-netflix-zuul等。
最佳實踐:
1件豌、編寫AutoConfiguration配置類
2疮方、在META-INF/spring.factories里用org.springframework.boot.autoconfigure.EnableAutoConfiguration來指定。
?
spring-boot-autoconfigure包里的配置類都是通過這種方式引入的茧彤。
示例:
用于在項目中導(dǎo)入的第三方包spring-cloud-netflix-zuul
引入spring-cloud-netflix-zuul的demo項目(實際是通過spring-cloud-starter-zuul引入的)
當(dāng)然骡显,這個方式需要程序使用@EnableAutoConfiguration注解,這個注解是通過AutoConfigurationImportSelector來掃描spring.factories文件曾掂,把定義的配置類引入的惫谤。
讀取spring.factories文件的實現(xiàn)
是通過org.springframework.core.io.support.SpringFactoriesLoader實現(xiàn)的。
SpringFactoriesLoader的實現(xiàn)類似于SPI(Service Provider Interface)java SPI提供一種服務(wù)發(fā)現(xiàn)機(jī)制珠洗,為某個接口尋找服務(wù)實現(xiàn)的機(jī)制溜歪。
有點類似IOC的思想,就是將裝配的控制權(quán)移到程序之外许蓖,在模塊化設(shè)計中這個機(jī)制尤其重要蝴猪。
?
實現(xiàn)說明:
1 @SpringBootApplication
2 public class Application {
3 public static void main(String[] args) {
4 SpringApplication.run(Application.class, args);
5 }
6 }
這是springboot項目中應(yīng)用最常見的啟動方式富岳,核心有兩個:
- @SpringBootApplication注解
- SpringApplication.run()靜態(tài)方法
和我們此處討論有關(guān)系的是注解@SpringBootApplication
@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 {....}
@ComponentScan,spring的自動掃描注解拯腮,對應(yīng)方法一窖式。
@EnableAutoConfiguration:借助@Import的幫助,將所有符合自動配置條件的bean定義加載到IoC容器(建議放在根包路徑下动壤,這樣可以掃描子包和類)
@EnableAutoConfiguration源碼如下:
@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {....}
其核心是一個EnableAutoConfigurationImportSelector類
public class EnableAutoConfigurationImportSelector
extends AutoConfigurationImportSelector {...}
核心方法在頂級接口ImportSelector的selectImports()的實現(xiàn)上萝喘,源碼如下:
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
//1.從META-INF/spring-autoconfigure-metadata.properties文件中載入配置屬性(有一些有默認(rèn)值)
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
//2.獲取注解屬性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//3.獲取自動配置類
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
//4.移除重復(fù)的
configurations = removeDuplicates(configurations);
//5.排序
configurations = sort(configurations, autoConfigurationMetadata);
//6.排出需要排出的
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
//6.過濾器OnClassCondition(注解中配置存在某類才生效)
configurations = filter(configurations, autoConfigurationMetadata);
//7.觸發(fā)自動配置導(dǎo)入監(jiān)聽事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
-
使用@Import注解
這個注解可以引入三種類
-
使用了@Configuration注解的類
如spring-cloud-netflix中ZuulProxyAutoConfiguration通過@import導(dǎo)入了若干個被@Configuration注解的類
-
ImportSelector的子類(嚴(yán)格說來這不屬于被@Configuration標(biāo)注的配置類這一前提,但也屬于springboot自動配置能力的一種琼懊,故羅列在此)
如@EnableAutoConfiguration中所引入的EnableAutoConfigurationImportSelector
-
ImportBeanDefinitionRegistrar的子類
{todo}
-