Springboot 自动配置浅析

Introduction

咱们知道,SpringBoot之因此强大,就是由于他提供了各类默认的配置,可让咱们在集成各个组件的时候从各类各样的配置文件中解放出来。java

拿一个最普通的 web 项目举例。咱们须要使用 servlet 容器,SpringBoot 就提供了嵌入式的 Tomcat 做为默认容器,不须要一行配置就能直接以最普通的 Java 程序的方式启动:java -jar;接收请求须要一个网络端口,默认配置好8080;处理请求须要 servlet 的多线程特性,默认配置好了最大线程数为200;处理好的请求以Restful 风格返回给调用方,SpringBoot 默认配置好了jackson进行 json 序列化,业务代码须要作的只是返回一个 POJO 对象;链接池直接就默认配置了性能最好的的 Hikari,以及链接池的默认尺寸为10……在一个简单的web应用中,这些配置咱们甚至均可能不了解或者没有意识到它们的存在,就可让程序正常运行。web

这就是自动配置的魔力——润物细无声。redis

那么自动配置是怎么实现的呢?本文就从POM文件和 @SpringBootApplication 注解来简单分析一下自动配置原理。spring

真的只是简单地,分析一下。json

POM文件

环境

  • SpringBoot 2.0.6

父项目

在每个 SpringBoot 项目一开始的 POM 文件中,就有一个父依赖springboot

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.0.6.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
</parent>

点进artifactId以后来到 spring-boot-starter-parent-2.0.6.RELEASE.pom 文件,这个文件还有一个父依赖:网络

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>2.0.6.RELEASE</version>
  <relativePath>../../spring-boot-dependencies</relativePath>
</parent>

再继续点进去来到 spring-boot-dependencies-2.0.6.RELEASE.pom 文件中。在该文件的 <properties> 标签中能够看到各类各样的组件的版本信息, <dependencyManagement> 标签中声明了各个组件的maven坐标信息。其中,我数了一下,在 SpringBoot 2.0.6 中一个有177个带有版本信息的组件名,包括了你们熟悉的 elasticsearch、activemq、redis、kafka等等。多线程

这里(spring-boot-dependencies-2.0.6.RELEASE.pom文件)称为 SpringBoot 的“版本仲裁中心”,它是用来管理 SpringBoot 应用里面的全部依赖版本的地方。 它包含了大部分开发中会用到的一些组件的版本,因此咱们导入依赖默认是不须要写版本号的,SpringBoot 会自动帮咱们配置须要的版本。这样在引入某个组件的时候不用考虑这个组件和系统中已有的组件兼不兼容之类的问题,避免了烦人的版本冲突问题。(固然,没有在 dependencies里面管理的依赖天然须要声明版本号)app

启动器(Starters)

父项目作版本仲裁,那么真正的 jar 包是从哪里导入进来的呢?这就要说到咱们的starters了。点开web-starter能够看到它帮咱们导入了web模块正常运行所依赖的组件,就不用咱们一个一个手动导入了。elasticsearch

因此,所谓的Starters就是一系列依赖描述的组合,咱们能够经过导入这些starters就会有相应的依赖了并能够基于他们进行相应的开发

Springboot把开发中中会遇到的场景都抽象成一个个的starter,好比(),只须要在项目里面引入这些starter 相关场景的全部依赖都会导入进来。要用什么功能就导入什么场景的启动器

@SpringBootApplication

一个典型的 springboot 项目的入口类以下所示:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

只要运行main方法就能启动该应用。main 中运行 run 方法时须要传入一个类,这个类正是使用@SpringBootApplication注解标注的类,若是没有这个注解程序是跑不起来的。

这个注解标注在某个类上就说明这个类是 springboot 的主配置类,springboot 就应该运行这个类的 main 方法来启动springboot应用

点开这个注解的源码,能够看到这是一个组合注解,最主要的是这两个注解:

  • @SpringBootConfiguration

  • @EnableAutoConfiguration

@SpringBootConfiguration标注在某个类上,表示这是一个 SpringBoot 的配置类,它的底层是@Configuration,属于spring的底层注解,标注了这个注解的类表名这个类是一个配置类,取代之前开发中的xml文件配置,同时也代表这个类是 spring 容器中的组件,受容器管理。

接下来是@EnableAutoConfiguration注解,它的用处是开启自动配置,使用 spring 开发须要手动配置的东西,如今由 springboot 帮咱们配置了,具体的实现就是经过这个注解来实现的。该组合注解有两个。

1. @AutoConfigurationPackage

它的 注解中的核心代码是 @Import({Registrar.class})

@Import 的做用就是为容器中导入一个它指定的组件。

Registrar 这个类中有一个方法叫registerBeanDefinitions,用于注册一些 bean 定义信息:

public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
     AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}

打个断点在这一行代码上,运行

(new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()

获得的结果是主配置类所在的包名,目的就是将主配置类所在包及下面全部子包里面的全部组件扫描到Spring容器中。同时也说明了,若是在主配置所在包的上层包添加组件的话是不会被扫描到的、不起做用的。

2. @Import({AutoConfigurationImportSelector.class})

该注解导入了一个自动配置的选择器,真正地给容器中导入 springboot 自动帮咱们配置好的配置类。在 AutoConfigurationImportSelector 这个选择器中的 getAutoConfigurationEntry 方法中,以全限定类名的方式把全部须要的配置类导入 springboot 容器中。这些全限定类型所在文件路径为:

org/springframework/boot/spring-boot-autoconfigure/2.1.8.RELEASE/spring-boot-autoconfigure-2.1.8.RELEASE.jar!/META-INF/spring.factories

上述两个注解一个负责扫描咱们将要加容器中的类,一个加入 springboot 为咱们自动配置好的类,springboot 经过这两种方式省略了咱们大量的配置工做。

总结

本文从用于maven项目管理的pom.xml文件和标注在启动类上的@SpringBootApplication注解,简单分析了springboot 自动配置的实现。前者经过版本仲裁中心为咱们维护项目组件的版本,防止依赖冲突;后者经过在加载程序的时候导入数以百计的自动配置类实现自动配置。

原文发表于:https://pengcheng.site/2019/10/28/springboot-zi-dong-pei-zhi-qian-xi/

相关文章
相关标签/搜索