解读SpringBoot为什么要用DeferredImportSelector
目录
- 为什么使用 DeferredImportSelector?
- DeferredImportSelector 的工作原理
- DeferredImportSelectorMjBovSMJXY 的优势
- DeferredImportSelector 的劣势
- DeferredImportSelector 的使用场景
- DeferredImportSelector 的示例
- 如何使用 DeferredImportSelector
- Spring Boot 自动配置中的应用
- 总结
DeferredImportSelector
是 Spring Framework 3.1 引入的 ImportSelector
接口的增强版本,主要用于延迟加载配置类,提升 Spring Boot 应用的启动速度。
它允许在所有配置类处理完毕后,再根据其他配置类的信息选择性地导入一些配置类。
为什么使用 DeferredImportSelector?
传统的 ImportSelector
会在配置类解析的早期阶段执行,这意味着在选择要导入的配置类时,它可能无法访问完整的配置信息,导致无法做出最佳选择。
DeferredImportSelector
解决了这个问题,它的执行会被延迟到所有常规配置类都被处理之后,此时它可以访问到所有配置类的信息,从而做出更明智的导入决策。
DeferredImportSelector 的工作原理
注册: 当 Spring 容器解析配置类时,如果发现一个类实现了 DeferredImportSelector
接口,它不会立即执行 selectImports()
方法,而是将该 DeferredImportSelector
的实例注册到一个 DeferredImportSelectorHandler
中。
延迟执行: 在所有配置类都处理完毕后,DeferredImportSelectorHandler
会负责执行所有注册的 DeferredImportSelector
。
分组和排序 (可选): DeferredImportSelector
可以实现 DeferredImportSelector.Group
接口,将多个 DeferredImportSelector
分组,并按组进行排序。 Spring Boot 允许对 DeferredImportSelector.Group
进行排序以控制执行顺序。
selectImports()
方法: 在 selectImports()
方法中,DeferredImportSelector
可以访问到整个 Spring 容器的配置信息,例如:
- 已经注册的 Bean 定义。
- 已经加载的配置类。
- 环境信息 (Environment)。
返回要导入的配置类: selectImports()
方法返回一个 String 数组,包含了要导入的配置类的全限定名。 Spring 容器会根据这些全限定名来导入相应的配置类,并注册 Bean。
DeferredImportSelector 的优势
- 延迟加载: 避免过早加载不必要的配置类,提升启动速度。
- 更智能的配置选择: 基于已加载的配置信息,做出更精确的配置选择。
- 条件化配置: 实现更复杂的条件化配置逻辑。
- 排序和分组: 控制
DeferredImportSelector
的执行顺序。
DeferredImportSelector 的劣势
- 更复杂: 比
ImportSelector
更复杂,需要理解延迟加载和分组排序的机制。 - 调试难度增加: 由于是延迟执行,调试时可能需要更多步骤。
DeferredImportSelector 的使用场景
- 自动配置: Spring Boot 的自动配置机制大量使用了
DeferredImportSelector
。 例如,EnableAutoConfiguration
注解使用AutoConfigurationImportSelector
来选择需要导入的自动配置类。 - 条件化配置: 根据某个 Bean 是否存在,或者某个配置属性的值来选择是否导入某个配置类。
- 模块化: 将应用分解为多个模块,根据已加载的模块信息来选择导入其他模块的配置。
DeferredImportSelector 的示例
import org.springframework.context.annotation.DeferredImportSelector; import org.springframework.core.type.AnnotationMetadata; public class MyDeferredImportSelector implements DeferredImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // 可以获取注解信息 importingClassMetadata // 可以访问 Spring 容器中的 Bean 定义 // 根据条件选择导入不同的配置类 if (conditionA()) { return new String[] { "com.example.config.ConfigA" }; } else { return new String[] { "com.example.config.ConfigB" }; } } private boolean conditionA() { // 实现条件逻辑 return true; // 示例:始终返回 true } }
示例:分组和排序
import org.springframework.context.annotation.DeferredImportSelector; import org.springframework.core.type.AnnotationMetadata; import Java.util.ArrayList; import java.util.List; import java.util.Objects; public class MyDeferredImportSelector implements DeferredImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{"com.example.MyConfig"}; } @Override public Class<? extends Group> getImportGroup() { return MyGroup.class; } public static class MyGroup implements Group { private final List<Entry> entries = new ArrayList<>(); @Override public void process(AnnotationMetadata meta编程data, DeferredImportSelector importSelector) { // 可以根据metadata和importSelector的信息来决定是否添加entry entries.add(new Entry(metadata, importSelector.selectImports(metadata))); } @Override public Iterable<Entry> selectImports() { // 返回需要导入的类的列表,这里可以对entries进行排序,控制导入的顺序 return entries; } } }
如何使用 DeferredImportSelector
- 实现
DeferredImportSelector
接口: 创建一个类并实现DeferredImportSelector
接口,并重写selectImports()
方法。 - 实现
getImportGroup()
方法 (可选): 如果需要分组和排序,则实现getImportGroup()
并返回一个实现了Group
接口的类。 - 注册
DeferredImportSelector
: 可以通过@Import
注解,或者在META-INF/spring.factories
文件中注册DeferredImportSelector
。
Spring Boot 自动配置中的应用
Spring Boot 的自动配置机制利用 DeferredImportSelectorjs
实现了延迟加载和条件化配置。
@EnableAutoConfiguration
注解: 这个注解触发了自动配置机制。AutoConfigurationImportSelector
:@EnableAutoConfiguration
最终会使用AutoConfigurationImportSelector
这个D编程客栈eferredImportSelector
。spring.factories
文件:AutoConfigurationImportSelector
从phpMETA-INF/spring.factories
文件中读取org.springframework.boot.autoconfigure.EnableAutoConfiguration
键对应的自动配置类列表。- 条件化过滤:
AutoConfigurationImportSelector
会根据 Spring 容器中的条件 (例如,是否存在某个 Bean,或者某个配置属性的值) 来过滤这些自动配置类,只选择符合条件的自动配置类进行导入。
总结
DeferredImportSelector
是 Spring Boot 中一个重要的特性,它允许延迟加载和条件化配置,从而提升应用的启动速度和灵活性。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。
精彩评论