文章目录
- 一、pom.xml 的解读
- 1、继承关系解读
- 2、启动器
- 二、XxxxApplication(主程序)的解读
- 1、@SpringBootApplication(SpringBoot应用)
- 1.1、@ComponentScan(组件扫描)
- 1.2、@SpringBootConfiguration(SpringBoot配置)
- 2、@EnableAutoConfiguration(启用自动配置)
- 2.1、@AutoConfigurationPackage
- 2.1.1@Import(AutoConfigurationPackages.Registrar.class)(自动配置包的注册)
- 2.2、@Import(AutoConfigurationImportSelector.class)
- 2.2.1、getAutoConfigurationEntry()(获取自动配置条目)
- 2.2.2、getCandidateConfigurations()(获取候选配置)
- 2.2.3、loadFactoryNames()(加载工厂名称)
- 2.2.4、loadSpringFactories()(加载spring工厂)
- 3、总结
一、pom.xml 的解读
1、继承关系解读
我们可以发现pom.xml是有父文件的(spring-boot-starter-parent)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
在spring-boot-starter-parent.pom中配置了静态资源过滤。
spring-boot-starter-parent.pom也是有父文件的(spring-boot-dependencies.pom)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.5.3</version>
</parent>
所有的核心依赖以及版本管理都在spring-boot-dependencies.pom中。
正是因为如此,我们在写或者在引入一些SpringBoot的依赖时,不需要指定依赖的版本,因为我们所常使用的依赖,在父依赖中都有统一的管理。
2、启动器
在pom.xml中我们可以发现,有诸多的spring-boot-starter-xxx类型的依赖,他们统一被称为SpringBoot的应用程序启动器。启动器机就是SpringBoot的启动场景。
springboot中的应用程序启动器有44种
名称 | 描述 |
spring-boot-starter | 核心启动器,包括自动配置支持、日志记录和 YAML |
spring-boot-starter-activemq | 使用 Apache ActiveMQ 的 JMS 消息传递入门 |
spring-boot-starter-amqp | 使用 Spring AMQP 和 Rabbit MQ 的入门者 |
spring-boot-starter-aop | 使用 Spring AOP 和 AspectJ 进行面向方面编程的入门者 |
spring-boot-starter-artemis | 使用 Apache Artemis 进行 JMS 消息传递的入门者 |
spring-boot-starter-batch | 使用 Spring Batch 的启动器 |
spring-boot-starter-cache | 使用 Spring Framework 的缓存支持的 Starter |
spring-boot-starter-data-cassandra | Starter 使用 Cassandra 分布式数据库和 Spring Data Cassandra |
spring-boot-starter-data-cassandra-reactive | Starter 使用 Cassandra 分布式数据库和 Spring Data Cassandra Reactive |
spring-boot-starter-data-couchbase | 使用 Couchbase 面向文档的数据库和 Spring Data Couchbase 的入门者 |
spring-boot-starter-data-couchbase-reactive | Starter 使用 Couchbase 面向文档的数据库和 Spring Data Couchbase Reactive |
spring-boot-starter-data-elasticsearch | 使用 Elasticsearch 搜索和分析引擎以及 Spring Data Elasticsearch 的入门者 |
spring-boot-starter-data-jdbc | 使用 Spring Data JDBC 的入门者 |
spring-boot-starter-data-jpa | 将 Spring Data JPA 与 Hibernate 结合使用的入门者 |
spring-boot-starter-data-ldap | 使用 Spring Data LDAP 的入门者 |
spring-boot-starter-data-mongodb | 使用 MongoDB 面向文档的数据库和 Spring Data MongoDB 的入门者 |
spring-boot-starter-data-mongodb-reactive | Starter 使用 MongoDB 面向文档的数据库和 Spring Data MongoDB Reactive |
spring-boot-starter-data-neo4j | 使用 Neo4j 图形数据库和 Spring Data Neo4j 的入门者 |
spring-boot-starter-data-r2dbc | 使用 Spring Data R2DBC 的启动器 |
spring-boot-starter-data-redis | 将 Redis 键值数据存储与 Spring Data Redis 和 Lettuce 客户端一起使用的入门者 |
spring-boot-starter-data-redis-reactive | 将 Redis 键值数据存储与 Spring Data Redis 反应式和 Lettuce 客户端一起使用的入门者 |
spring-boot-starter-data-rest | 使用 Spring Data REST 在 REST 上公开 Spring Data 存储库的启动器 |
spring-boot-starter-freemarker | 使用 FreeMarker 视图构建 MVC Web 应用程序的入门者 |
spring-boot-starter-groovy-templates | 使用 Groovy 模板视图构建 MVC Web 应用程序的入门者 |
spring-boot-starter-hateoas | 使用 Spring MVC 和 Spring HATEOAS 构建基于超媒体的 RESTful Web 应用程序的入门者 |
spring-boot-starter-integration | 使用 Spring Integration 的入门者 |
spring-boot-starter-jdbc | 将 JDBC 与 HikariCP 连接池一起使用的 Starter |
spring-boot-starter-jersey | 使用 JAX-RS 和 Jersey 构建 RESTful Web 应用程序的初学者。替代方案spring-boot-starter-web |
spring-boot-starter-jooq | 使用 jOOQ 访问 SQL 数据库的入门者。spring-boot-starter-data-jpa或的替代品spring-boot-starter-jdbc |
spring-boot-starter-json | 读写json的Starter |
spring-boot-starter-jta-atomikos | 使用 Atomikos 的 JTA 事务入门 |
spring-boot-starter-mail | 使用 Java Mail 的 Starter 和 Spring Framework 的电子邮件发送支持 |
spring-boot-starter-mustache | 使用 Mustache 视图构建 Web 应用程序的入门者 |
spring-boot-starter-oauth2-client | 使用 Spring Security 的 OAuth2/OpenID Connect 客户端功能的入门者 |
spring-boot-starter-oauth2-resource-server | 使用 Spring Security 的 OAuth2 资源服务器功能的入门者 |
spring-boot-starter-quartz | 使用 Quartz 调度器的启动器 |
spring-boot-starter-rsocket | 用于构建 RSocket 客户端和服务器的 Starter |
spring-boot-starter-security | 使用 Spring Security 的入门者 |
spring-boot-starter-test | Starter 用于使用包括 JUnit Jupiter、Hamcrest 和 Mockito 在内的库测试 Spring Boot 应用程序 |
spring-boot-starter-thymeleaf | 使用 Thymeleaf 视图构建 MVC Web 应用程序的初学者 |
spring-boot-starter-validation | 将 Java Bean 验证与 Hibernate Validator 结合使用的入门工具 |
spring-boot-starter-web | 使用 Spring MVC 构建 Web(包括 RESTful)应用程序的入门者。使用 Tomcat 作为默认的嵌入式容器 |
spring-boot-starter-web-services | 使用 Spring Web 服务的入门者 |
spring-boot-starter-webflux | 使用 Spring Framework 的 Reactive Web 支持构建 WebFlux 应用程序的 Starter |
spring-boot-starter-websocket | 使用 Spring Framework 的 WebSocket 支持构建 WebSocket 应用程序的 Starter |
Spring Boot 生产启动器
除了应用程序启动器之外,以下启动器还可用于添加生产就绪功能
名称 | 描述 |
spring-boot-starter-actuator | 使用 Spring Boot 的 Actuator 的 Starter,它提供了生产就绪的特性来帮助你监控和管理你的应用程序 |
Spring Boot 技术入门
最后,Spring Boot 还包括以下启动器,如果您想排除或交换特定的技术方面,可以使用它们:Spring Boot 技术入门
名称 | 描述 |
spring-boot-starter-jetty | 使用 Jetty 作为嵌入式 servlet 容器的启动器。替代方案spring-boot-starter-tomcat |
spring-boot-starter-log4j2 | 使用 Log4j2 进行日志记录的启动器。替代方案spring-boot-starter-logging |
spring-boot-starter-logging | 使用 Logback 进行日志记录的启动器。默认日志记录启动器 |
spring-boot-starter-reactor-netty | 使用 Reactor Netty 作为嵌入式响应式 HTTP 服务器的启动器。 |
spring-boot-starter-tomcat | 使用 Tomcat 作为嵌入式 servlet 容器的启动器。使用的默认 servlet 容器启动器spring-boot-starter-web |
spring-boot-starter-undertow | 使用 Undertow 作为嵌入式 servlet 容器的启动器。替代方案spring-boot-starter-tomcat |
二、XxxxApplication(主程序)的解读
我们从主程序中的@XxxxApplication注解开始,逐层往下进行"点击进入",初步了解基本原理。
1、@SpringBootApplication(SpringBoot应用)
首先,在主程序中我们可以注意到@SpringBootApplication注解
点进去可以看到三个比较重要的注解
1.1、@ComponentScan(组件扫描)
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
如果大家对springmvc有了解的,会记得component-scan,其作用是扫描service层下的包
<context:component-scan base-package="com.sdpei.service"/>
所以@ComponentScan的作用是扫描与当前主启动类同级的包
1.2、@SpringBootConfiguration(SpringBoot配置)
点开@SpringBootConfiguration之后是我们可以看到另一个比较重要的注解@Configuration
接着往下点,会发现原来它是一个@Component组件
在springmvc中@component 是把普通pojo实例化到spring容器中,相当于配置文件中的< bean>
2、@EnableAutoConfiguration(启用自动配置)
当我点开这个注解之后,会发现有两个比较重要的注解,一个是@AutoConfigurationPackage(自动配置包),另一个是@Import(AutoConfigurationImportSelector.class)(自动配置导入选择器)
2.1、@AutoConfigurationPackage
我们先点开看看@AutoConfigurationPackage注解,发现有一个@Import(AutoConfigurationPackages.Registrar.class)(自动配置包的注册)
2.1.1@Import(AutoConfigurationPackages.Registrar.class)(自动配置包的注册)
点开这个注解,我们可以发现里面有这么一段代码,是对"类"的注册
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImports(metadata));
}
}
AnnotationMetadata metadata:是一个注解的源文件
BeanDefinitionRegistry:是一个bean的定义注册表
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0])):通过文件读取包名进行注册
2.2、@Import(AutoConfigurationImportSelector.class)
2.2.1、getAutoConfigurationEntry()(获取自动配置条目)
点看这个注解之后,有一个getAutoConfigurationEntry()(获取自动配置条目)的方法
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
2.2.2、getCandidateConfigurations()(获取候选配置)
getAutoConfigurationEntry()方法中有getCandidateConfigurations()(获取候选配置)的方法,点开这个方法,是这样的
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;
}
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
return EnableAutoConfiguration.class:获取被"@EnableAutoConfiguration"标记的类
而"主程序"就是被@EnableAutoConfiguration"标记的类,因为@SpringBootApplication中有@EnableAutoConfiguration,所以是获取到了"主程序"
2.2.3、loadFactoryNames()(加载工厂名称)
getCandidateConfigurations()方法中有loadFactoryNames()(加载工厂名称)的方法,点开这个方法,是这样的
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
2.2.4、loadSpringFactories()(加载spring工厂)
对于loadFactoryNames()中的私有方法loadSpringFactories()(加载spring工厂),核心代码是这样描述的
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
...
result = new HashMap<>();
try {
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
//遍历上面的资源(url),并封装到properties中,供下面的使用
while (urls.hasMoreElements()) {
....
}
}
...
}
FACTORIES_RESOURCE_LOCATION :META-INF/spring.factories
其中spring.factories我们可以在如下的位置找到
3、总结
springboot中的所有的自动配置都是在主程序启动时进行扫描和加载的,所有的自动配置都在spring.factory中。
但是不是说spring.factory中的所有的自动配置类都能生效
,因为存在一个@ConditionalOnXxxx的注解来判断是否所以需的依赖(jar包)是否存在
,只有相应自动配置类所需要的依赖(jar包)是存在,才会进行加载。
这个是从侧面说明了为什么会有那么多的"启动器"需要在pom.xml中需要手动的配置。
大体过程
- springboot在启动时,会从spring.factory中加载获取需要的自动配置类。
- 将获取到的自动配置类导入容器,并进行自动生效。
- 整合javaEE,解决方案设自动配置都是在spring-boot-autoconfigure-2.5.3.jar包下的。
- springboot会将所需要的组件以类名的形式进行返回,使得这些组件被添加在容器中。