文章目录

  • 一、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注解开始,逐层往下进行"点击进入",初步了解基本原理。

Springboot 数据库 不自动装配_spring boot

1、@SpringBootApplication(SpringBoot应用)

首先,在主程序中我们可以注意到@SpringBootApplication注解

Springboot 数据库 不自动装配_spring_02

点进去可以看到三个比较重要的注解

Springboot 数据库 不自动装配_应用程序_03

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

Springboot 数据库 不自动装配_Data_04


接着往下点,会发现原来它是一个@Component组件

Springboot 数据库 不自动装配_应用程序_05

在springmvc中@component 是把普通pojo实例化到spring容器中,相当于配置文件中的< bean>

2、@EnableAutoConfiguration(启用自动配置)

当我点开这个注解之后,会发现有两个比较重要的注解,一个是@AutoConfigurationPackage(自动配置包),另一个是@Import(AutoConfigurationImportSelector.class)(自动配置导入选择器)

Springboot 数据库 不自动装配_Data_06

2.1、@AutoConfigurationPackage

我们先点开看看@AutoConfigurationPackage注解,发现有一个@Import(AutoConfigurationPackages.Registrar.class)(自动配置包的注册)

2.1.1@Import(AutoConfigurationPackages.Registrar.class)(自动配置包的注册)

Springboot 数据库 不自动装配_spring_07


点开这个注解,我们可以发现里面有这么一段代码,是对"类"的注册

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我们可以在如下的位置找到

Springboot 数据库 不自动装配_spring boot_08

3、总结

springboot中的所有的自动配置都是在主程序启动时进行扫描和加载的,所有的自动配置都在spring.factory中。

但是不是说spring.factory中的所有的自动配置类都能生效,因为存在一个@ConditionalOnXxxx的注解来判断是否所以需的依赖(jar包)是否存在,只有相应自动配置类所需要的依赖(jar包)是存在,才会进行加载。

这个是从侧面说明了为什么会有那么多的"启动器"需要在pom.xml中需要手动的配置。

大体过程

  1. springboot在启动时,会从spring.factory中加载获取需要的自动配置类。
  2. 将获取到的自动配置类导入容器,并进行自动生效。
  3. 整合javaEE,解决方案设自动配置都是在spring-boot-autoconfigure-2.5.3.jar包下的。
  4. springboot会将所需要的组件以类名的形式进行返回,使得这些组件被添加在容器中。