优化@Conditional

master
xuchengsheng 2023-10-12 22:41:02 +08:00
parent 86d9800367
commit 9dd99636b9
1 changed files with 35 additions and 29 deletions

View File

@ -1,25 +1,31 @@
## @Conditional ## @Conditional
- [@Conditional](#conditional) - [@Conditional](#conditional)
- [一、注解描述](#一注解描述) - [一、基本信息](#一基本信息)
- [二、注解源码](#二注解源码) - [二、注解描述](#二注解描述)
- [三、主要功能](#三主要功能) - [三、注解源码](#三注解源码)
- [四、最佳实践](#四最佳实践) - [四、主要功能](#四主要功能)
- [4.1、在@Bean上使用](#41在bean上使用) - [五、最佳实践](#五最佳实践)
- [4.2、在@Configuration上使用](#42在configuration上使用) - [在@Bean上使用](#在bean上使用)
- [4.3、自定义组合注解](#43自定义组合注解) - [在@Configuration上使用](#在configuration上使用)
- [五、时序图](#五时序图) - [自定义组合注解](#自定义组合注解)
- [六、源码分析](#六源码分析) - [六、时序图](#六时序图)
- [七、注意事项](#七注意事项) - [七、源码分析](#七源码分析)
- [八、总结](#八总结) - [八、注意事项](#八注意事项)
- [8.1、最佳实践总结](#81最佳实践总结) - [九、总结](#九总结)
- [8.2、源码分析总结](#82源码分析总结) - [最佳实践总结](#最佳实践总结)
- [源码分析总结](#源码分析总结)
### 一、注解描述
### 一、基本信息
✒️ **作者** - Lex 📝 **博客** - [我的CSDN](https://blog.csdn.net/duzhuang2399/article/details/133800722) 📚 **文章目录** - [所有文章](https://github.com/xuchengsheng/spring-reading) 🔗 **源码地址** - [@Conditional源码](https://github.com/xuchengsheng/spring-reading/tree/master/spring-annotation/spring-annotation-conditional)
### 二、注解描述
`@Conditional`注解是用来基于满足某些特定条件来决定一个Bean是否应该被注册到Spring容器的。这提供了一种灵活的方式来根据环境、配置或其他因素来决定是否激活或者创建某个Bean。 `@Conditional`注解是用来基于满足某些特定条件来决定一个Bean是否应该被注册到Spring容器的。这提供了一种灵活的方式来根据环境、配置或其他因素来决定是否激活或者创建某个Bean。
### 二、注解源码 ### 、注解源码
`@Conditional`注解是 Spring 框架自 3.0 版本开始引入的一个核心注解,用于指示一个组件只在所有指定条件匹配时才能被注册。 `@Conditional`注解是 Spring 框架自 3.0 版本开始引入的一个核心注解,用于指示一个组件只在所有指定条件匹配时才能被注册。
@ -60,7 +66,7 @@ public @interface Conditional {
} }
``` ```
### 、主要功能 ### 、主要功能
1. **条件化 Bean 注册** 1. **条件化 Bean 注册**
+ 可以根据特定的条件来决定是否创建并注册一个 Bean。这允许我们根据环境、配置或其他因素动态地选择哪些 Bean 需要被实例化。 + 可以根据特定的条件来决定是否创建并注册一个 Bean。这允许我们根据环境、配置或其他因素动态地选择哪些 Bean 需要被实例化。
@ -75,9 +81,9 @@ public @interface Conditional {
6. **不支持继承** 6. **不支持继承**
+ `@Conditional` 注解本身不是继承的,因此,从父类或接口继承的条件不会被子类考虑。 + `@Conditional` 注解本身不是继承的,因此,从父类或接口继承的条件不会被子类考虑。
### 、最佳实践 ### 、最佳实践
#### 4.1、在@Bean上使用 #### 在@Bean上使用
首先来看看启动类入口,首先设置一个系统属性`enable.bean`为`true`,然后上下文环境使用`AnnotationConfigApplicationContext`此类是使用Java注解来配置Spring容器的方式构造参数我们给定了一个`MyConfiguration`组件类最后打印了Spring上下文中所有的bean定义名称。 首先来看看启动类入口,首先设置一个系统属性`enable.bean`为`true`,然后上下文环境使用`AnnotationConfigApplicationContext`此类是使用Java注解来配置Spring容器的方式构造参数我们给定了一个`MyConfiguration`组件类最后打印了Spring上下文中所有的bean定义名称。
@ -151,7 +157,7 @@ beanDefinitionName = myBeanConfiguration
beanDefinitionName = user2 beanDefinitionName = user2
``` ```
#### 4.2、在@Configuration上使用 #### 在@Configuration上使用
首先来看看启动类入口,首先设置一个系统属性`enable.config`为`true`,然后上下文环境使用`AnnotationConfigApplicationContext`此类是使用Java注解来配置Spring容器的方式构造参数我们给定了一个`MyConfiguration`组件类最后打印了Spring上下文中所有的bean定义名称。 首先来看看启动类入口,首先设置一个系统属性`enable.config`为`true`,然后上下文环境使用`AnnotationConfigApplicationContext`此类是使用Java注解来配置Spring容器的方式构造参数我们给定了一个`MyConfiguration`组件类最后打印了Spring上下文中所有的bean定义名称。
@ -224,7 +230,7 @@ beanDefinitionName = user4
无任何bean 无任何bean
``` ```
#### 4.3、自定义组合注解 #### 自定义组合注解
首先来看看启动类入口,首先设置一个系统属性`enable.custom`为`true`,然后上下文环境使用`AnnotationConfigApplicationContext`此类是使用Java注解来配置Spring容器的方式构造参数我们给定了一个`MyConfiguration`组件类最后打印了Spring上下文中所有的bean定义名称。 首先来看看启动类入口,首先设置一个系统属性`enable.custom`为`true`,然后上下文环境使用`AnnotationConfigApplicationContext`此类是使用Java注解来配置Spring容器的方式构造参数我们给定了一个`MyConfiguration`组件类最后打印了Spring上下文中所有的bean定义名称。
@ -308,7 +314,7 @@ beanDefinitionName = user6
无任何bean 无任何bean
``` ```
### 、时序图 ### 、时序图
~~~mermaid ~~~mermaid
sequenceDiagram sequenceDiagram
@ -330,7 +336,7 @@ ConditionEvaluator->>AnnotatedBeanDefinitionReader:返回true or false
AnnotatedBeanDefinitionReader->>AnnotatedBeanDefinitionReader:如果shouldSkip返回是true,跳过Bean的注册 AnnotatedBeanDefinitionReader->>AnnotatedBeanDefinitionReader:如果shouldSkip返回是true,跳过Bean的注册
~~~ ~~~
### 、源码分析 ### 、源码分析
首先来看看启动类入口,首先设置一个系统属性`enable.custom`为`true`,然后上下文环境使用`AnnotationConfigApplicationContext`此类是使用Java注解来配置Spring容器的方式构造参数我们给定了一个`MyConfiguration`组件类最后打印了Spring上下文中所有的bean定义名称。 首先来看看启动类入口,首先设置一个系统属性`enable.custom`为`true`,然后上下文环境使用`AnnotationConfigApplicationContext`此类是使用Java注解来配置Spring容器的方式构造参数我们给定了一个`MyConfiguration`组件类最后打印了Spring上下文中所有的bean定义名称。
@ -511,7 +517,7 @@ private Condition getCondition(String conditionClassName, @Nullable ClassLoader
} }
``` ```
### 、注意事项 ### 、注意事项
1. **实现 `Condition` 接口** 1. **实现 `Condition` 接口**
+ 为了使用 `@Conditional`, 我们需要实现 `Condition` 接口。该接口只有一个方法,`matches(ConditionContext context, AnnotatedTypeMetadata metadata)`,我们需要在这里放置我们的条件逻辑。 + 为了使用 `@Conditional`, 我们需要实现 `Condition` 接口。该接口只有一个方法,`matches(ConditionContext context, AnnotatedTypeMetadata metadata)`,我们需要在这里放置我们的条件逻辑。
@ -533,9 +539,9 @@ private Condition getCondition(String conditionClassName, @Nullable ClassLoader
9. **注意与 `@Profile` 的区别** 9. **注意与 `@Profile` 的区别**
+ 虽然 `@Conditional``@Profile` 在某些情况下可以达到相同的效果,但它们的目的不同。`@Profile` 基于环境,而 `@Conditional` 更加通用,允许我们基于任意条件创建 bean。 + 虽然 `@Conditional``@Profile` 在某些情况下可以达到相同的效果,但它们的目的不同。`@Profile` 基于环境,而 `@Conditional` 更加通用,允许我们基于任意条件创建 bean。
### 、总结 ### 、总结
#### 8.1、最佳实践总结 #### 最佳实践总结
1. **基于`@Bean`的条件配置** 1. **基于`@Bean`的条件配置**
@ -567,7 +573,7 @@ private Condition getCondition(String conditionClassName, @Nullable ClassLoader
- 当条件满足(如`enable.custom`为`true`),带有`@ConditionalOnCustomActive`注解的配置类或bean会被注册。 - 当条件满足(如`enable.custom`为`true`),带有`@ConditionalOnCustomActive`注解的配置类或bean会被注册。
- 当条件不满足,它们不会被注册。 - 当条件不满足,它们不会被注册。
#### 8.2、源码分析总结 #### 源码分析总结
1. **初始化与启动** 1. **初始化与启动**
- 通过 `AnnotationConfigApplicationContext` 构造函数初始化 Spring 上下文,并通过 `register``refresh` 方法完成 bean 的注册和容器的刷新。 - 通过 `AnnotationConfigApplicationContext` 构造函数初始化 Spring 上下文,并通过 `register``refresh` 方法完成 bean 的注册和容器的刷新。