SpringBoot - 自动装配
SpringBoot - 自动装配
SpringBoot 最核心的功能就是自动装配,
Starter 作为 SpringBoot 的核心功能之一,基于自动配置代码提供了自动配置模块及依赖的能力,让软件集成变得简单、易用。使用 SpringBoot 时,我们只需引人对应的 Starter,SpringBoot 启动时便会自动加载相关依赖,集成相关功能,这便是 SpringBoot 的自动装配功能。
简单概括其自动配置的原理:由@SpringBootAppliction组合注解中的@EnableAutoConfiguration注解开启自动配置,加载 spring.factories 文件中注册的各种 AutoConfiguration 配置类,当其 @Conditional 条件注解生效时,实例化该配置类中定义的 Bean,并注入 Spring 上下文。
SpringBoot 自动装配过程涉及以下主要内容:@EnableAutoConfiguration: 扫描类路径下的META-INF/spring.factories文件,并加载其中中注册的 AutoConfiguration 配置类,开启自动装配;
spring.factories:配置文件,位于 jar 包的 META-INF 目录下,按照指定格式注册了 AutoConfiguration 配置类;AutoConfiguration 类:自动配置类,SpringBoot 的大量以 xxxAutoConfiguration 命名的自动配置类,定义了三方组件集成 Spring 所需初始化的 Bean 和条件;@Conditional 条件注解及其行生注解:使用在 AutoConfiguration 类上,设置了配置类的实例化条件;Starter:三方组件的依赖及配置,包括 SpringBoot 预置组件和自定义组件,往往会包含 spring.factories 文件、AutoConfiguration 类和其他配置类。其功能间的作用关系如下图:
1. @EnableAutoConfiguration
2. @AutoConfigurationImportSelector
@EnableAutoConfiguration的自动配置功能是通过@Import注解导入的ImportSelector来完成的。 @Import(AutoConfigurationlmportSelector.class)是@EnableAutoConfiguration注解的组成部分,也是自动配置功能的核心实现者。下面讲解@Import的基本使用方法和ImportSelector的实现类AutoConfigurationlmportSelector。
2. @Import
@Import注解,提供了导入配置类的功能。SpringBoot 的源代码中,有大量的EnableXXX类都使用了该注解,了解@Import有助于我们理解 SpringBoot 的自动装配,@Import有以下三个用途:
通过@Import引入@Configuration注解的类;
导入实现了ImportSelector或ImportBeanDefinitionRegistrar的类;
通过@lmport导入普通的POJO。
3. AutoConfigurationlmportSelector 实现类
@Import的许多功能都需要借助接口ImportSelector来实现,ImportSelector决定可引人哪些 @Configuration的注解类,ImportSelector接口源码如下:
java 代码解读复制代码public interface ImportSelector {
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
ImportSelector接口只提供了一个参数为AnnotationMetadata的方法,返回的结果为一个字符串数组。其中参数AnnotationMetadata内包含了被@Import注解的类的注解信息。在selectimports方法内可根据具体实现决定返回哪些配置类的全限定名,将结果以字符串数组的形式返回。如果实现了接口ImportSelector的类的同时又实现了以下4个Aware接口,那么 Spring 保证在调用ImportSelector之前会先调用Aware接口的方法。这4个接口为:EnvironmentAware、BeanFactoryAware、 BeanClassLoaderAware和ResourceLoaderAware。
在AutoConfigurationlmportSelector的源代码中就实现了这4个接口:
四、@Conditional 注解
@Conditional 注解允许你根据特定的条件来动态配置 Spring Bean。换句话说,只有在特定条件满足的情况下,Spring 才会实例化和注入标注了 @Conditional 的 Bean。
@Conditional 注解本身并不包含具体的条件逻辑,而是依赖于实现了 Condition 接口的类来定义条件逻辑。使用时需要将实现了 Condition 接口的类作为参数传递给 @Conditional 注解。
1. Condition 接口
1 package org.springframework.context.annotation; 2 3 import org.springframework.core.type.AnnotatedTypeMetadata; 4 5 @FunctionalInterface 6 public interface Condition { 7 // 决定条件是否匹配 8 boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); 9 }
matches方法的第一个参数为ConditionContext,可通过该接口提供的方法来获得 Spring 应用的上下文信息;matches方法的第二个参数为AnnotatedTypeMetadata,该接口提供了访问特定类或方法的注解功能,可以用来检查带有@Bean注解的方法上是否还有其他注解。
2. conditional
1 @Target({ElementType.TYPE, ElementType.METHOD}) 2 @Retention(RetentionPolicy.RUNTIME) 3 @Documented 4 public @interface Conditional { 5 Class<? extends Condition>[] value(); 6 }
@Conditional 注解唯一的元素属性value是接口 Condition 的数组,只有在数组中指定的所有Condition的matches方法都返回true的情况下,被注解的类才会被加载
3. @Conditional 的衍生注解
Spring 提供了一些常用的 @Conditional 注解,用于处理常见的条件逻辑:
- @ConditionalOnProperty: 根据配置属性来判断是否注入 Bean。
- @ConditionalOnClass: 当类路径中存在特定的类时注入 Bean。
- @ConditionalOnMissingBean: 当容器中不存在特定的 Bean 时注入。
- @ConditionalOnBean: 当容器中存在特定的 Bean 时注入。
- @ConditionalOnWebApplication: 只有在 Web 应用环境中才注入 Bean。
- @ConditionalOnExpression: 根据 SpEL 表达式的结果来判断是否注入 Bean。
通过一个举例,我们看下衍生注解是如何发挥作用的。
1)spring.factories文件
我们在spring.factories文件中看到这一行自动配置类:

2)SpringApplicationAdminJmxAutoConfiguration实现类
其中有一个SpringApplicationAdminJmxAutoConfiguration实现类
1 # Auto Configure 2 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 3 org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ 4 org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ 5 org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ 6 org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ 7 org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
找到SpringApplicationAdminJmxAutoConfiguration这个类的源码:
1 @AutoConfiguration( 2 after = {JmxAutoConfiguration.class} 3 ) 4 @ConditionalOnProperty( 5 prefix = "spring.application.admin", 6 value = {"enabled"}, 7 havingValue = "true", 8 matchIfMissing = false 9 ) 10 public class SpringApplicationAdminJmxAutoConfiguration { 11 12 //... 13 14 public SpringApplicationAdminJmxAutoConfiguration() { 15 } 16 17 //... 18 }
3)@ConditionalOnProperty 注解
1 @Retention(RetentionPolicy.RUNTIME) 2 @Target({ElementType.TYPE, ElementType.METHOD}) 3 @Documented 4 @Conditional({OnPropertyCondition.class}) 5 public @interface ConditionalOnProperty { 6 String[] value() default {}; 7 8 String prefix() default ""; 9 10 String[] name() default {}; 11 12 String havingValue() default ""; 13 14 boolean matchIfMissing() default false; 15 }
这个注解中,各个属性的作用
1. prefix 指定了属性的前缀
比如:prefix = "spring.application.admin",它表示所有相关属性都应该以 spring.application.admin 开头。
例如,这里的完整属性名是 spring.application.admin.enabled。
2. value 指定了具体的属性名
value = {"enabled"},在这个例子中,它是 enabled。
与前缀结合,这个属性的完整名是 spring.application.admin.enabled。
3. havingValue 指定了配置属性的期望值
havingValue = "true",只有当 spring.application.admin.enabled 的值为 true 时,条件才会满足。
例如,只有在 application.properties 或 application.yml 文件中配置了 spring.application.admin.enabled=true 时,注解标注的配置才会生效。
4. matchIfMissing 指定了当配置属性缺失时是否默认匹配
matchIfMissing = false
如果 matchIfMissing 设置为 true,即使配置文件中没有 spring.application.admin.enabled 属性,条件也会匹配。
如果 matchIfMissing 设置为 false(如本例), 当配置文件中没有 spring.application.admin.enabled 属性时,条件不会匹配。
参考链接:https://juejin.cn/post/7137095650160115743