SpringBoot Application注解原理及代碼詳解
1、SpringBoot 啟動(dòng)main()
@SpringBootApplication
public class TomcatdebugApplication {
public static void main(String[] args) {
SpringApplication.run(TomcatdebugApplication.class, args);
}
}
1.1 @SpringBootApplication 注解,其實(shí)主要是@ComponentScan,@EnableAutoConfiguration,@SpringBootConfiguration三個(gè)注解

@ComponentScan 注解:
spring里有四大注解:@Service,@Repository,@Component,@Controller用來(lái)定義一個(gè)bean.@ComponentScan注解就是用來(lái)自動(dòng)掃描被這些注解標(biāo)識(shí)的類(lèi),最終生成ioc容器里的bean.
可以通過(guò)設(shè)置@ComponentScan basePackages,includeFilters,excludeFilters屬性來(lái)動(dòng)態(tài)確定自動(dòng)掃描范圍,類(lèi)型已經(jīng)不掃描的類(lèi)型.
默認(rèn)情況下:它掃描所有類(lèi)型,并且掃描范圍是@ComponentScan注解所在配置類(lèi)包及子包的類(lèi)
@SpringBootConfiguration 注解:
@SpringBootConfiguration繼承自@Configuration,二者功能也一致,標(biāo)注當(dāng)前類(lèi)是配置類(lèi),
并會(huì)將當(dāng)前類(lèi)內(nèi)聲明的一個(gè)或多個(gè)以@Bean注解標(biāo)記的方法的實(shí)例納入到spring容器中,并且實(shí)例名就是方法名。
demo 說(shuō)明:
(1) 注入spring ioc bean
@SpringBootConfiguration
public class Config {
@Bean
public Map createMap(){
Map map = new HashMap();
map.put("username","gxz");
map.put("age",27);
return map;
}
}
(2)調(diào)用:
public static void main( String[] args )
{
//方式1 獲取context
ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
context.getBean(Runnable.class).run();
context.getBean("createMap"); //注意這里直接獲取到這個(gè)方法bean
int age = (int) map.get("age");
System.out.println("age=="+age);
//方式2. 使用@Autowired注解,應(yīng)用bean
// @Autowired// Map createMap
}
@EnableAutoConfiguration 注解
@EnableAutoConfiguration作用:從classpath中搜索所有的META-INF/spring.factories配置文件,然后將其中key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的value加載到spring容器中。

上圖分析源碼可知: @EnableAutoConfiguration = @Import + @AutoConfigurationPackage
@AutoConfigurationPackage:主要作用是自動(dòng)配置包
@Import: Spring底層注解@Import,給容器中導(dǎo)入一個(gè)組件;導(dǎo)入的組件由AutoConfigurationPackages.Registrar.class將主配置類(lèi)(@SpringBootApplication標(biāo)注的類(lèi))的所在包以及下面所有子包里面的所有組件掃描到Spring容器。
AutoConfigurationImportSelector的作用是導(dǎo)入哪些組件的選擇器。將所有需要導(dǎo)入的組件以全類(lèi)名的方式返回,這些組件就會(huì)被添加到容器中;也會(huì)給容器導(dǎo)入非常多的自動(dòng)配置類(lèi)(xxxAutoConfiguration),就是給容器中導(dǎo)入這個(gè)場(chǎng)景需要的所有組件,并配置好這些組件。
有了自動(dòng)配置類(lèi),免去了我們手動(dòng)編寫(xiě)配置注入功能組件等的工作
具體工作流程圖:

@EnableAutoConfiguration加載過(guò)程
自動(dòng)配置主要由AutoConfigurationImportSelector實(shí)現(xiàn)的,我們主要從這個(gè)類(lèi)開(kāi)始講起。AutoConfigurationImportSelector是@EnableAutoConfiguration“@Import”的DeferredImportSelector實(shí)現(xiàn)類(lèi),由于DeferredImportSelector作為ImportSelector的子接口,所以組件自動(dòng)配置邏輯均在selectImports(AnnotationMetadata)方法中實(shí)現(xiàn)
源碼分析:
AutoConfigurationImportSelector.java
根據(jù)以上代碼分析自動(dòng)配置加載過(guò)程主要分為以下幾個(gè)步驟:
1.判斷是否開(kāi)啟自動(dòng)配置
2.從META-INF/spring-autoconfigure-metadata.properties文件中載入屬性配置
3.獲取所有的配置列表
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//1.是否開(kāi)啟自動(dòng)配置,默認(rèn)開(kāi)啟
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
try {
//2.從META-INF/spring-autoconfigure-metadata.properties文件中載入屬性配置(有一些有默認(rèn)值),獲取注解信息
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
//3.獲取所有的配置列表
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
configurations = this.sort(configurations, autoConfigurationMetadata);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return (String[])configurations.toArray(new String[configurations.size()]);
} catch (IOException var6) {
throw new IllegalStateException(var6);
}
}
}
1.是否開(kāi)啟自動(dòng)配置,默認(rèn)開(kāi)啟
protected boolean isEnabled(AnnotationMetadata metadata) {
return true;
}
2.從META-INF/spring-autoconfigure-metadata.properties文件中載入屬性配置
protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";
private AutoConfigurationMetadataLoader() {
}
public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
return loadMetadata(classLoader, "META-INF/spring-autoconfigure-metadata.properties");
}
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources(path) : ClassLoader.getSystemResources(path);
Properties properties = new Properties();
while(urls.hasMoreElements()) {
properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource((URL)urls.nextElement())));
}
return loadMetadata(properties);
} catch (IOException var4) {
throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", var4);
}
}
3、獲取所有的配置列表
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
String name = this.getAnnotationClass().getName();
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
Assert.notNull(attributes, "No auto-configuration attributes found. Is " + metadata.getClassName() + " annotated with " + ClassUtils.getShortName(name) + "?");
return attributes;
}
總結(jié):
springboot底層實(shí)現(xiàn)自動(dòng)配置的步驟:
1.springboot應(yīng)用啟動(dòng)
2.@SpringBootApplication起作用
3.@EnableAutoConfiguration
4.@AutoConfigurationPackage:這個(gè)組合注解主要是@Import(AutoConfigurationPackages.Registrar.class),它通過(guò)將Registrar類(lèi)導(dǎo)入到容器中,而Registrar類(lèi)作用是掃描主配置類(lèi)同級(jí)目錄以及子包,并將相應(yīng)的組件導(dǎo)入到springboot創(chuàng)建管理的容器中
5.@Import(AutoConfigurationImportSelector.class):它通過(guò)將AutoConfigurationImportSelector類(lèi)導(dǎo)入到容器中,AutoConfigurationImportSelector類(lèi)作用是通過(guò)selectImports方法實(shí)現(xiàn)將配置類(lèi)信息交給SpringFactory加載器進(jìn)行一系列的容器創(chuàng)建過(guò)程,具體實(shí)現(xiàn)可查看上面的源碼
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Springboot基于BCrypt非對(duì)稱(chēng)加密字符串的實(shí)現(xiàn)
本文主要介紹了Springboot基于BCrypt非對(duì)稱(chēng)加密字符串的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
Spring項(xiàng)目中使用Junit單元測(cè)試并配置數(shù)據(jù)源的操作
這篇文章主要介紹了Spring項(xiàng)目中使用Junit單元測(cè)試并配置數(shù)據(jù)源的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
SpringBoot實(shí)現(xiàn)mysql與clickhouse多數(shù)據(jù)源的項(xiàng)目實(shí)踐
本文主要介紹了SpringBoot實(shí)現(xiàn)mysql與clickhouse多數(shù)據(jù)源的項(xiàng)目實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-11-11
java普通類(lèi)如何轉(zhuǎn)javafx程序
這篇文章主要介紹了java普通類(lèi)如何轉(zhuǎn)javafx程序方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
Java設(shè)計(jì)模式之簡(jiǎn)單工廠 工廠方法 抽象工廠深度總結(jié)
設(shè)計(jì)模式(Design Pattern)是前輩們對(duì)代碼開(kāi)發(fā)經(jīng)驗(yàn)的總結(jié),是解決特定問(wèn)題的一系列套路。它不是語(yǔ)法規(guī)定,而是一套用來(lái)提高代碼可復(fù)用性、可維護(hù)性、可讀性、穩(wěn)健性以及安全性的解決方案2021-09-09
MyBatis 參數(shù)類(lèi)型為String時(shí)常見(jiàn)問(wèn)題及解決方法
這篇文章主要介紹了MyBatis 參數(shù)類(lèi)型為String時(shí)常見(jiàn)問(wèn)題及解決方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-03-03
Map如何根據(jù)key指定條件進(jìn)行過(guò)濾篩選
這篇文章主要介紹了Map如何根據(jù)key指定條件進(jìn)行過(guò)濾篩選問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
java8 如何實(shí)現(xiàn)分組計(jì)算數(shù)量和計(jì)算總數(shù)
這篇文章主要介紹了java8 如何實(shí)現(xiàn)分組計(jì)算數(shù)量和計(jì)算總數(shù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07

