Spring Boot自动装配

这篇具有很好参考价值的文章主要介绍了Spring Boot自动装配。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

自动装配是 Spring Boot 最核心的功能之一,第三方可以基于这个特性非常方便的和 Spring 做整合,实现自己的 Starter,做到开箱即用。
Java 早期并不支持注解,所以那会儿 Spring 只能通过 xml 的形式来配置。早期项目里要引入一个功能模块,首先我们要引入 SDK,然后在 xml 里配置所需的 bean。随着引入的模块越来越多,开发者很快陷入 xml 的旋涡之中。
Spring 3.0 时代,官方开始提供@Import注解实现自动装配的能力,同时也伴随了一堆以@EnableXXX命名风格的注解,顾名思义加上这些注解就能启用对应的能力,这俩注解一般配合使用。
到了 Spring Boot 时代,自动装配再度迎来升级,它在@Import基础上增加了 SPI 的能力,而且还支持条件装配,使用上更加灵活。

理解自动装配

什么是自动装配???
跟自动装配相对立的就是手动装配,早期我们通过 xml 手动往容器里注册 bean 的方式就是手动装配。手动装配的缺点是:

  • 使用麻烦,需要维护一堆 xml
  • 使用门槛高,开发者需要知道配置细节

反之,自动装配就是开发者根据 Spring Boot 定制的规范编写AutoConfiguration类,Spring Boot 会自动加载这些配置类并把对应的 bean 注册到容器,这些 bean 是具备某种能力的,这样第三方就可以很轻松的把自己要提供的功能装进 Spring Boot。有了自动装配,开发者仅需加上少量注解或配置,甚至什么都不加(约定大于配置),就可以为项目引入一个功能模块。

装配的是什么???
从广义上理解,装配的是模块、是组件、是一个具体的功能。从狭义上理解,装配的其实是一个个具备某种能力的 bean。

自动装配是怎么实现的???
通过一个叫@EnableAutoConfiguration的注解往容器导入了一个叫AutoConfigurationImportSelector的类,它实现了ImportSelector接口,Spring 启动时会触发子类方法按照规则加载自动装配类。

设计实现

在使用 Spring Boot 开发时,我们一般会在启动类上加@SpringBootApplication注解,它就是自动装配的入口。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    ......
}

它是一个复合注解,里面还集成了 Spring 提供的一些其它注解,从名字就能看出来,与自动装配有关的是@EnableAutoConfiguration注解。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    
	Class<?>[] exclude() default {};

	String[] excludeName() default {};
}

@EnableAutoConfiguration也是一个复合注解,它最核心的功能就是往容器导入了AutoConfigurationImportSelector类。
Spring Boot自动装配,Spring Boot,spring boot,java,后端
AutoConfigurationImportSelector 实现了各种 Aware 接口,具备 BeanFactory、BeanClassLoader 等感知能力。最重要的是它实现了 DeferredImportSelector 接口,DeferredImportSelector 又继承自 ImportSelector。
ImportSelector 接口用来向容器注册批量导入配置类,子类重写selectImports()返回要导入的类的全限定名数组:

public interface ImportSelector {

	String[] selectImports(AnnotationMetadata importingClassMetadata);

	@Nullable
	default Predicate<String> getExclusionFilter() {
		return null;
	}
}

子接口 DeferredImportSelector 的区别是二者导入的时机不同,ImportSelector 会在@Configuration Bean 处理前调用,DeferredImportSelector 会等处理完所有的@Configuration Bean 之后再调用。
所以,Spring 启动时会先触发AutoConfigurationImportSelector.AutoConfigurationGroup#process收集要导入的类,再触发selectImports()返回导入项的迭代器。

@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
    Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
            () -> String.format("Only %s implementations are supported, got %s",
                    AutoConfigurationImportSelector.class.getSimpleName(),
                    deferredImportSelector.getClass().getName()));
    // 获取要导入的自动配置类
    AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
            .getAutoConfigurationEntry(annotationMetadata);
    this.autoConfigurationEntries.add(autoConfigurationEntry);
    for (String importClassName : autoConfigurationEntry.getConfigurations()) {
        this.entries.putIfAbsent(importClassName, annotationMetadata);
    }
}

核心是getAutoConfigurationEntry(),它会按照 Spring Boot 的规范加载自动装配类,去重后再移除掉需要被排除的类,接着触发一个 AutoConfigurationImportListener 监听事件,最后返回收集到的类。

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    // 可以通过配置spring.boot.enableautoconfiguration=false来禁用自动装配
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    // 加载候选配置类
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    // 去重 转HashSet
    configurations = removeDuplicates(configurations);
    // 移除掉要排除的类
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    configurations = getConfigurationClassFilter().filter(configurations);
    // 触发AutoConfigurationImportListener监听事件
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}

Spring Boot 会按照什么规则加载配置类呢?方法是getCandidateConfigurations(),它会加载候选的配置类,有两套加载规则:

  • 读取 ClassPath 下META-INF/spring.factories文件里以org.springframework.boot.autoconfigure.EnableAutoConfiguration为 Key 配置的类
  • 读取 ClassPath 下META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件里配置的所有类

第一套规则更多的是给第三方提供的口子,第二套规则是 Spring Boot 导入内部配置类的口子。

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    /**
     * 读取ClassPath下META-INF/spring.factories文件里
     * 被org.springframework.boot.autoconfigure.EnableAutoConfiguration标注的类
     */
    List<String> configurations = new ArrayList<>(
            SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
    /**
     * 读取ClassPath下META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
     * 文件里配置的类都要导入
     */
    ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
    return configurations;
}

读取文件加载配置类用到了 Spring 提供的 SpringFactoriesLoader 类,代码不复杂,这里就不赘述了。
我们重点看一下,Spring Boot 内部都提供了哪些配置类,文件路径在spring-boot-autoconfigure/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,官方默认提供了 144 个自动装配类,这里贴几个示例。

org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration
......

这些配置类基本从名字就可以看出它们的功能,例如:AopAutoConfiguration 用来配置切面编程相关的 bean;RabbitAutoConfiguration 用来配置 RabbitMQ 相关的 bean。
自动配置类本身会作为 bean 注册到容器,除此之外还可以通过@Bean注解方法的形式注册 bean。如果要提供的功能比较复杂,不想所有的代码都耦合在一个类里面,还可以在配置类上继续加@Import注解引入另一个配置类。

条件配置
官方一股脑提供了 144 个自动配置类,我们不一定都需要啊,所以条件配置诞生了。
条件配置的意思是,可以给自动配置类加上一些前置条件,只有这些条件都满足了,配置类才会生效。条件配置伴随的是一堆以@ConditionalXXX命名风格的注解,这里举几个常用的:

  • @ConditionalOnBean:容器存在满足条件的 bean 才生效
  • @ConditionalOnClass:容器存在满足条件的 Class 才生效
  • @ConditionalOnMissingBean:容器不存在满足条件的 bean 才生效
  • @ConditionalOnMissingClass:容器不存在满足条件的 Class 才生效
  • @ConditionalOnWebApplication:必须是指定类型的 Web 应用环境才生效

有了条件配置,即使官方一股脑提供了一堆自动配置类,很多也都是不会生效的,要想生效我们得引入相关的依赖和配置。
以 RabbitAutoConfiguration 为例,它的生效条件是存在 RabbitTemplate.class、Channel.class,如果我们没有引入相关依赖,这些类肯定是不存在的,配置类自然也就不会生效了。

@AutoConfiguration
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import({ RabbitAnnotationDrivenConfiguration.class, RabbitStreamConfiguration.class })
public class RabbitAutoConfiguration {
    
}

尾巴

所谓的自动装配,就是 Spring Boot 程序在启动时会去扫描 ClassPath 下的META-INF/spring.factories文件,自动把 AutoConfiguration 类注册到容器,免去了开发者需要自己配置 bean 的麻烦过程。Spring Boot 一股脑提供了 144 个自动配置类,绝大多数开发者并不需要,所以提供了基于条件的自动配置,只有前置条件都满足了,配置类才会生效。基于自动装配和约定大于配置的设计理念,开发者仅需编写少量配置甚至不写任何配置就可以方便的引入一个功能模块。文章来源地址https://www.toymoban.com/news/detail-817769.html

到了这里,关于Spring Boot自动装配的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入了解Spring Boot自动装配

    Spring Boot的自动装配是一项强大的功能,能够简化应用程序的配置和开发过程。让我们通过一系列详细的例子来深入了解这一特性。 在Spring Boot中,自动装配是指框架根据应用程序的依赖关系,自动配置和装配相应的Bean,而无需手动设置。这使得开发者可以更专注于业务逻辑

    2024年01月23日
    浏览(43)
  • Spring Boot如何实现自动装配

    Spring Boot的自动装配是它的一大特点,可以大大提高开发效率,减少重复性代码的编写。本文将详细讲解Spring Boot如何实现自动装配。 在传统的Spring框架中,我们需要手动配置和管理Bean的依赖关系,但在Spring Boot中,大量的配置可以自动完成。这是因为Spring Boot中引入了自动装

    2024年02月04日
    浏览(37)
  • Spring Boot源码解析 - 自动装配原理

    Spring Boot 自动装配是 Spring Boot 框架的一个关键特性,它的目标是让开发者能够快速构建 Spring 应用程序,减少繁琐的配置工作。   @SpringApplication 从启动类 @SpringApplication 注解入手, @SpringBootApplication 是一个组合注解,它是 Spring Boot 框架中常用的一个主要注解之一。它结合了

    2024年01月19日
    浏览(42)
  • Spring Boot中自动装配机制的原理

    1 .自动装配,简单来说就是自动把第三方组件的Bean装载到Spring IOC容器里面 ,不需要开发人员再去写Bean的装配配置, 2.在Spring Boot应用里面,只需要在启动类加上 @SpringBootApplication 注解就可以实现自动装配。 3.@SpringBootApplication是一个复合注解, 真正实现自动装配的注解是@

    2024年02月10日
    浏览(32)
  • 【Spring Boot 源码学习】自动装配流程源码解析(上)

    《Spring Boot 源码学习系列》 上篇博文,笔者带大家从整体上了解了AutoConfigurationImportSelector 自动装配逻辑的核心功能及流程,由于篇幅有限,更加细化的功能及流程详解还没有介绍。本篇开始将从其源码入手,重点解析细化后的自动装配流程源码。 在开始本篇的内容介绍之前

    2024年02月14日
    浏览(38)
  • 【Spring Boot 源码学习】自动装配流程源码解析(下)

    《Spring Boot 源码学习系列》 上篇博文,笔者带大家了解了自动装配流程中有关自动配置加载的流程; 本篇将介绍自动装配流程剩余的内容,包含了自动配置组件的排除和过滤、触发自动配置事件。 在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,

    2024年02月11日
    浏览(34)
  • 【Spring Boot自动装配原理详解与常见面试题】—— 每天一点小知识

                                                                  💧 S p r i n g B o o t 自动装配原理详解与常见面试题 color{#FF1493}{Spring Boot自动装配原理详解与常见面试题} Sp r in g B oo t 自动装配原理详解与常见面试题 💧           🌷 仰望天空

    2024年02月16日
    浏览(43)
  • 拆解Spring boot:Springboot为什么如此丝滑而简单?源码剖析解读自动装配

    🎉🎉欢迎光临,终于等到你啦🎉🎉 🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀 🌟持续更新的专栏 《Spring 狂野之旅:从入门到入魔》 🚀 本专栏带你从Spring入门到入魔   这是苏泽的个人主页可以看到我其他的内容哦👇👇 努力的苏泽 http://suzee.blog.csdn

    2024年03月23日
    浏览(42)
  • 微信小程序的授权登录-Java 后端 (Spring boot)

    微信开发文档链接:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html 一个可以测试的微信小程序 此微信小程序的APPID和APPscret(至开发者后台获取) 从时序图我们可以了解到流程大致分为两步: 小程序端获取code后传给Java后台 Java后台获取code后向微信后台接口

    2024年02月09日
    浏览(51)
  • “从零开始学习Spring Boot:快速搭建Java后端开发环境“

    标题:从零开始学习Spring Boot:快速搭建Java后端开发环境 摘要:本文将介绍如何从零开始学习Spring Boot,并详细讲解如何快速搭建Java后端开发环境。通过本文的指导,您将能够快速搭建一个基于Spring Boot的Java后端开发环境并开始编写代码。 正文: 一、准备工作 在开始之前,

    2024年02月15日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包