spring-boot-starter-parent:父依赖项目管理
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.1.7.RELEASE</version>
</parent>
查看spring-boot-starter-parent底层源文件
发现存在另外一个父依赖spring-boot-dependencies,核心代码如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
...
查看spring-boot-dependencies底层源文件
该文件通过 properties 标签对一些常用技术框架的依赖文件进行了统一的版本号管理
所以通过pom.xml引入依赖文件时,如果引入的依赖文件被spring-boot-starter-parent所管理,则不需要引入版本号,否则需要使用 version 标签指定版本号
<properties>
<activemq.version>5.15.9</activemq.version>
...
<spring.version>5.1.9.RELEASE</spring.version>
<spring-amqp.version>2.1.8.RELEASE</spring-amqp.version>
<spring-batch.version>4.1.2.RELEASE</spring-batch.version>
<spring-cloud-connectors.version>2.0.6.RELEASE</spring-cloud-connectors.version>
<spring-data-releasetrain.version>Lovelace-SR10</spring-data-releasetrain.version>
<spring-framework.version>${spring.version}</spring-framework.version>
<spring-hateoas.version>0.25.2.RELEASE</spring-hateoas.version>
<spring-integration.version>5.1.7.RELEASE</spring-integration.version>
<spring-kafka.version>2.2.8.RELEASE</spring-kafka.version>
<spring-ldap.version>2.3.2.RELEASE</spring-ldap.version>
<spring-plugin.version>1.2.0.RELEASE</spring-plugin.version>
<spring-restdocs.version>2.0.3.RELEASE</spring-restdocs.version>
<spring-retry.version>1.2.4.RELEASE</spring-retry.version>
<spring-security.version>5.1.6.RELEASE</spring-security.version>
<spring-session-bom.version>Bean-SR7</spring-session-bom.version>
<spring-ws.version>3.0.7.RELEASE</spring-ws.version>
<sqlite-jdbc.version>3.25.2</sqlite-jdbc.version>
<statsd-client.version>3.1.0</statsd-client.version>
<sun-mail.version>${javax-mail.version}</sun-mail.version>
<thymeleaf.version>3.0.11.RELEASE</thymeleaf.version>
<thymeleaf-extras-data-attribute.version>2.0.1</thymeleaf-extras-data-attribute.version>
<thymeleaf-extras-java8time.version>3.0.4.RELEASE</thymeleaf-extras-java8time.version>
<thymeleaf-extras-springsecurity.version>3.0.4.RELEASE</thymeleaf-extras-springsecurity.version>
<thymeleaf-layout-dialect.version>2.3.0</thymeleaf-layout-dialect.version>
<tomcat.version>9.0.22</tomcat.version>
<unboundid-ldapsdk.version>4.0.11</unboundid-ldapsdk.version>
<undertow.version>2.0.23.Final</undertow.version>
...
</properties>
spring-boot-starter-web:Web场景依赖启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
查看spring-boot-starter-web依赖文件源码
提供web依赖开发场景所需的底层所有依赖环境
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.7.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.1.7.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.1.7.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.9.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
自动配置由以下注解决定:
@SpringBootApplication
标注这个类是一个SpringBoot的应用
能够扫描Spring组件并自动配置SpringBoot
自动配置的原理?
@SpringBootApplication内部源码如下
1、@SpringBootConfiguration:表示这是个SpringBoot配置类
注解源码的核心代码如下:
发现存在一个@Configuration注解,说明@SpringBootConfiguration和@Configuration注解的作用一样,标识一个可以被组件扫描器扫描的配置类。
2、@EnableAutoConfiguration:开启自动配置功能
注解源码的核心代码如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
?
Class
发现@EnableAutoConfiguration由@AutoConfigurationPackage和@Import()组合而成
@AutoConfigurationPackage的源码
@Import({Registrar.class})
作用:
向容器导入注册的所有组件,导入的组件由Resgistrar决定
Registrar类的源码的核心代码如下:
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
?
/*
使用debug模式启动项目,
AutoConfigurationPackages.PackageImport(metadata)).getPackageName(),这个部分获取的是项目主程序启动类所在的目录
*/
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
...
}
总结:@AutoConfigurationPackage的主要作用是获取项目主程序启动类所在根目录,从而指定后续组件扫描器要扫描的包位置
@Import({AutoConfigurationImportSelector.class})
查看AutoConfigurationImportSelector类的getAutoConfigurationEntry()方法
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
/*
获取SpringBoot提供的后续自动配置类XXXAutoConfiguration
*/
List<String> configurations =
/*
该方法的主要作用是
从SpringBoot提供的自动配置依赖环境META-INF/spring.factories
文件中获取所有的候选自动配置类XXXAutoConfiguration
*/
this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
/*
筛选并过滤当前应用环境下需要的自动配置类XXXAutoConfiguration
*/
configurations = this.filter(configurations, autoConfigurationMetadata);
/*
该方法的主要作用是
对所有候选的自动配置类进行筛选,根据项目pom.xml文件中加入的依赖文件筛选 出最终符合当前项目运行环境对应的自动配置类
*/
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
总结:@Import({AutoConfigurationImportSelector.class})的主要作用是筛选出当前项目需要启动的自动配置类,从而实现当前项目运行所需的自动配置环境
3、@ComponentScan():组件包扫描器
将指定包中的注解类自动装配到Spring的Bean容器中
具体扫描的包的根路径由SpringBoot项目主程序启动类所在包位置决定
总结:在定义项目包结构时,要求定义的包结构要非常规范,保证定义的类能够被组件扫描器扫描
项目主程序启动类要定义在最外层的根目录位置
然后在根目录位置内部建立子包和类进行业务开发
在主程序启动类中的main()方法中,执行SpringApplication.run()即可启动整个SpringBoot程序,具体的执行流程是什么呢?
run()方法内部源码的核心代码:
/*
SpringApplication.run()的方法内部执行了两个操作
1、SpringApplication的初始化
2、调用run()启动项目
*/
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
1、SpringApplication的初始化
SpringApplication实例对象初始化的源码信息的核心代码:
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));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
从上述源码可以看出,SpringApplication的初始化过程分为4部分
1、this.webApplicationType = WebApplicationType.deduceFromClasspath();
判断当前webApplicationType 应用的类型
deduceFromClasspath()用于查看Classpath路径下是否存在某个特征类,从而判断类型是SERVLET应用(传统MVC应用)还是REACTIVE应用(WebFlux交互式应用)
2、this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
用于设置SpringApplication应用的初始化器
在初始化器设置过程中会使用Spring类加载器SpringFactoriesLoader从META-INF/spring.factories文件中获取所有可用的应用初始化器类ApplicationContextInitializer
3、this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
用于设置SpringApplication应用的监听器
在初始化器设置过程中会使用Spring类加载器SpringFactoriesLoader从META-INF/spring.factories文件中获取所有可用的监听器类ApplicationListener
4、this.mainApplicationClass = this.deduceMainApplicationClass();
用于推断并设置项目main()方法启动的主程序启动类
2、调用run()启动项目
run(args)方法执行的项目初始化启动过程的核心代码:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
//(1)获取SpringApplication初始化的SpringApplicationRunListener运行监听器并运行
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
?
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//(2)项目运行环境的预配置
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
//排除一些不需要的运行环境
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
/*
(3)项目应用上下文ApplicationContext的预配置
创建应用上下文环境ApplicationContext
使用之前初始化设置的context(应用上下文环境)、environment、listener、applicationArguments(项目参数)、printedBanner(项目图标信息)进行上下文的组装配置,并刷新配置
*/
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
?
//(4)由项目运行监听器启动配置好的应用上下文ApplicationContext
listeners.started(context);
//(5)调用上下文中、中配置的程序执行器XXXRunner,使得在项目启动完成后立即执行一些特定程序
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
?
try {
//(6)由项目运行监听器持续运行配置好的应用上下文
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
原文:https://www.cnblogs.com/LittleSkinny/p/13695341.html