Skip to content

Commit bebf4e5

Browse files
committed
doc: Spring Conditional
1 parent 7dbed25 commit bebf4e5

File tree

2 files changed

+302
-0
lines changed

2 files changed

+302
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
* [Spring-定时任务](/docs/Spring/clazz/Spring-Scheduling.md)
6969
* [Spring StopWatch](/docs/Spring/clazz/Spring-StopWatch.md)
7070
* [Spring 元数据](/docs/Spring/clazz/Spring-Metadata.md)
71+
* [Spring 条件接口](/docs/Spring/clazz/Spring-Conditional.md)
7172

7273

7374
### Spring5 新特性
+301
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
# Spring Conditional
2+
- Author: [HuiFer](https://github.com/huifer)
3+
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
4+
5+
6+
7+
## Conditional
8+
9+
```java
10+
@Target({ ElementType.TYPE, ElementType.METHOD })
11+
@Retention(RetentionPolicy.RUNTIME)
12+
@Documented
13+
public @interface Conditional {
14+
15+
/**
16+
* 多个匹配器接口
17+
*/
18+
Class<? extends Condition>[] value();
19+
20+
}
21+
```
22+
23+
24+
25+
## Condition
26+
27+
```
28+
@FunctionalInterface
29+
public interface Condition {
30+
31+
/**
32+
* 匹配,如果匹配返回true进行初始化,返回false跳过初始化
33+
*/
34+
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
35+
36+
}
37+
```
38+
39+
40+
41+
- ConditionContext 上下文
42+
- AnnotatedTypeMetadata 注解信息
43+
44+
### ConditionContext
45+
46+
```
47+
public interface ConditionContext {
48+
49+
/**
50+
* bean的定义
51+
*/
52+
BeanDefinitionRegistry getRegistry();
53+
54+
/**
55+
* bean 工厂
56+
*/
57+
@Nullable
58+
ConfigurableListableBeanFactory getBeanFactory();
59+
60+
/**
61+
* 环境
62+
*/
63+
Environment getEnvironment();
64+
65+
/**
66+
* 资源加载器
67+
*/
68+
ResourceLoader getResourceLoader();
69+
70+
/**
71+
* 类加载器
72+
*/
73+
@Nullable
74+
ClassLoader getClassLoader();
75+
76+
}
77+
```
78+
79+
- 唯一实现 : `org.springframework.context.annotation.ConditionEvaluator.ConditionContextImpl`
80+
81+
82+
83+
- 构造方法
84+
85+
```java
86+
public ConditionContextImpl(@Nullable BeanDefinitionRegistry registry,
87+
@Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {
88+
89+
this.registry = registry;
90+
this.beanFactory = deduceBeanFactory(registry);
91+
this.environment = (environment != null ? environment : deduceEnvironment(registry));
92+
this.resourceLoader = (resourceLoader != null ? resourceLoader : deduceResourceLoader(registry));
93+
this.classLoader = deduceClassLoader(resourceLoader, this.beanFactory);
94+
}
95+
```
96+
97+
- 在构造方法中加载了一些变量, 这些变量是根据一定规则转换后得到. 具体规则不展开.
98+
99+
100+
101+
102+
103+
104+
105+
### AnnotatedTypeMetadata
106+
107+
- 元数据接口
108+
109+
```java
110+
public interface AnnotatedTypeMetadata {
111+
112+
/**
113+
* 获取所有注解
114+
*/
115+
MergedAnnotations getAnnotations();
116+
117+
/**
118+
* 是否有注解
119+
*/
120+
default boolean isAnnotated(String annotationName) {
121+
return getAnnotations().isPresent(annotationName);
122+
}
123+
124+
/**
125+
* 获取注解的属性
126+
*/
127+
@Nullable
128+
default Map<String, Object> getAnnotationAttributes(String annotationName) {
129+
return getAnnotationAttributes(annotationName, false);
130+
}
131+
132+
}
133+
```
134+
135+
136+
137+
138+
139+
## 源码分析
140+
141+
- 对应测试类`org.springframework.context.annotation.ConfigurationClassWithConditionTests`
142+
143+
```java
144+
@Test
145+
public void conditionalOnMissingBeanMatch() throws Exception {
146+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
147+
ctx.register(BeanOneConfiguration.class, BeanTwoConfiguration.class);
148+
ctx.refresh();
149+
assertThat(ctx.containsBean("bean1")).isTrue();
150+
assertThat(ctx.containsBean("bean2")).isFalse();
151+
assertThat(ctx.containsBean("configurationClassWithConditionTests.BeanTwoConfiguration")).isFalse();
152+
}
153+
154+
155+
156+
@Configuration
157+
static class BeanOneConfiguration {
158+
159+
@Bean
160+
public ExampleBean bean1() {
161+
return new ExampleBean();
162+
}
163+
}
164+
165+
@Configuration
166+
@Conditional(NoBeanOneCondition.class)
167+
static class BeanTwoConfiguration {
168+
169+
@Bean
170+
public ExampleBean bean2() {
171+
return new ExampleBean();
172+
}
173+
}
174+
175+
176+
static class NoBeanOneCondition implements Condition {
177+
178+
@Override
179+
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
180+
return !context.getBeanFactory().containsBeanDefinition("bean1");
181+
}
182+
}
183+
184+
```
185+
186+
187+
188+
189+
190+
191+
192+
- `org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean`
193+
194+
195+
196+
197+
198+
199+
200+
201+
202+
### shouldSkip
203+
204+
205+
206+
```java
207+
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
208+
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
209+
return false;
210+
}
211+
212+
if (phase == null) {
213+
if (metadata instanceof AnnotationMetadata &&
214+
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
215+
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
216+
}
217+
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
218+
}
219+
220+
List<Condition> conditions = new ArrayList<>();
221+
// 获取注解 Conditional 的属性值
222+
for (String[] conditionClasses : getConditionClasses(metadata)) {
223+
for (String conditionClass : conditionClasses) {
224+
// 序列化成注解
225+
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
226+
// 插入注解列表
227+
conditions.add(condition);
228+
}
229+
}
230+
231+
AnnotationAwareOrderComparator.sort(conditions);
232+
233+
for (Condition condition : conditions) {
234+
ConfigurationPhase requiredPhase = null;
235+
if (condition instanceof ConfigurationCondition) {
236+
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
237+
}
238+
239+
// matches 进行验证
240+
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
241+
return true;
242+
}
243+
}
244+
245+
return false;
246+
}
247+
```
248+
249+
250+
251+
252+
253+
- 读取注解信息, 并且执行注解对应的类的方法
254+
255+
用例如下. 实例化`BeanTwoConfiguration`对象的时候会去执行`NoBeanOneCondition`方法
256+
257+
```java
258+
@Configuration
259+
@Conditional(NoBeanOneCondition.class)
260+
static class BeanTwoConfiguration {
261+
262+
@Bean
263+
public ExampleBean bean2() {
264+
return new ExampleBean();
265+
}
266+
}
267+
268+
269+
static class NoBeanOneCondition implements Condition {
270+
271+
@Override
272+
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
273+
return !context.getBeanFactory().containsBeanDefinition("bean1");
274+
}
275+
}
276+
```
277+
278+
在开发中可以自定义matches规则
279+
280+
281+
282+
283+
284+
285+
286+
这也是在注册的时候第一个方法
287+
288+
```java
289+
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
290+
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
291+
@Nullable BeanDefinitionCustomizer[] customizers) {
292+
293+
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
294+
// 和条件注解相关的函数
295+
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
296+
return;
297+
}
298+
299+
// 省略其他
300+
}
301+
```

0 commit comments

Comments
 (0)