一、Spring Boot自动配置原理
相比较于传统的 Spring 应用,搭建一个 SpringBoot 应用,我们只需要引入一个注解 @SpringBootApplication,就可以成功运行。
前面四个不用说,是定义一个注解所必须的,关键就在于后面三个注解:
当然如果你想了解前面四个注解,可以查看我的文章:
@Target、@Retention、@Documented、@Inherited注解的超详细分析
@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan。也就是说我们如果不用 @SpringBootApplication 这个复合注解,而是直接使用最下面这三个注解,也能启动一个 SpringBoot 应用。
前面四个不用说,是定义一个注解所必须的,关键就在于后面三个注解:@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan。也就是说我们如果不用 @SpringBootApplication 这个复合注解,而是直接使用最下面这三个注解,也能启动一个 SpringBoot 应用,其中,Spring Boot的自动配置最核心的注解是@EnableAutoConfiguration。
1.@SpringBootConfiguration 注解
这个注解我们点进去就可以发现,它实际上就是一个 @Configuration 注解,这个注解大家应该很熟悉了,加上这个注解就是为了让当前类作为一个配置类交由 Spring 的 IOC 容器进行管理,因为前面我们说了,SpringBoot 本质上还是 Spring,所以原属于 Spring 的注解 @Configuration 在 SpringBoot 中也可以直接应用。
2.@ComponentScan 注解
@ComponentScan这个注解也很熟悉,用于定义 Spring 的扫描路径,等价于在 xml 文件中配置 context:component-scan,假如不配置扫描路径,那么 Spring 就会默认扫描当前类所在的包及其子包中的所有标注了 @Component,@Service,@Controller 等注解的类。
通过查看源码可以知道,@ComponentScan使用了@Repeatable(ComponentScans.class)注解,@ComponentScans是聚合多个ComponentScan注解的容器注解,它使ComponentScan注解可以在同一个类或方法上多次使用,@Repeatable注解的例子如下:
3.@EnableAutoConfiguration注解
这个注解才是实现自动装配的关键,点进去之后发现,它是一个由 @AutoConfigurationPackage 和 @Import 注解组成的复合注解。
1)@AutoConfigurationPackage
①@import注解简介
@Import
注解,通常用于配置类(Configuration类)中,用于导入其他配置类或组件。
@Import
的主要用途是引入其他的配置类或将其他类注册为Spring容器中的组件。这可以帮助在Spring应用程序中构建模块化的配置,并将多个配置类组合在一起以构建完整的应用程序上下文。
@Import
可以使用不同的参数来指定要导入的配置类或要注册为组件的类,具体取决于使用的具体注解,例如:
-
@Import(ClassToImport.class)
: 导入一个指定的类作为配置类或组件。 -
@Import({Class1.class, Class2.class})
: 导入多个类作为配置类或组件。 -
@Import(MyImportSelector.class)
: 使用一个实现了ImportSelector
接口的类,根据条件动态选择要导入的配置类。 -
@Import(MyImportBeanDefinitionRegistrar.class)
: 使用一个实现了ImportBeanDefinitionRegistrar
接口的类,允许自定义注册bean的逻辑。
这些方式允许你以不同的方式组合和导入配置类或组件,以满足应用程序的需求。@Import
通常与Spring的注解驱动配置一起使用,例如@Configuration
或@ComponentScan
,以更好地管理应用程序的组件和配置。
②@Import(AutoConfigurationPackages.Registrar.class)
@Import(AutoConfigurationPackages.Registrar.class)
用于导入 AutoConfigurationPackages.Registrar
这个类。这通常用于自动配置类(Auto-Configuration classes)中,以确保能够扫描到与自动配置相关的包。
使用AutoConfigurationPackages这个类注册程序包。如果没有指定基包或基包类,则会注册带注解类的包。
具体来说,AutoConfigurationPackages.Registrar
是Spring Boot内部使用的一个类,它的作用是将与自动配置相关的包注册到Spring应用程序的包扫描路径中。这样,Spring框架可以找到并加载与这些包相关的组件和配置。
在Spring Boot中,自动配置类通常包含在spring.factories
文件中,这些自动配置类负责自动配置应用程序的各个部分。为了确保这些自动配置类能够被发现并生效,@Import(AutoConfigurationPackages.Registrar.class)
通常用于这些自动配置类中。
具体地,AutoConfigurationPackages.Registrar
会注册自动配置类所在的包,以便Spring可以扫描和加载这些类。这有助于确保自动配置的生效,并使Spring Boot应用程序能够自动配置其所需的功能。
通常情况下,开发者无需显式使用 @Import(AutoConfigurationPackages.Registrar.class)
,它是在Spring Boot的自动配置机制内部使用的。但如果你需要编写自定义的自动配置类,你可能需要了解它的作用以正确配置包扫描路径。
2)@Import(AutoConfigurationImportSelector.class)
@Import(AutoConfigurationImportSelector.class)
用于自动配置类(Auto-Configuration classes)中,以根据条件自动导入其他配置类。它是Spring Boot自动配置机制的一部分,用于根据应用程序的环境和配置来动态选择和导入适当的配置类。
具体来说,AutoConfigurationImportSelector
是一个选择器,它根据应用程序的条件和配置来选择需要导入的自动配置类。这些自动配置类包含了应用程序所需的配置,以便自动配置各个部分。
在Spring Boot应用程序中,通常不需要显式使用 @Import(AutoConfigurationImportSelector.class)
,因为它是在内部由Spring Boot自动处理的。Spring Boot会自动根据应用程序的配置和依赖关系,选择并导入合适的自动配置类,以确保应用程序能够自动配置所需的功能。
总结起来,@Import(AutoConfigurationImportSelector.class)
是Spring Boot内部机制的一部分,用于根据应用程序的条件和配置来选择和导入自动配置类,以满足应用程序的需求。通常情况下,开发者无需手动使用此注解,Spring Boot会自动处理自动配置。
①AutoConfigurationImportSelector.class的selectImports方法
这个类代码挺多的,我这边只写一下里面重要的方法
selectImports方法会扫描类路径并找到所有的自动配置类。然后,对每个自动配置类,selectImports
方法会被调用,以确定是否要导入这个自动配置类。如果满足条件,该自动配置类的名称会被返回。
这个方法返回的是一个字符串数组,其中包含了要导入的自动配置类的全限定类名。这些自动配置类包含了应用程序所需的配置,以便启用各种功能和特性。
查看源码我们可以看到,selectImports(),方法调用了getAutoConfigurationEntry()方法,这个方法里面又有一个关键的方法getCandidateConfigurations()。
getCandidateConfigurations()方法借助SpringFactoriesLoader.loadFactoryNames()方法,扫描了所有包含META-INF/spring.factories的jar包,这些jar包实际上就是我们引入的starter中的依赖。
在loadFactoryNames()方法中加载spring.factories文件。
二、Debug验证
在AutoConfigurationImportSelector类的getCandidateConfigurations()方法的第一行打上断点,然后debug模式启动SpringBoot项目。
我们发现 configurations集合中存储了许多全类名,这些就是SpringBoot帮我们把依赖中的相关的组件装配到了IOC容器中。
比如我们项目中添加了注册中心nacos相关的依赖,可以看到nacos依赖的库中META-INF文件夹中有spring.factories文件,这个文件中定义了一些必要的组件全类名,SpringBoot根据这些就可以利用Java的反射机制为我们创建出这些对象,然后放到IOC容器中。
当然并不是所有依赖的库中的META-INF文件夹中都有spring.factories文件,spring.factories只是 Spring Boot 自动配置的一部分,如果你的项目并不使用这些特性,就不会存在这个文件。
三、总结
SpringBoot自动装配原理:
-
@EnableAutoConfiguration注解导入AutoConfigurationImportSelector类。
-
selectImports方法调用SpringFactoriesLoader.loadFactoryNames()扫描所有jar下面的对应的META-INF/spring.factories文件.
-
把所有在spring.factories文件中扫描到的全类名进行实例化加载到IOC容器中。
SpringBoot自动装配说白了就是自动帮我们把第三方的组件装配到IOC容器,不需要再手动的去写Bean相关的配置,因为大多数配置SpringBoot已经帮我们约定好了,也就是约定大于配置的理念。