一文弄懂 Spring boot 启动流程

本文详细探讨了Spring Boot、Spring MVC和Spring的区别,强调Spring Boot的自动配置特性。通过@SpringBootApplication入口,解释了@EnableAutoConfiguration注解及其核心@Import(AutoConfigurationImportSelector.class),并介绍了SpringFactoriesLoader的作用。最后概述了Spring Boot的启动流程。
摘要由CSDN通过智能技术生成

Spring Boot、Spring MVC 和 Spring 有什么区别?

分别描述各自的特征:

Spring 框架就像一个家族,有众多衍生产品例如 boot、security、jpa等等;但他们的基础都是Spring 的ioc和 aop,ioc 提供了依赖注入的容器, aop解决了面向切面编程,然后在此两者的基础上实现了其他延伸产品的高级功能。

Spring MVC 提供了一种轻度耦合的方式来开发 web 应用;它是 Spring 的一个模块,是一个 web 框架;通过 DispatcherServlet, ModelAndView 和 View Resolver,开发web应用变得很容易;解决的问题领域是网站应用程序或者服务开发—— URL路由、Session、模板引擎、静态Web资源等等。

Spring Boot实现了auto-configuration自动配置(另外三大神器actuator监控,cli命令行接口,starter依赖),降低了项目搭建的复杂度。它主要是为了解决使用Spring框架需要进行大量的配置太麻烦的问题,所以它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具;同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box)。

所以,用最简练的语言概括就是:

Spring 是一个“引擎”;

Spring MVC 是基于Spring的一个 MVC 框架;

Spring Boot 是基于Spring4的条件注册的一套快速开发整合包。


Spring boot 的启动类入口

用过springboot的技术人员很显而易见的两者之间的差别就是视觉上很直观的:springboot有自己独立的启动类(独立程序)

package dev.cd;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

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

}

从上面代码可以看出,Annotation定义(@SpringBootApplication)和类定义(SpringApplication.run)最为耀眼,所以要揭开SpringBoot的神秘面纱,我们要从这两位开始就可以了。


@SpringBootApplication 注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // 继承了Configuration,表示当前是 JavaConfig
@EnableAutoConfiguration // 开启springboot的注解功能,springboot的四大神器之一,其借助@import的帮助
@ComponentScan( // 扫描 basePackage 下的 @Component
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {

在这里插入图片描述
在其中比较重要的有三个注解,分别是:

1)@SpringBootConfiguration // 继承了@Configuration,表示当前是注解类

2)@EnableAutoConfiguration // 开启 Spring boot 的注解功能,Spring boot 的四大神器之一,其借助@import的帮助

3)@ComponentScan(excludeFilters = { // 扫描路径设置(具体使用待确认)

注:@ComponentScan 是扫描 @Component 注解申明的类的,其中 @Configuration 也是集成自该注解


@EnableAutoConfiguration 注解

此注解顾名思义是可以自动配置,所以应该是 Spring boot 中最为重要的注解。

在spring框架中就提供了各种以@Enable开头的注解,例如: @EnableScheduling、@EnableCaching、@EnableMBeanExport等; @EnableAutoConfiguration 的理念和做事方式其实一脉相承简单概括一下就是,借助@Import的支持,收集和注册特定场景相关的bean定义。

@EnableScheduling是通过@Import将Spring调度框架相关的bean定义都加载到IoC容器【定时任务、时间调度任务】。
@EnableAutoConfiguration也是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器。

@EnableAutoConfiguration作为一个复合Annotation,其自身定义关键信息如下:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class}) //重点注解
public @interface EnableAutoConfiguration {

@Import(AutoConfigurationImportSelector.class)【重点注解】

在这里插入图片描述
可以从图中看出 AutoConfigurationImportSelector 实现了 DeferredImportSelector ImportSelector 继承的方法: selectImports

  public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

看下关键方法 getAutoConfigurationEntry(annotationMetadata)

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(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.getConfigurationClassFilter().filter(configurations);
        this.fireAutoConfigurationImportEvents(configurations, exclusions);
        return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
    }
}

List configurations = getCandidateConfigurations(annotationMetadata,attributes);其实是去加载各个组件jar下的 public static final String FACTORIES_RESOURCE_LOCATION = “META-INF/spring.factories”; 外部文件。

该方法在springboot启动流程——bean实例化前被执行,返回要实例化的类信息列表。

如果获取到类信息,spring可以通过类加载器将类加载到jvm中,现在我们已经通过spring-boot的starter依赖方式依赖了我们需要的组件,那么这些组件的类信息在select方法中就可以被获取到。

  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;
    }

其返回一个自动配置类的类名列表,方法调用了 SpringFactoriesLoader 类的 loadFactoryNames 方法,查看该方法

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
 String factoryClassName = factoryClass.getName();
 return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
 }

自动配置器会跟根据传入的 factoryClass.getName() 到项目系统路径下所有的 spring.factories 文件中找到相应的key,从而加载里面的类。

这个外部文件,有很多自动配置的类。如下:

在这里插入图片描述
小结:最关键的要属 @Import(AutoConfigurationImportSelector.class),借助 AutoConfigurationImportSelector,@EnableAutoConfiguration 可以帮助 SpringBoot 应用将所有符合条件(spring.factories)的bean定义(如 JavaConfig @Configuration 配置)都加载到当前SpringBoot创建并使用的IoC容器。

SpringFactoriesLoader详解

借助于Spring框架原有的一个工具类:SpringFactoriesLoader 的支持,@EnableAutoConfiguration 可以智能的自动配置功效才得以大功告成!

SpringFactoriesLoader 属于 Spring 框架私有的一种扩展方案,其主要功能就是从指定的配置文件META-INF/spring.factories 加载配置,加载工厂类。

SpringFactoriesLoader 为 Spring 工厂加载器,该对象提供了 loadFactoryNames 方法,入参为factoryClass 和classLoader 即需要传入工厂类名称和对应的类加载器,方法会根据指定的 classLoader,加载该类加器搜索路径下的指定文件,即 spring.factories 文件;

传入的工厂类为接口,而文件中对应的类则是接口的实现类,或最终作为实现类。

public abstract class SpringFactoriesLoader {
//...
  public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
    ...
  }
   
   
  public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
    ....
  }
}

配合 @EnableAutoConfiguration 使用的话,它更多是提供一种配置查找的功能支持,即根据 @EnableAutoConfiguration 的完整类名org.springframework.boot.autoconfigure.EnableAutoConfiguration 作为查找的 Key,获取对应的一组@Configuration类。

在这里插入图片描述

Spring boot 启动流程概览图

在这里插入图片描述

深入探索 SpringApplication 执行流程

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值