继承springboot父工程依赖pox.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
spring-boot-starter-parent继承了spring-boot-dependencies
- 这个依赖中定义了常用依赖的版本,以及锁定了其版本,所以我们在导入starter时,无需定义版本
- 若没有在这里定义版本,则需要自己导入相应的版本信息,如mysql的jdbc驱动
starter【web】启动器
<!-- 导入了web模块正常运行所依赖的组件,DispatcherServlet,内置tomcat容器等等-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
spring-boot-starter-web:
<!--
这是springboot的基础依赖,基本所有的启动器都依赖于spring-boot-starter。
其依赖内容包括自动配置,日志,注解,spring核心,yaml等。
导入了相应的starter后,springboot就会自动配置其运行组件
springboot官方定义的启动器依赖都是以 spring-boot-starter 开头的。【spring-boot-starter-xxx】
如果官方没有定义,其他技术需要集成springboot,则需要自己定义启动器依赖,如 mybatis 【mybatis-spring-boot-starter】
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.8.RELEASE</version>
<scope>compile</scope>
</dependency>
@SpringBootApplication注解
// 标记当前是一个启动引导类,是springboot应用的入口。
// 本身是一个组合注解。
@SpringBootConfiguration // 点击
@EnableAutoConfiguration // 点击
// 包扫描器,不包含excludeFilters以下过滤注解
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM,
classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
//...............
}
@SpringBootConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration //点击
public @interface SpringBootConfiguration {
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // 表示该注解是一个配置类注解,并且自己是容器中的一个组件
public @interface Configuration {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
@EnableAutoConfiguration
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage // 点击
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
@AutoConfigurationPackage
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// 自定义化配置包扫描,指定要扫描的包
@Import({Registrar.class}) // 点击
public @interface AutoConfigurationPackage {
}
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
}
private final String packageName;
public String getPackageName() {
// 包名:就是Spring容器需要去扫描能够识别的注解。其实就是启动引导类所在的包及其子包
return this.packageName;
}
@AutoConfigurationImportSelector
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
// 获取自动化配置的元数据
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
// 通过配置的元数据和注解的元数据,得到一个自动化配置的entry键值对
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
// 获取注解的属性
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
// 通过注解元数据和属性获取真正意义上的集合
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
// 加载配置文件中的信息
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
// 遍历配置文件中的信息,转换为Properties对象,放入到信息中
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
// 遍历
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
// 获取工厂类名称
String factoryClassName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryName = var9[var11];
result.add(factoryClassName, factoryName.trim());
}
}
}
// 添加缓存
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
META-INF/spring.factories
@Configuration
// 是否自动配置的条件
@ConditionalOnWebApplication(type = Type.SERVLET)
// 判断是否有下面三个的配置的
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
SpringApplication.run(XXX.class, args)
// public static ConfigurableApplicationContext run()返回一个Spring容器对象
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
创建SpringApplication对象
public SpringApplication(Class... primarySources) {
this((ResourceLoader)null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
// 判断当前是否是web环境
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 从类路径下找到META‐INF/spring.factories配置的所有ApplicationContextInitializer;
// 然后封装成一个Map,转成Set,遍历Set,通过反射创建对象,
// 赋值给SpringApplication的initializers属性
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 从类路径下找到META‐INF/spring.factories配置的所有ApplicationListener;
// 然后封装成一个Map,转成Set,遍历Set,通过反射创建对象,
// 赋值给SpringApplication的listeners属性
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
// 从多个配置类中找到有main方法的主配置类
this.mainApplicationClass = this.deduceMainApplicationClass();
}
执行run方法
public ConfigurableApplicationContext run(String... args) {
// 创建StopWatch对象,执行start方法,开始计时。StopWatch用来计算run方法的执行时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
// 从类路径下META‐INF/spring.factories中获取SpringApplicationRunListeners,
// 反射创建对象,并回调start方法;
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
// 准备命令行参数,就是传入的args
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境,完成后,回调listener的environmentPrepared方法。
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
// 打印SpringBoot的logo
Banner printedBanner = this.printBanner(environment);
// 创建Spring容器,通过判断,决定是web的Spring容器还是普通的Spring容器
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[]{ConfigurableApplicationContext.class}, context);
// 准备上下文环境
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新容器,加载所有的组件【如果是web环境,会启动tomcat】
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
// 停止计时,
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).
logStarted(this.getApplicationLog(), stopWatch);
}
// 回调所有的SpringApplicationRunListener的started();
listeners.started(context);
// 从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
// 【ApplicationRunner先回调,CommandLineRunner再回调】
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}