SpringBoot vsersion 2.2.6
1. SpringApplication.run (Application.class, args);
De este método como objeto de investigación
1.1 @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 {
...
@SpringBootApplication contiene tres anotaciones importantes @SpringBootConfiguration y @EnableAutoConfiguration @ComponentScan
1.2 @SpringBootConfiguration
La capa inferior es @Configuration annotation
@Configuration La clase actual como clase de configuración es equivalente a una etiqueta Beans. Puede usar @Bean para declarar múltiples Beans en el contenedor IOC con esta anotación.
1.3 @EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
// isEnabled用到了这个变量 去environment拿这个key值的value
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
...
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass() == AutoConfigurationImportSelector.class) {
return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
}
return true;
}
@AutoConfigurationPackage Esta anotación importa una ruta de exploración registrada @Import (AutoConfigurationPackages.Registrar.class) a la variable global
@Import (AutoConfigurationImportSelector.class)
1.4 AutoConfigurationImportSelector
selectImports -> getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
//spring.boot.enableautoconfiguration environment里的这个key值为false 返回空
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获取注解的属性值
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 获取spring.factories里的 org.springframework.boot.autoconfigure.EnableAutoConfiguration的value集合名称
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 去重
configurations = removeDuplicates(configurations);
// 收集排除的类名
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
// 去排除的数据
configurations.removeAll(exclusions);
// 由所有AutoConfigurationImportFilter类的实例再进行一次筛选
configurations = filter(configurations, autoConfigurationMetadata);
// 绑定事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
}
重点: starter 原理
selectImports -> getAutoConfigurationEntry -> getCandidateConfigurations
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 相当于Spring的SPI 约定META-INF/spring.factories 读取里面的配置信息
// 核心发现配置类的方法 loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader)
// factoryType -> EnableAutoConfiguration.class
// 发现factory.factories里面的这个org.springframework.boot.autoconfigure.EnableAutoConfiguration这个key的value的类
// 自定义的starter也是利用了这个SPI的机制 网上自定义的starter的demo很多
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;
}
2. SpringgApplication
Constructor SpringgApplication
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// servlet REACTIVE NONE webApplication属性
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// spring.factories 初始化类
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// spring.factories 监听类
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
SpringApplication.run
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// java.awt.headless是J2SE的一种模式用于在缺少显示屏、键盘或者鼠标时的系统配置,很多监控工具如jconsole 需要将该值设置为true,系统变量默认为true
configureHeadlessProperty();
// 从META-INF/spring.factories中获取监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
// 封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 构造应用上下文环境,完成后回调SpringApplicationRunListeners的environmentPrepared方法
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 处理需要忽略的Bean
configureIgnoreBeanInfo(environment);
// 打印banner
Banner printedBanner = printBanner(environment);
// 创建webApplication容器
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] {
ConfigurableApplicationContext.class }, context);
// 准备上下文环境,将environment保持到IOC容器中
// 执行applyInitializers 回调ApplicationContextInitializer的initialize方法
// 回调SpringApplicationRunListeners的contextPrepared方法
// 回调SpringApplicationRunListeners的contextLoaded方法
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 完成组件的扫描,创建,加载等
refreshContext(context);
// 从beanFactory获取所有的ApplicationRunner
// CommandLinedRunner进行回调
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, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}