@ -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;
|
||||
}
|
||||
|
||||
// 省略其他
|
||||
}
|
||||
```
|
@ -0,0 +1,139 @@
|
||||
# SpringFactoriesLoader
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring-boot](https://github.com/SourceHot/spring-boot-read)
|
||||
|
||||
|
||||
- 全路径 : `org.springframework.core.io.support.SpringFactoriesLoader`
|
||||
- 测试类 : `org.springframework.core.io.support.SpringFactoriesLoaderTests`
|
||||
|
||||
|
||||
## loadFactories
|
||||
|
||||
- **加载并实例化工厂**
|
||||
|
||||
```java
|
||||
public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
|
||||
Assert.notNull(factoryType, "'factoryType' must not be null");
|
||||
ClassLoader classLoaderToUse = classLoader;
|
||||
if (classLoaderToUse == null) {
|
||||
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
|
||||
}
|
||||
// 工厂实现类名称
|
||||
List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
|
||||
}
|
||||
List<T> result = new ArrayList<>(factoryImplementationNames.size());
|
||||
for (String factoryImplementationName : factoryImplementationNames) {
|
||||
// 将实例化的工厂放入结果集合
|
||||
result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
|
||||
}
|
||||
// 排序
|
||||
AnnotationAwareOrderComparator.sort(result);
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## loadSpringFactories
|
||||
|
||||
- 获取接口的实现类名
|
||||
|
||||
```java
|
||||
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
|
||||
MultiValueMap<String, String> result = cache.get(classLoader);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
// 找 META-INF/spring.factories
|
||||
Enumeration<URL> urls = (classLoader != null ?
|
||||
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
|
||||
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
|
||||
result = new LinkedMultiValueMap<>();
|
||||
while (urls.hasMoreElements()) {
|
||||
// 获取 路由地址
|
||||
URL url = urls.nextElement();
|
||||
// url 解析
|
||||
UrlResource resource = new UrlResource(url);
|
||||
// Properties 解析
|
||||
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
|
||||
// 循环解析结果
|
||||
for (Map.Entry<?, ?> entry : properties.entrySet()) {
|
||||
String factoryTypeName = ((String) entry.getKey()).trim();
|
||||
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
|
||||
// 放入list
|
||||
result.add(factoryTypeName, factoryImplementationName.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
// 放入缓存
|
||||
cache.put(classLoader, result);
|
||||
return result;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalArgumentException("Unable to load factories from location [" +
|
||||
FACTORIES_RESOURCE_LOCATION + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- 存放在 测试目录下的`META-INF/spring.factories`
|
||||
|
||||
```properties
|
||||
org.springframework.core.io.support.DummyFactory =\
|
||||
org.springframework.core.io.support.MyDummyFactory2, \
|
||||
org.springframework.core.io.support.MyDummyFactory1
|
||||
|
||||
java.lang.String=\
|
||||
org.springframework.core.io.support.MyDummyFactory1
|
||||
|
||||
org.springframework.core.io.support.DummyPackagePrivateFactory=\
|
||||
org.springframework.core.io.support.DummyPackagePrivateFactory
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
- `Enumeration<URL> urls ` 变量存放的是 扫描到的`META-INF/spring.factories` 路径
|
||||
|
||||
- while 代码简单描述
|
||||
1. 获取文件路径
|
||||
2. 文件路径解析
|
||||
3. 读取文件 Properties 解析
|
||||
4. 放入返回结果
|
||||
5. 放入缓存
|
||||
|
||||
|
||||
|
||||
## instantiateFactory
|
||||
|
||||
```java
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T instantiateFactory(String factoryImplementationName, Class<T> factoryType, ClassLoader classLoader) {
|
||||
try {
|
||||
Class<?> factoryImplementationClass = ClassUtils.forName(factoryImplementationName, classLoader);
|
||||
if (!factoryType.isAssignableFrom(factoryImplementationClass)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Class [" + factoryImplementationName + "] is not assignable to factory type [" + factoryType.getName() + "]");
|
||||
}
|
||||
return (T) ReflectionUtils.accessibleConstructor(factoryImplementationClass).newInstance();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to instantiate factory class [" + factoryImplementationName + "] for factory type [" + factoryType.getName() + "]",
|
||||
ex
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- 反射创建
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 444 KiB |
After Width: | Height: | Size: 144 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 134 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 112 KiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 258 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 8.2 KiB |
After Width: | Height: | Size: 104 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 9.9 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 93 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 6.9 KiB |