今天跟大家來(lái)探討下SpringBoot的核心注解@SpringBootApplication以及run方法,理解下springBoot為什么不需要XML,達(dá)到零配置
首先我們先來(lái)看段代碼
@SpringBootApplication
public class StartEurekaApplication
{
public static void main(String[] args)
{
SpringApplication.run(StartEurekaApplication.class, args);
}
}
我們點(diǎn)進(jìn)@SpringBootApplication來(lái)看
@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 {
}
上面的元注解我們?cè)谶@里不在做解釋?zhuān)嘈糯蠹以陂_(kāi)發(fā)當(dāng)中肯定知道,我們要來(lái)說(shuō)@SpringBootConfiguration @EnableAutoConfiguration 這兩個(gè)注解,到這里我們知道 SpringBootApplication注解里除了元注解,我們可以看到又是@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan的組合注解,官網(wǎng)上也有詳細(xì)說(shuō)明,那我們現(xiàn)在把目光投向這三個(gè)注解。
首先我們先來(lái)看 @SpringBootConfiguration,那我們點(diǎn)進(jìn)來(lái)看
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
我們可以看到這個(gè)注解除了元注解以外,就只有一個(gè)@Configuration,那也就是說(shuō)這個(gè)注解相當(dāng)于@Configuration,所以這兩個(gè)注解作用是一樣的,那他是干嘛的呢,相信很多人都知道,它是讓我們能夠去注冊(cè)一些額外的Bean,并且導(dǎo)入一些額外的配置。那@Configuration還有一個(gè)作用就是把該類(lèi)變成一個(gè)配置類(lèi),不需要額外的XML進(jìn)行配置。所以@SpringBootConfiguration就相當(dāng)于@Configuration。
那我們繼續(xù)來(lái)看下一個(gè)@EnableAutoConfiguration,這個(gè)注解官網(wǎng)說(shuō)是 讓Spring自動(dòng)去進(jìn)行一些配置,那我們點(diǎn)進(jìn)來(lái)看
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
可以看到它是由 @AutoConfigurationPackage,@Import(EnableAutoConfigurationImportSelector.class)這兩個(gè)而組成的,我們先說(shuō)@AutoConfigurationPackage,他是說(shuō):讓包中的類(lèi)以及子包中的類(lèi)能夠被自動(dòng)掃描到spring容器中。 我們來(lái)看@Import(EnableAutoConfigurationImportSelector.class)這個(gè)是核心,之前我們說(shuō)自動(dòng)配置,那他到底幫我們配置了什么,怎么配置的?
就和@Import(EnableAutoConfigurationImportSelector.class)息息相關(guān),程序中默認(rèn)使用的類(lèi)就自動(dòng)幫我們找到。我們來(lái)看EnableAutoConfigurationImportSelector.class
public class EnableAutoConfigurationImportSelector
extends AutoConfigurationImportSelector {
@Override
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass().equals(EnableAutoConfigurationImportSelector.class)) {
return getEnvironment().getProperty(
EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class,
true);
}
return true;
}
}
可以看到他繼承了AutoConfigurationImportSelector我們繼續(xù)來(lái)看AutoConfigurationImportSelector,這個(gè)類(lèi)有一個(gè)方法
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List
這個(gè)類(lèi)會(huì)幫你掃描那些類(lèi)自動(dòng)去添加到程序當(dāng)中。我們可以看到getCandidateConfigurations()這個(gè)方法,他的作用就是引入系統(tǒng)已經(jīng)加載好的一些類(lèi),到底是那些類(lèi)呢,我們點(diǎn)進(jìn)去看一下
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
這個(gè)類(lèi)回去尋找的一個(gè)目錄為META-INF/spring.factories,也就是說(shuō)他幫你加載讓你去使用也就是在這個(gè)META-INF/spring.factories目錄裝配的,他在哪里?
我們點(diǎn)進(jìn)spring.factories來(lái)看
我們可以發(fā)現(xiàn)幫我們配置了很多類(lèi)的全路徑,比如你想整合activemq,或者說(shuō)Servlet
可以看到他都已經(jīng)幫我們引入了進(jìn)來(lái),我看隨便拿幾個(gè)來(lái)看
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\\
org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\\
比如我們經(jīng)常用的security,可以看到已經(jīng)幫你配置好,所以我們的EnableAutoConfiguration主要作用就是讓你自動(dòng)去配置,但并不是所有都是創(chuàng)建好的,是根據(jù)你程序去進(jìn)行決定。 那我們繼續(xù)來(lái)看
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM,
classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM,
classes = AutoConfigurationExcludeFilter.class) })
這個(gè)注解大家應(yīng)該都不陌生,掃描包,放入spring容器,那他在springboot當(dāng)中做了什么策略呢?我們可以點(diǎn)跟煙去思考,幫我們做了一個(gè)排除策略,他在這里結(jié)合SpringBootConfiguration去使用,為什么是排除,因?yàn)椴豢赡芤簧蟻?lái)全部加載,因?yàn)閮?nèi)存有限。
那么我們來(lái)總結(jié)下@SpringbootApplication:就是說(shuō),他已經(jīng)把很多東西準(zhǔn)備好,具體是否使用取決于我們的程序或者說(shuō)配置,那我們到底用不用?那我們繼續(xù)來(lái)看一行代碼
public static void main(String[] args)
{
SpringApplication.run(StartEurekaApplication.class, args);
}
那們來(lái)看下在執(zhí)行run方法到底有沒(méi)有用到哪些自動(dòng)配置的東西,比如說(shuō)內(nèi)置的Tomcat,那我們來(lái)找找內(nèi)置Tomcat,我們點(diǎn)進(jìn)run
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
然后他調(diào)用又一個(gè)run方法,我們點(diǎn)進(jìn)來(lái)看
public ConfigurableApplicationContext run(String... args) {
//計(jì)時(shí)器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
//監(jiān)聽(tīng)器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
//準(zhǔn)備上下文
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
//預(yù)刷新context
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//刷新context
refreshContext(context);
//刷新之后的context
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
那我們關(guān)注的就是 refreshContext(context); 刷新context,我們點(diǎn)進(jìn)來(lái)看
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
我們繼續(xù)點(diǎn)進(jìn)refresh(context);
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
-
XML
+關(guān)注
關(guān)注
0文章
188瀏覽量
33773 -
spring
+關(guān)注
關(guān)注
0文章
340瀏覽量
15118 -
Boot
+關(guān)注
關(guān)注
0文章
153瀏覽量
36780 -
注解
+關(guān)注
關(guān)注
0文章
18瀏覽量
2775 -
SpringBoot
+關(guān)注
關(guān)注
0文章
175瀏覽量
408
發(fā)布評(píng)論請(qǐng)先 登錄
Spring Boot的注解原理是什么
Spring Boot中常見(jiàn)的各類(lèi)型注解的使用方式
Spring Boot常用注解與使用方式
求一種SpringBoot定時(shí)任務(wù)動(dòng)態(tài)管理通用解決方案
Java注解及其底層原理解析 1

什么是 SpringBoot?

SpringBoot常用注解及使用方法1
SpringBoot常用注解及使用方法2
Springboot常用注解合集

SpringBoot常用注解及原理
SpringBoot的核心注解2

評(píng)論