SpringBoot自动装配详解

SpringBoot自动装配

在讲之前先了解一下,手动装配的流程是怎么样的,毕竟没有对比就没有伤害嘛😁

在没有Spring Boot的情况下,你需要手动配置和添加相关依赖,以实现类似于Spring Boot自动装配的功能。主要步骤:

  1. 引入Spring相关依赖: 首先,你需要引入Spring框架的相关依赖,包括核心容器(spring-context)、AOP(spring-aop)、数据访问(spring-jdbc、spring-orm)、事务管理(spring-tx)、Web(spring-web)等,具体依赖根据项目需求而定。

    <!-- Spring Core Container -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.10.RELEASE</version> 
    </dependency>
    
    <!-- Spring AOP -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.3.10.RELEASE</version>
    </dependency>
    
    <!-- 其他Spring相关依赖... -->
    
  2. 手动配置Spring配置文件: 在没有Spring Boot的情况下,你需要手动创建Spring的配置文件(例如XML配置文件)来定义和配置Spring容器中的Bean、数据源、事务管理等。

    <!-- applicationContext.xml -->
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!-- 配置数据源、事务管理、其他Bean... -->
        
    </beans>
    
  3. 手动扫描组件和配置类: Spring Boot自动扫描组件的特性在没有Spring Boot的情况下需要手动配置。你可以通过在配置文件中添加 <context:component-scan> 元素来启用组件扫描。

    <!-- applicationContext.xml -->
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
           xmlns:context="http://www.springframework.org/schema/context">
    
        <context:component-scan base-package="com.example" />
        
    </beans>
    
  4. 手动配置Web应用(如果有): 如果你的项目是一个Web应用,你需要手动配置Servlet、Filter、Listener等。

    <!-- web.xml -->
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
    
        <!-- 配置Servlet、Filter、Listener等... -->
        
    </web-app>
    

而在SpringBoot中,你不需要写这一大堆的xml配置文件,很多配置只需要通过Spring Boot 的全局配置文件 application.propertiesapplication.yml进行修改,比如更换端口号,配置 JPA 属性等等。

优点👌:因为Spring Boot提供了自动装配、默认配置和内嵌服务器等功能,让你更专注于业务逻辑的开发而不用过多关心底层配置

进入正题
什么是SpringBoot自动装配?

Spring Boot 的自动装配(Auto-Configuration)原理是基于Spring Framework的条件化配置和@EnableAutoConfiguration注解实现的。这种机制允许开发者在项目中引入相关的依赖,Spring Boot 将根据这些依赖自动配置应用程序的上下文和功能。

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

例如在SpringBoot项目中,引入Redis,只需要在Maven中,引入一个Redis的starter

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

然后在配置文件中写下Redis的配置就可以调用Redis的服务,这就是SpringBoot的强大之处

在这里插入图片描述

在这里插入图片描述

通俗来讲,自动装配就是通过注解或一些简单的配置就可以在SpringBoot的帮助下开启和配置各种功能,比如数据库访问、Web开发

SpringBoot自动装配原理

首先点进@SpringBootApplication注解的内部

在这里插入图片描述

让我们逐个解释这些注解的作用:

  1. @Target({ElementType.TYPE}): 该注解指定了这个注解可以用来标记在类上。在这个特定的例子中,这表示该注解用于标记配置类。
  2. @Retention(RetentionPolicy.RUNTIME): 这个注解指定了注解的生命周期,即在运行时保留。这是因为 Spring Boot 在运行时扫描类路径上的注解来实现自动配置,所以这里使用了 RUNTIME 保留策略。
  3. @Documented: 该注解表示这个注解应该被包含在 Java 文档中。它是用于生成文档的标记,使开发者能够看到这个注解的相关信息。
  4. @Inherited: 这个注解指示一个被标注的类型是被继承的。在这个例子中,它表明这个注解可以被继承,如果一个类继承了带有这个注解的类,它也会继承这个注解。
  5. @SpringBootConfiguration: 这个注解表明这是一个 Spring Boot 配置类。如果点进这个注解内部会发现与标准的 @Configuration 没啥区别,只是为了表明这是一个专门用于 Spring Boot 的配置。
  6. @EnableAutoConfiguration: 这个注解是 Spring Boot 自动装配的核心。它告诉 Spring Boot 启用自动配置机制,根据项目的依赖和配置自动配置应用程序的上下文。通过这个注解,Spring Boot 将尝试根据类路径上的依赖自动配置应用程序。
  7. @ComponentScan: 这个注解用于配置组件扫描的规则。在这里,它告诉 Spring Boot 在指定的包及其子包中查找组件,这些组件包括被注解的类、@Component 注解的类等。其中的 excludeFilters 参数用于指定排除哪些组件,这里使用了两个自定义的过滤器,分别是 TypeExcludeFilterAutoConfigurationExcludeFilter

看下来,其实@SpringBootApplication可以看作是@Configuration、@EnableAutoConfiguration、@ComponentScan的组合

@EnableAutoConfiguration

这个注解是实现自动装配的核心注解

在这里插入图片描述

  1. @AutoConfigurationPackage,将项目src中main包下的所有组件注册到容器中,例如标注了Component注解的类等等

  2. @Import({AutoConfigurationImportSelector.class}),是自动装配的核心,👇就来分析一下它

AutoConfigurationImportSelector

AutoConfigurationImportSelector 是 Spring Boot 中一个重要的类,它实现了 ImportSelector 接口,用于实现自动配置的选择和导入。具体来说,它通过分析项目的类路径和条件来决定应该导入哪些自动配置类。

代码太多,选取部分主要功能的代码

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    
    // ... (其他方法和属性)

  // 获取所有符合条件的类的全限定类名,例如RedisTemplate的全限定类名(org.springframework.data.redis.core.RedisTemplate;),这些类需要被加载到 IoC 容器中。
	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		// 扫描类路径上的 META-INF/spring.factories 文件,获取所有实现了 AutoConfiguration 接口的自动配置类
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);

		// 过滤掉不满足条件的自动配置类,比如一些自动装配类
		configurations = filter(configurations, annotationMetadata, attributes);

		// 排序自动配置类,根据 @AutoConfigureOrder 和 @AutoConfigureAfter/@AutoConfigureBefore 注解指定的顺序
		sort(configurations, annotationMetadata, attributes);

		// 将满足条件的自动配置类的类名数组返回,这些类将被导入到应用程序上下文中
		return StringUtils.toStringArray(configurations);
	}

	// ... (其他方法)
	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		// 获取自动配置类的候选列表,从 META-INF/spring.factories 文件中读取
		// 通过类加载器加载所有候选类
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());

		// 过滤出实现了 AutoConfiguration 接口的自动配置类
		configurations = configurations.stream()
				.filter(this::isEnabled)
				.collect(Collectors.toList());

		// 对于 Spring Boot 1.x 版本,还需要添加 spring-boot-autoconfigure 包中的自动配置类
		// configurations.addAll(getAutoConfigEntry(getAutoConfigurationEntry(metadata)));
		return configurations;
	}

	// ... (其他方法)
	protected List<String> filter(List<String> configurations, AnnotationMetadata metadata,
			AnnotationAttributes attributes) {
		// 使用条件判断机制,过滤掉不满足条件的自动配置类
		configurations = configurations.stream()
				.filter(configuration -> isConfigurationCandidate(configuration, metadata, attributes))
				.collect(Collectors.toList());
		return configurations;
	}

	// ... (其他方法)
	protected void sort(List<String> configurations, AnnotationMetadata metadata,
			AnnotationAttributes attributes) {
		// 根据 @AutoConfigureOrder 和 @AutoConfigureAfter/@AutoConfigureBefore 注解指定的顺序对自动配置类进行排序
		configurations.sort((o1, o2) -> {
			int i1 = getAutoConfigurationOrder(o1, metadata, attributes);
			int i2 = getAutoConfigurationOrder(o2, metadata, attributes);
			return Integer.compare(i1, i2);
		});
	}
  
  	// ... (其他方法)

}

梳理一下😂,以下是 AutoConfigurationImportSelector 的主要工作:

  1. 扫描类路径: 在应用程序启动时,AutoConfigurationImportSelector 会扫描类路径上的 META-INF/spring.factories 文件,这个文件中包含了各种 Spring 配置和扩展的定义。在这里,它会查找所有实现了 AutoConfiguration 接口的类,具体的实现为getCandidateConfigurations方法。
  2. 条件判断: 对于每一个发现的自动配置类,AutoConfigurationImportSelector 会使用条件判断机制(通常是通过 @ConditionalOnXxx 注解)来确定是否满足导入条件。这些条件可以是配置属性、类是否存在、Bean是否存在等等。

​ 例如:下面这个配置类,只有在RabbitTemplate.class, Channel.class存在才会去加载

@Configuration
// 检查相关的类:RabbitTemplate 和 Channel是否存在
// 存在才会加载
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
}

有兴趣的童鞋可以详细了解下 Spring Boot 提供的条件注解

  • @ConditionalOnBean:当容器里有指定 Bean 的条件下
  • @ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下
  • @ConditionalOnSingleCandidate:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean
  • @ConditionalOnClass:当类路径下有指定类的条件下
  • @ConditionalOnMissingClass:当类路径下没有指定类的条件下
  • @ConditionalOnProperty:指定的属性是否有指定的值
  • @ConditionalOnResource:类路径是否有指定的值
  • @ConditionalOnExpression:基于 SpEL 表达式作为判断条件
  • @ConditionalOnJava:基于 Java 版本作为判断条件
  • @ConditionalOnJndi:在 JNDI 存在的条件下差在指定的位置
  • @ConditionalOnNotWebApplication:当前项目不是 Web 项目的条件下
  • @ConditionalOnWebApplication:当前项目是 Web 项 目的条件下
  1. 根据条件导入自动配置类: 满足条件的自动配置类将被导入到应用程序的上下文中。这意味着它们会被实例化并应用于应用程序的配置。

懂了上面这些,我们其实可以自己实现一个Starter,非常简单

自定义Starter

第一步,创建threadpool-spring-boot-starter工程

img

第二步,引入 Spring Boot 相关依赖

img

第三步,创建ThreadPoolAutoConfiguration

img

第四步,在threadpool-spring-boot-starter工程的 resources 包下创建META-INF/spring.factories文件

img

最后新建工程引入threadpool-spring-boot-starter

img

测试通过!!!

img

总结

Spring Boot 通过@EnableAutoConfiguration开启自动装配,通过 SpringFactoriesLoader 最终加载META-INF/spring.factories中的自动配置类实现自动装配,自动配置类其实就是通过@Conditional按需加载的配置类,想要其生效必须引入spring-boot-starter-xxx包实现起步依赖

希望这篇文章能够帮助你更好地理解SpringBoot自动装配,Happy coding! 🚀;点个关注,关注更多干货😘

参考链接:https://javaguide.cn/system-design/framework/spring/spring-boot-auto-assembly-principles.html

  • 23
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot自动装配原理是基于 Spring 框架的核心特性之一,即依赖注入(Dependency Injection)和控制反转(Inversion of Control)。通过自动装配SpringBoot 可以根据一定的规则,自动将需要的依赖对象注入到相应的组件中,简化了开发者的配置工作。 在 SpringBoot 中,自动装配主要通过以下几个步骤实现: 1. ComponentScan:SpringBoot 会根据指定的包路径进行组件扫描,找到所有被注解标记的组件,如 @Component、@Service、@Repository 等。 2. ConditionalOnClass/ConditionalOnMissingClass:SpringBoot 会根据类路径中是否存在指定的类来判断是否需要装配某个组件。当类存在时,装配该组件;当类不存在时,跳过该组件。 3. ConditionalOnBean/ConditionalOnMissingBean:SpringBoot 会根据容器中是否存在指定的 Bean 来判断是否需要装配某个组件。当 Bean 存在时,跳过该组件;当 Bean 不存在时,装配该组件。 4. EnableAutoConfiguration:SpringBoot 提供了一系列以 Enable 开头的注解,用于开启特定功能的自动配置。这些注解会在特定条件下加载一些默认的配置类,将默认的配置注入到容器中。 5. 自定义配置:除了 SpringBoot 提供的默认自动配置之外,开发者还可以通过自定义配置文件(application.properties 或 application.yml)来覆盖默认配置,实现个性化的自动装配。 总的来说,SpringBoot自动装配原理就是根据一系列的条件和规则,将需要的依赖对象自动注入到相应的组件中,简化了开发者的配置工作,提高了开发效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值