springboot源码分析——自动装配实现原理

文章目录

  • 前言
  • 1、SpringBootApplication注解剖析
    • 1.1、@EnableAutoConfiguration
      • 1.1.1、模块装配
      • 1.1.2、@EnableAutoConfiguration注解解析
  • 2、SPI机制
  • 总结


前言

我们知道使用springboot构建一个应用非常简单,在引入以来后,只需要编写一个SpringBoot的主启动类就可以运行SpringBoot应用,这里主启动类上必须标注@SpringBootApplication注解,接下来我们会剖析其内部实现原理

springboot源码分析——自动装配实现原理_第1张图片


1、SpringBootApplication注解剖析

从下图可以看出来他是一个组合注解,等价于同时标注@Configuration+@EnableAutoConfiguration+@ComponentScan注解。

  1. @ComponentScan作用:可以指定包扫描的跟路径,不指定路径默认扫描当前配置类所在包及其子包里的所有组件
  2. @SpringBootApplication作用:这个注解是被@Configration注解标注,说明他其实是用来标注配置类的,而且是标注主启动类的。
  3. @EnableAutoConfiguration作用:这个注解作用比较复杂,下面单独做分析。

springboot源码分析——自动装配实现原理_第2张图片

1.1、@EnableAutoConfiguration

在这里分析注解的时候先补充一些前置逻辑,在spring中,装配组件的方式有三种:

  1. 使用模块注解@Component以及其延伸注解标注
  2. 使用配置类@Configuration@Bean注解标注
  3. 使用模块装配@Enablexxx@Import注解标注

1.1.1、模块装配

前两种装配方式我们很熟悉,这里模块装配在平常开发中不常用,但是在很多集成的框架源码中非常常用,我们先看下模块装配使用示例。

  1. 使用@import导入普通类

springboot源码分析——自动装配实现原理_第3张图片

  1. 使用@import导入配置类

springboot源码分析——自动装配实现原理_第4张图片

  1. 使用@import导入ImportSelector,这里可以通过实现ImportSelector接口,在实现方法中添加要注册进容器中的类的名字。

springboot源码分析——自动装配实现原理_第5张图片
springboot源码分析——自动装配实现原理_第6张图片

  1. 导入ImportBeanDefinitionRegistrar,这里可以通过实现ImportBeanDefinitionRegistrar接口,在实现方法中自己构建BeanDefinition注册到容器中。

springboot源码分析——自动装配实现原理_第7张图片
springboot源码分析——自动装配实现原理_第8张图片

1.1.2、@EnableAutoConfiguration注解解析

  1. 这个注解也是一个组合注解,首先顶着一个@AutoConfigurationPackage注解,
    然后使用@Import导入了一个AutoConfigurationImportSelector类,下面我们来剖析一下。

springboot源码分析——自动装配实现原理_第9张图片

@AutoConfigurationPackage,这个注解在内部又使用了@Import注解导入了Registrar这个类

springboot源码分析——自动装配实现原理_第10张图片

Registrar这个类向容器中保存了导入的配置类所在的包的根路径,这个配置类也就是我们的主启动类,这个是用来后期扫描组件使用的。

springboot源码分析——自动装配实现原理_第11张图片

  1. @Import({AutoConfigurationImportSelector.class})导入了AutoConfigurationImportSelector类。
  • 这里发现他没有直接实现ImportSelector而是实现DeferredImportSelector,这个是因为DeferredImportSelector的执行实际比ImportSelector要持,这种对需要标注@Conditional的导入来说很有用。

springboot源码分析——自动装配实现原理_第12张图片

selectImports方法中会调用getAutoConfigurationEntry加载自动配置类,这里重点就是调用getCandidateConfigurations方法获取到一个配置列表,然后把这些配置返回,通过selectImport装配到容器中,那这个返回的必然是其他组件的核心。

springboot源码分析——自动装配实现原理_第13张图片

getCandidateConfigurations方法内部又调用了SpringFactoriesLoader#leadFactoryNames,传入的Class就是@EnableAutoConfiguration

springboot源码分析——自动装配实现原理_第14张图片

SpringFactoriesLoader#loadFactoryNames方法中会使用classLoader取加载指定路径下的资源,这个路径是META-INF/spring.factories

springboot源码分析——自动装配实现原理_第15张图片

我们看下spring-boot-autoconfiguration 包下 META-INF/spring.factories,在这个文件中全是自动装配类的全限定类名,装配到IOC容器中,之后自动配置类就会通过ImportSelector的机制被创建出来。

springboot源码分析——自动装配实现原理_第16张图片

2、SPI机制

SPI全称为 Service Provider Interface,是jdk内置的一种服务提供发现机制。简单来说,它就是一种动态替换发现的机制。SPI规定,所有要预先声明的类都应该放在 META-INF/services 中。配置的文件名是接口/抽象类的全限定名,文件内容是抽象类的子类或接口的实现类的全限定类名,如果有多个,借助换行符,一行一个。

我们在上面可以看到Spring是通过SPI机制来进行服务发现的,但是使用的是SpringFactoriesLoader而没有使用java``的ServiceLeader来进行加载,我们来剖析一下SpringFactoriesLoader,看和java原生的ServiceLeader的区别:

  1. 之前看过spring.factories文件,文件中定义的是key-value的关系,这样设计的好处就不再局限于接口-实现类的关系,key可以随意定义,比如是一个注解。
  2. 从下图的代码中可以看出,加载完成之后会把result放到cache中,这时候下次再加载的时候就就可以直接从缓存中获取了,无需重复加载。

springboot源码分析——自动装配实现原理_第17张图片

总结

  1. 通过AutoConfigurationImportSelector配置SpringFactoriesLoader可以加载路径“META-INF/spring.factories”文件中配置的许多自动装配类。
  2. Spring自己实现了SPI技术,使用key-value更灵活,增加了缓存避免重复加载耗费资源。

你可能感兴趣的:(springboot,spring,boot,java,spring)