SpringBoot 自动装配原理
创始人
2024-03-15 23:07:20
0

什么是自动装配

  • springboot 定义一套接口规范,这套规范规定:springboot 在启动时会扫描外部引用 jar 包中的 META-INF/spring.factories 文件,将文件中配置的类型信息加载到 spring 容器,并执行类中定义的各种操作
  • 对于外部 jar 来说,只需要按照 springboot 定义的标准,就能将自己的功能装置进 springboot

自动装配的作用

  • 自动装配能够很大程度减少开发人员对 bean 的装配工作,只需要通过把对应的 bean 对象配置到对应工程下 META-INF/spring.factories,就能够装配到 spring 容器中

DeferredImportSelector 接口分析

  • springboot 的 AutoConfigurationImportSelector 类实现 DeferredImportSelector 接口,并且实现内部接口 Group,重写 Group 的 process() 和 selectImports() 方法
  • DeferredImportSelector 接口的 process() 和 selectImports() 方法,在 spring 调用bean定义注册后置处理器的时候会调用这个两个方法
  • process() 方法会获取 spring.factories 中用户定义的 bean 列表,selectImports() 方法获取将 process() 方法获取的 bean 对象列表包装成 Group 接口的内部类 Entry 对象
  • 在获取到 Entry 对象列表之后,将这些 bean 对象注册到容器中
  • 之后 spring 会对容器中的 bean 对象列表进行实例化和属性填充
/*** 继承 ImportSelector 接口*/
public interface DeferredImportSelector extends ImportSelector {/*** 返回 Group 接口实现类的 class*/@Nullabledefault Class getImportGroup() {return null;}/*** Group 接口,使用必须实现这个类*/interface Group {/*** 上面分组完成后 spring 会调用该方法,循环 List 里的 DeferredImportSelector 类,并循环调用 process()*/void process(AnnotationMetadata metadata, DeferredImportSelector selector);/*** 每个 Group 只执行一次,返回一个迭代器,spring 会使用迭代器的 forEach 方法进行迭代,想要导入 spring 容器的类要封装成 Entry 对象*/Iterable selectImports();/*** Entry 实体类,持有注解和需要导入的类名称*/class Entry {private final AnnotationMetadata metadata;private final String importClassName;public Entry(AnnotationMetadata metadata, String importClassName) {this.metadata = metadata;this.importClassName = importClassName;}public AnnotationMetadata getMetadata() {return this.metadata;}public String getImportClassName() {return this.importClassName;}@Overridepublic boolean equals(@Nullable Object other) {if (this == other) {return true;}if (other == null || getClass() != other.getClass()) {return false;}Entry entry = (Entry) other;return (this.metadata.equals(entry.metadata) && this.importClassName.equals(entry.importClassName));}@Overridepublic int hashCode() {return (this.metadata.hashCode() * 31 + this.importClassName.hashCode());}@Overridepublic String toString() {return this.importClassName;}}}}

自动装配实现原理

AutoConfigurationGroup 实现类分析

  • spring 在容器刷新的时候会调用这两个方法
  • 调用两个方法之后,用户定义的 bean 对象会被注入到 spring 容器中,之后会统一对bean对象进行实例化和属性填充
// 解析用户定义在 spring.factories 中的 bean 对象
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {// 确定是 AutoConfigurationImportSelector 子类Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,() -> String.format("Only %s implementations are supported, got %s",AutoConfigurationImportSelector.class.getSimpleName(),deferredImportSelector.getClass().getName()));// 从 "META-INF/spring.factories" 文件获取需要的自动配置类AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector).getAutoConfigurationEntry(annotationMetadata);// 将需要的类传入全局变量,以便 selectImports 方法使用this.autoConfigurationEntries.add(autoConfigurationEntry);for (String importClassName : autoConfigurationEntry.getConfigurations()) {this.entries.putIfAbsent(importClassName, annotationMetadata);}
}// 将获取出来的bean对象排序、过滤包装成 DeferredImportSelector.Group.Entry 对象
@Override
public Iterable selectImports() {// 没有需要自动装配的类,返回空集合if (this.autoConfigurationEntries.isEmpty()) {return Collections.emptyList();}// 去除不需要的Set allExclusions = this.autoConfigurationEntries.stream().map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());Set processedConfigurations = this.autoConfigurationEntries.stream().map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream).collect(Collectors.toCollection(LinkedHashSet::new));processedConfigurations.removeAll(allExclusions);// 排序,封装对象并返回集合return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream().map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName)).collect(Collectors.toList());
}

  • 获取 spring.factories 中的 bean 对象列表
// 获取 spring.factories 中的 bean 对象
protected AutoConfigurationEntry  getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}// 获取注解的属性的内容AnnotationAttributes attributes = getAttributes(annotationMetadata);// 获取候选 bean,获取 spring.factories 中定义的beanList configurations = getCandidateConfigurations(annotationMetadata, attributes);// 去重configurations = removeDuplicates(configurations);						// 去除排除的类					Set exclusions = getExclusions(annotationMetadata, attributes);			checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);configurations = getConfigurationClassFilter().filter(configurations);fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);}

流程总结

  • springboot 自动装配的流程
  • spring 容器刷新对 DeferredImportSelector 的处理

相关内容

热门资讯

聚杰微纤(300819)披露制... 截至2025年12月25日收盘,聚杰微纤(300819)报收于28.81元,较前一交易日上涨3.0%...
康曼德资本董事长丁楹:A股将进... 2025年A股在政策、估值、盈利、资金四重支撑下走出了牛市行情,但市场细分赛道的分化却愈发明显。20...
缅甸妙瓦底KK园区等已被强力拆... 视频来源:公安部微信公众号 记者12月25日从公安部获悉,近日,公安部派出工作组会同缅甸、泰国执法部...
盐田港(000088)披露公司... 截至2025年12月25日收盘,盐田港(000088)报收于4.55元,较前一交易日上涨0.66%,...
952名缅甸妙瓦底地区涉电诈犯... 来源:人民日报客户端 中缅泰联合开展清剿缅甸妙瓦底地区 赌诈园区行动 952名缅甸妙瓦底地区涉电诈犯...
原创 新... 最近几个赛季,孙铭徽一直都被视为广厦的“小外援”,距离他上一次场均得分不到两位数,还要追溯到2018...
意大利要求Meta暂停禁止竞争... 意大利已下令Meta公司暂停其禁止企业在WhatsApp上使用商业工具提供自家AI聊天机器人的政策。...
山西证券(002500)披露现... 截至2025年12月25日收盘,山西证券(002500)报收于6.11元,较前一交易日上涨0.33%...