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


前言

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

在这里插入图片描述


1、SpringBootApplication注解剖析

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

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

在这里插入图片描述

1.1、@EnableAutoConfiguration

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

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

1.1.1、模块装配

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

  1. 使用@import导入普通类

在这里插入图片描述

  1. 使用@import导入配置类

在这里插入图片描述

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

在这里插入图片描述
在这里插入图片描述

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

在这里插入图片描述
在这里插入图片描述

1.1.2、@EnableAutoConfiguration注解解析

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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中,这时候下次再加载的时候就就可以直接从缓存中获取了,无需重复加载。

在这里插入图片描述

总结

  1. 通过AutoConfigurationImportSelector配置SpringFactoriesLoader可以加载路径“META-INF/spring.factories”文件中配置的许多自动装配类。
  2. Spring自己实现了SPI技术,使用key-value更灵活,增加了缓存避免重复加载耗费资源。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值