Blog

  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

springboot启动配置原理

发表于 2019-08-20 更新于 2019-08-23 分类于 SpringBoot 阅读次数:
本文字数: 6.1k

启动类

1
2
3
4
5
6
7
@SpringBootApplication
public class SpringbootDay1Application {

public static void main(String[] args) {
SpringApplication.run(SpringbootDay1Application.class, args);
}
}

其中有一个@SpringBootApplication注解和SpringApplication.run(SpringbootDay1Application.class, args)方法。

@SpringBootApplication注解

1
2
3
4
5
6
@SpringBootConfiguration  //里面就是一个@Configuration注解
@EnableAutoConfiguration //开启自动装配
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {}

@SpringBootConfiguration

1
2
@Configuration
public @interface SpringBootConfiguration {}

其实就是一个@Configuration注解

@EnableAutoConfiguration

1
2
3
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
@AutoConfigurationPackage
1
2
3
4
5
6
7
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {}
//AutoConfigurationPackages.Registrar
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}

将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器;

@Import(AutoConfigurationImportSelector.class)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//将META-INF/spring.factories配置的org.springframework.boot.autoconfigure.EnableAutoConfiguration找出来
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
configurations = sort(configurations, autoConfigurationMetadata);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}

将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中;会给容器中导入非常多的自动配置类(xxxAutoConfiguration),就是所谓的自动装配类

SpringApplication.run()方法

1
2
3
4
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}

可以发现,首先会new 一个SpringApplication对象,然后再调用此对象的run方法。

new SpringApplication

1
2
3
4
5
6
7
8
9
10
11
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//判断是否是web项目
this.webApplicationType = deduceWebApplicationType();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}

这里的setInitializers()和setListeners()方法是通过SpringFactoriesLoader找到spring.factories文件中配置的ApplicationContextInitializer和ApplicationListener两个接口的实现类。

  • ApplicationContextInitializer的主要目的是在ConfigurableApplicationContext做refresh之前,对ConfigurableApplicationContext实例做进一步的设置或处理。
  • ApplicationListener是Spring框架对Java事件监听机制的一种框架实现。

run()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//获取SpringApplicationRunListeners;从类路径下META‐INF/spring.factori
SpringApplicationRunListeners listeners = getRunListeners(args);
//回调所有的获取SpringApplicationRunListener.starting()方法
listeners.starting();
try {
//封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
//根据是否是web应用创建不同的ioc容器
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//1.将准备好的Environment设置给ApplicationContext
//2.遍历调用所有的ApplicationContextInitializer的initialize()方法来对已经创建好的ApplicationContext进行进一步的处理
//3.将所有的bean加载到容器中
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//刷新容器,就和spring中refresh()方法一样。
//ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);Spring注解版
//扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
refreshContext(context);
//从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, listeners, exceptionReporters, ex);
throw new IllegalStateException(ex);
}
listeners.running(context);
//返回ioc容器
return context;
}

总结

在启动方法中,调用run()方法,其中首先创建一个SpringApplication对象,然后再调用此对象的run方法,在run()方法中,先初始化一下环境,然后创建一个容器,然后将所有的组件(配置类,自定义组件,还有@SpringBootApplication注解中的自动装配的类)放入ioc容器中。


------ 已触及底线感谢您的阅读 ------
麻辣香锅不要辣 微信支付

微信支付

  • 本文作者: 麻辣香锅不要辣
  • 本文链接: https://http://ybhub.gitee.io/2019/08/20/springboot启动配置原理/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
# SpringBoot
SpringBoot自动装配--嵌入式Servlet容器
springboot-----cache
  • 文章目录
  • 站点概览
麻辣香锅不要辣

麻辣香锅不要辣

21 日志
11 分类
20 标签
GitHub 简书
  1. 1. 启动类
    1. 1.1. @SpringBootApplication注解
      1. 1.1.1. @SpringBootConfiguration
      2. 1.1.2. @EnableAutoConfiguration
        1. 1.1.2.1. @AutoConfigurationPackage
        2. 1.1.2.2. @Import(AutoConfigurationImportSelector.class)
    2. 1.2. SpringApplication.run()方法
      1. 1.2.1. new SpringApplication
      2. 1.2.2. run()
  2. 2. 总结
© 2019 – 2020 麻辣香锅不要辣 | 站点总字数: 20.4k字
|
0%