Springboot启动流程源码分析

Springboot启动流程源码分析(一)(自动配置)

我们首先从pom.xml文件开始分析

  • 其中它主要是依赖一个父项目,主要是管理控制项目的资源过滤及插件依赖!
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
  • 在父启动类里,发现还有一个父依赖
      <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.3.2.RELEASE</version>
      </parent>
  • 这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;
    • 以后我们导入依赖默认是不需要写版本
    • 但是如果导入的包没有在依赖中管理着就需要手动配置版本了

启动器 spring-boot-starter介绍

    <dependency>    
        <groupId>org.springframework.boot</groupId>    
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  • springboot-boot-starter-xxx:就是spring-boot的场景启动器
  • spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件
  • SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来
  • 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义 starter;

主启动类SpringbootApplication---->一系列注解原理

1、SpringbootApplication主启动类main方法

  • 默认的主启动类,一个简单的启动类并不简单!下面我们来分析一下 @SpringBootApplication 注解都干了什么
	@SpringBootApplication // 来标注一个主程序类  说明这是一个Spring Boot应用
    public class SpringbootApplication {
       public static void main(String[] args) {
         //以为是启动了一个方法,没想到启动了一个服务
          SpringApplication.run(SpringbootApplication.class, args);
       }
    }

2、@SpringBootApplication注解

  • 来标注一个主程序类 说明这是一个Spring Boot应用

  • SpringBoot就应该运行这个类的main方法来启动SpringBoot应用

  • 在这个注解中还有许多其他的注解,如下代码所示

    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
            @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication {
        // ...
    }

3、@ComponentScan注解(@SpringBootApplication子注解)

  • 该注解在Spring中很重要 ,它对应XML配置中的元素。

  • 作用:自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中

4、@SpringBootConfiguration注解(@SpringBootApplication子注解)

  • 作用:SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类
  • 在该注解下含有两个注解:@Configuration、@Component
    @Configuration
    public @interface SpringBootConfiguration {}
    // @Configuration点进去得到下面的 @Component
    @Component
    public @interface Configuration {}
  • 这里的 @Configuration,说明这是一个配置类 ,配置类就是对应Spring的xml 配置文件

  • 这里的 @Component 这就说明,启动类本身也是Spring中的一个组件而已,负责启动应用!

我们回到 SpringBootApplication 注解中继续看。

5、@EnableAutoConfiguration(@SpringBootApplication的注解)

  • 注解作用:开启自动配置功能

    • 以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置
    • @EnableAutoConfiguration告诉SpringBoot开启自动配置功能,这样自动配置才能生效
  • 点进EnableAutoConfiguration注解继续查看:

    • @AutoConfigurationPackage :自动配置包

          @Import(AutoConfigurationPackages.Registrar.class)
          public @interface AutoConfigurationPackage {
          }
      
    • @import :Spring底层注解@import , 给容器中导入一个组件

      • Registrar.class 的作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器
  • 退到上一步,继续看@EnableAutoConfiguration的注解

  • **@Import({AutoConfigurationImportSelector.class}) :给容器导入组件 **

    • AutoConfigurationImportSelector :自动配置导入选择器,那么它会导入哪些组件的选择器呢?我们点击去这个类看源码:
    • getCandidateConfigurations方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    // 这里的getSpringFactoriesLoaderFactoryClass()方法,返回的就是注解类Class:EnableAutoConfiguration
   List<String> configurations = SpringFactoriesLoader.
       loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());
   return configurations;
}
// 返回自动配置类EnableAutoConfiguration 
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
   return EnableAutoConfiguration.class;
}
  • 这个方法又调用了 SpringFactoriesLoader 类的静态方法loadFactoryNames() 方法
	// @Nullable ClassLoader classLoader 参数为该类自己SpringFactoriesLoader	
	public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
		// 就是传过来的EnableAutoConfiguration.class;
        String factoryTypeName = factoryType.getName();
        // 这里又调用了loadSpringFactories方法,Map有键为EnableAutoConfiguration就返回,没有取空集合
		return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
	}
  • 我们继续追踪查看 loadSpringFactories 方法
	public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";    
	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        // 获得classLoader,我们返回可以看到这里得到的就是EnableAutoConfiguration标注的类本身
        MultiValueMap<String, String> result = cache.get(classLoader);
        // 缓存中若有,则直接返回
        if (result != null)   return result;       
        try {
            // 去加载文件资源 "META-INF/spring.factories"
            Enumeration<URL> urls = (classLoader != null ?
                        classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                        ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
                result = new LinkedMultiValueMap<>();
                while (urls.hasMoreElements()) {
                    URL url = urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    // 将读取到的资源遍历,封装成为一个Properties 
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    for (Map.Entry<?, ?> entry : properties.entrySet()) {
                        String factoryTypeName = ((String) entry.getKey()).trim();
                        for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                            result.add(factoryTypeName, factoryImplementationName.trim());
                        }
                    }
                }
                cache.put(classLoader, result);
                return result;
        }
    }

spring.factories文件

  • 我们可以全局搜索并打开spring.factories , 看到了很多自动配置的信息

AopAutoConfiguration实例

  • 随便找一个自动配置类打开看看,比如 :AopAutoConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(Advice.class)
	static class AspectJAutoProxyingConfiguration{ }
    @Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
			matchIfMissing = true)
	static class ClassProxyingConfiguration{ }
  • 自动配置的实现是加载classpath下所有的META-INF/spring.factories配置文件
  • 将其中对应的 org.springframework.boot.autoconfigure 包下的配置项
  • 通过反射实例化将标注了 @ConfigurationJavaConfig形式的聚集加载到IOC容器完成配置
posted @ 2022-03-11 23:31  lam要努力  阅读(63)  评论(0编辑  收藏  举报