1前言
在hello world中已經(jīng)啟動(dòng)了一個(gè)最精簡(jiǎn)的springboot 應(yīng)用.從我們編寫的代碼來看,它與非spring boot應(yīng)用區(qū)別有兩個(gè)地方:
(1)在QuickStartApplication
類上添加了注解@SpringBootApplication
;
(2)是main方法調(diào)用SpringApplication.run(QuickStartApplication.class,args)
這篇博客主要分享第一點(diǎn)卿樱,注解@SpringBootApplication
.分享的時(shí)候,我也是按照自己閱讀源碼的方式(每個(gè)人都有自己方法摸航,方式.不喜勿噴).
2進(jìn)入主題
我用IDEA進(jìn)行開發(fā),所以使用快捷鍵也是IDEA的.下面就是demo里代碼
@SpringBootApplication
public class QuickStartApplication {
public static void main(String[]args){
SpringApplication.run(QuickStartApplication.class,args);
}
}
進(jìn)入到@SpringBootApplication
的源碼柴墩,可以看到里面組合了三個(gè)我們感興趣的注解:@ComponentScan
,@EnableAutoConfiguration
,@SpringBootConfiguration
.我們一一分析這三個(gè)注解.
2.1@ComponentScan
使用過spring框架的小伙伴都知道忙厌,spring里有四大注解:@Service
,@Repository
,@Component
,@Controller
用來定義一個(gè)bean.@ComponentScan
注解就是用來自動(dòng)掃描被這些注解標(biāo)識(shí)的類凫岖,最終生成ioc容器里的bean.可以通過設(shè)置@ComponentScan
basePackages江咳,includeFilters,excludeFilters屬性來動(dòng)態(tài)確定自動(dòng)掃描范圍哥放,類型已經(jīng)不掃描的類型.默認(rèn)情況下:它掃描所有類型歼指,并且掃描范圍是@ComponentScan
注解所在配置類包及子包的類,在hello word 工程里甥雕,添加了一個(gè)componentscan 分支,說明這個(gè)情況.QuickStartApplication
,CurrentPackageController
類的package是com.simos.componentscan
.SubPackageController
的package 是com.simos.componentscan.controller
.而OutPackageController
的package是com.simos.controller
.啟動(dòng)后只有:SubPackageController
踩身,CurrentPackageController
被掃描生成bean,而OutPackageController
卻沒有被掃描到.下面三個(gè)截圖說明了這一點(diǎn):
總結(jié)一下社露,使用
@SpringBootApplication
注解挟阻,就說明你使用了@ComponentScan
的默認(rèn)配置,這就建議你把使用@SpringBootApplication
注解的類放置在root package(官方表述)下,其他類都置在root package的子包里面附鸽,這樣bean就不會(huì)被漏掃描.
2.2@SpringBootConfiguration
這個(gè)注解的作用與@Configuration
作用相同脱拼,都是用來聲明當(dāng)前類是一個(gè)配置類.可以通過@Bean
注解生成IOC容器管理的bean.在QuickStartApplication
中定義bean,并在@HelloController
中注入使用
@SpringBootApplication
public class QuickStartApplication {
public static void main(String[]args){
SpringApplication.run(QuickStartApplication.class,args);
}
@Bean
public BeanTest beanTest(){
return new BeanTest();
}
}
下面是@HelloController
@RestController
public class HelloController {
@Autowired
BeanTest beanTest;
@RequestMapping(value = "/hello",method = RequestMethod.GET)
public String hello(){
return "hello world!";
}
@RequestMapping(value = "/beantest",method = RequestMethod.GET)
public String beanTest(){
return "beanTest!";
}
}
2.3@EnableAutoConfiguration
@EnableAutoConfiguration
是springboot實(shí)現(xiàn)自動(dòng)化配置的核心注解坷备,通過這個(gè)注解把spring應(yīng)用所需的bean注入容器中.@EnableAutoConfiguration
源碼通過@Import
注入了一個(gè)ImportSelector
的實(shí)現(xiàn)類
AutoConfigurationImportSelector
,這個(gè)ImportSelector
最終實(shí)現(xiàn)根據(jù)我們的配置熄浓,動(dòng)態(tài)加載所需的bean.
'AutoConfigurationImportSelector'的完成動(dòng)態(tài)加載實(shí)現(xiàn)方法源碼如下:
@Override
//annotationMetadata 是@import所用在的注解.這里指定是@EnableAutoConfiguration
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//加載XXConfiguration的元數(shù)據(jù)信息(包含了某些類被生成bean條件),繼續(xù)跟進(jìn)這個(gè)方法調(diào)用省撑,就會(huì)發(fā)現(xiàn)加載的是:spring-boot-autoconfigure jar包里面META-INF的spring-autoconfigure-metadata.properties
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
//獲取注解里設(shè)置的屬性赌蔑,在@SpringBootApplication設(shè)置的exclude,excludeName屬性值,其實(shí)就是設(shè)置@EnableAutoConfiguration的這兩個(gè)屬性值
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//從spring-boot-autoconfigure jar包里面META-INF/spring.factories加載配置類的名稱竟秫,打開這個(gè)文件發(fā)現(xiàn)里面包含了springboot框架提供的所有配置類
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
//去掉重復(fù)項(xiàng)
configurations = removeDuplicates(configurations);
//獲取自己配置不需要生成bean的class
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
//校驗(yàn)被exclude的類是否都是springboot自動(dòng)化配置里的類娃惯,如果存在拋出異常
checkExcludedClasses(configurations, exclusions);
//刪除被exclude掉的類
configurations.removeAll(exclusions);
//過濾刷選,滿足OnClassCondition的類
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
//返回需要注入的bean的類路徑
return StringUtils.toStringArray(configurations);
}
3小結(jié)
通過第二節(jié)我們可以看到肥败,springboot是通過注解@EnableAutoConfiguration
的方式石景,去查找,過濾拙吉,加載所需的configuration
,@ComponentScan
掃描我們自定義的bean,@SpringBootConfiguration
使得被@SpringBootApplication
注解的類聲明為注解類.因此@SpringBootApplication
的作用等價(jià)于同時(shí)組合使用@EnableAutoConfiguration
潮孽,@ComponentScan
,@SpringBootConfiguration
.