Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* [将 BeanDefinition 注册进 IoC 容器](/docs/Spring/IoC/3、将BeanDefinition注册进IoC容器.md)
* [依赖注入(DI)](/docs/Spring/IoC/4、依赖注入(DI).md)
* [BeanPostProcessor](/docs/Spring/IoC/BeanPostProcessor.md)
* [Spring BeanFactory源码解析](/docs/Spring/clazz/Spring-beanFactory.md)

### AOP

Expand Down Expand Up @@ -67,6 +68,9 @@
* [Spring-import注解](/docs/Spring/clazz/Spring-Import.md)
* [Spring-定时任务](/docs/Spring/clazz/Spring-Scheduling.md)
* [Spring StopWatch](/docs/Spring/clazz/Spring-StopWatch.md)
* [Spring 元数据](/docs/Spring/clazz/Spring-Metadata.md)
* [Spring 条件接口](/docs/Spring/clazz/Spring-Conditional.md)


### Spring5 新特性

Expand All @@ -89,6 +93,7 @@
* [SpringBoot 自动装配](/docs/SpringBoot/SpringBoot-自动装配.md)
* [SpringBoot ConfigurationProperties](/docs/SpringBoot/SpringBoot-ConfigurationProperties.md)
* [SpringBoot 日志系统](/docs/SpringBoot/SpringBoot-LogSystem.md)
* [SpringBoot ConditionalOnBean](/docs/SpringBoot/SpringBoot-ConditionalOnBean.md)

## MyBatis

Expand Down Expand Up @@ -216,6 +221,12 @@

* [深挖 Redis 6.0 源码——SDS](docs/Redis/redis-sds.md)


## Nacos

* [nacos 服务注册](docs/nacos/nacos-discovery.md)


## 番外篇(JDK 1.8)
### 基础类库
* [String类 源码赏析](docs/JDK/basic/String.md)
Expand Down
301 changes: 301 additions & 0 deletions docs/Spring/clazz/Spring-Conditional.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
# Spring Conditional
- Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)



## Conditional

```java
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

/**
* 多个匹配器接口
*/
Class<? extends Condition>[] value();

}
```



## Condition

```
@FunctionalInterface
public interface Condition {

/**
* 匹配,如果匹配返回true进行初始化,返回false跳过初始化
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}
```



- ConditionContext 上下文
- AnnotatedTypeMetadata 注解信息

### ConditionContext

```
public interface ConditionContext {

/**
* bean的定义
*/
BeanDefinitionRegistry getRegistry();

/**
* bean 工厂
*/
@Nullable
ConfigurableListableBeanFactory getBeanFactory();

/**
* 环境
*/
Environment getEnvironment();

/**
* 资源加载器
*/
ResourceLoader getResourceLoader();

/**
* 类加载器
*/
@Nullable
ClassLoader getClassLoader();

}
```

- 唯一实现 : `org.springframework.context.annotation.ConditionEvaluator.ConditionContextImpl`



- 构造方法

```java
public ConditionContextImpl(@Nullable BeanDefinitionRegistry registry,
@Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {

this.registry = registry;
this.beanFactory = deduceBeanFactory(registry);
this.environment = (environment != null ? environment : deduceEnvironment(registry));
this.resourceLoader = (resourceLoader != null ? resourceLoader : deduceResourceLoader(registry));
this.classLoader = deduceClassLoader(resourceLoader, this.beanFactory);
}
```

- 在构造方法中加载了一些变量, 这些变量是根据一定规则转换后得到. 具体规则不展开.







### AnnotatedTypeMetadata

- 元数据接口

```java
public interface AnnotatedTypeMetadata {

/**
* 获取所有注解
*/
MergedAnnotations getAnnotations();

/**
* 是否有注解
*/
default boolean isAnnotated(String annotationName) {
return getAnnotations().isPresent(annotationName);
}

/**
* 获取注解的属性
*/
@Nullable
default Map<String, Object> getAnnotationAttributes(String annotationName) {
return getAnnotationAttributes(annotationName, false);
}

}
```





## 源码分析

- 对应测试类`org.springframework.context.annotation.ConfigurationClassWithConditionTests`

```java
@Test
public void conditionalOnMissingBeanMatch() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(BeanOneConfiguration.class, BeanTwoConfiguration.class);
ctx.refresh();
assertThat(ctx.containsBean("bean1")).isTrue();
assertThat(ctx.containsBean("bean2")).isFalse();
assertThat(ctx.containsBean("configurationClassWithConditionTests.BeanTwoConfiguration")).isFalse();
}



@Configuration
static class BeanOneConfiguration {

@Bean
public ExampleBean bean1() {
return new ExampleBean();
}
}

@Configuration
@Conditional(NoBeanOneCondition.class)
static class BeanTwoConfiguration {

@Bean
public ExampleBean bean2() {
return new ExampleBean();
}
}


static class NoBeanOneCondition implements Condition {

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return !context.getBeanFactory().containsBeanDefinition("bean1");
}
}

```







- `org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean`









### shouldSkip



```java
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}

if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}

List<Condition> conditions = new ArrayList<>();
// 获取注解 Conditional 的属性值
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
// 序列化成注解
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
// 插入注解列表
conditions.add(condition);
}
}

AnnotationAwareOrderComparator.sort(conditions);

for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}

// matches 进行验证
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}

return false;
}
```





- 读取注解信息, 并且执行注解对应的类的方法

用例如下. 实例化`BeanTwoConfiguration`对象的时候会去执行`NoBeanOneCondition`方法

```java
@Configuration
@Conditional(NoBeanOneCondition.class)
static class BeanTwoConfiguration {

@Bean
public ExampleBean bean2() {
return new ExampleBean();
}
}


static class NoBeanOneCondition implements Condition {

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return !context.getBeanFactory().containsBeanDefinition("bean1");
}
}
```

在开发中可以自定义matches规则







这也是在注册的时候第一个方法

```java
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {

AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
// 和条件注解相关的函数
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}

// 省略其他
}
```
Loading