(二)AutoConfigurationImportFilter过滤自动配置组件

AutoConfigurationImportFilter的使用

在AutoConfigurationImportSelector实现的selectImports方法中会通过AutoConfigurationImportFilter的相关接口实现来进行自动配置类的过滤

private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
    long startTime = System.nanoTime();
    String[] candidates = StringUtils.toStringArray(configurations);
    boolean[] skip = new boolean[candidates.length];
    boolean skipped = false;
    //获取META-INF/spring.factories中配置的所有过滤器
    Iterator var8 = this.getAutoConfigurationImportFilters().iterator();

    //遍历所有过滤器,并执行其match方法
    while(var8.hasNext()) {
    
        AutoConfigurationImportFilter filter = (AutoConfigurationImportFilter)var8.next();
        this.invokeAwareMethods(filter);
        boolean[] match = filter.match(candidates, autoConfigurationMetadata);

        for(int i = 0; i < match.length; ++i) {
            if (!match[i]) {
                skip[i] = true;
                candidates[i] = null;
                skipped = true;
            }
        }
    }

    if (!skipped) {
        return configurations;
    } else {
        List<String> result = new ArrayList(candidates.length);

        int numberFiltered;
        for(numberFiltered = 0; numberFiltered < candidates.length; ++numberFiltered) {
            if (!skip[numberFiltered]) {
                result.add(candidates[numberFiltered]);
            }
        }

        if (logger.isTraceEnabled()) {
            numberFiltered = configurations.size() - result.size();
            logger.trace("Filtered " + numberFiltered + " auto configuration class in " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
        }

        return new ArrayList(result);
    }
}

protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
    return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}


AutoConfigurationImportFilter过滤基本流程

  1. 获取META-INF/spring.factories中配置的所有过滤器
  2. 遍历所有过滤器,并执行其match方法
  3. 拼接自动配置类名和注解名为特定字符
  4. 根据字符串查询元数据中配置的类
  5. 尝试用类加载器加载该类
  6. 加载成功则匹配成功,抛出异常则匹配失败

1.获取META-INF/spring.factories中配置的所有过滤器

protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
    return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}

通过loadFactories方法在META-INF/spring.factories中获取所有的筛选条件,包括:

  • OnBeanCondition
  • OnClassCondition
  • OnWebApplicationCondition

2.遍历所有过滤器,并执行其match方法

遍历到的过滤器都实现了FilteringSpringBootCondition类,而FilteringSpringBootCondition则实现了AutoConfigurationImportFilter类,其中的match方法用来判断条件是否符合,match方法的实现方法如下:

public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
    ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
    ConditionOutcome[] outcomes = this.getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
    boolean[] match = new boolean[outcomes.length];

    for(int i = 0; i < outcomes.length; ++i) {
        match[i] = outcomes[i] == null || outcomes[i].isMatch();
        if (!match[i] && outcomes[i] != null) {
            this.logOutcome(autoConfigurationClasses[i], outcomes[i]);
            if (report != null) {
                report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
            }
        }
    }

    return match;
}

其中主要的判断逻辑,是在getOutcomes方法中,各过滤器实现了相应的getOutcomes方法用来进行条件判断。

3.拼接自动配置类名和注解名为特定字符

在各过滤器实现的getOutcomes方法中,对需要过滤的自动配置类进行分半处理,并且单独提取每一个自动配置类的条件进行判断,最后进行判断的步骤为:

private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, int start, int end, AutoConfigurationMetadata autoConfigurationMetadata) {
    ConditionOutcome[] outcomes = new ConditionOutcome[end - start];

    for(int i = start; i < end; ++i) {
        String autoConfigurationClass = autoConfigurationClasses[i];
        if (autoConfigurationClass != null) {
            String candidates = autoConfigurationMetadata.get(autoConfigurationClass, "ConditionalOnClass");
            if (candidates != null) {
                outcomes[i - start] = this.getOutcome(candidates);
            }
        }
    }

    return outcomes;
}

private ConditionOutcome getOutcome(String candidates) {
    try {
        if (!candidates.contains(",")) {
            return this.getOutcome(candidates, this.beanClassLoader);
        }

        String[] var2 = StringUtils.commaDelimitedListToStringArray(candidates);
        int var3 = var2.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            String candidate = var2[var4];
            ConditionOutcome outcome = this.getOutcome(candidate, this.beanClassLoader);
            if (outcome != null) {
                return outcome;
            }
        }
    } catch (Exception var7) {
    }

    return null;
}

private ConditionOutcome getOutcome(String className, ClassLoader classLoader) {
    return ClassNameFilter.MISSING.matches(className, classLoader) ? ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class, new Object[0]).didNotFind("required class").items(Style.QUOTE, new Object[]{className})) : null;
}


其中,通过PropertiesAutoConfigurationMetadata实现了AutoConfigurationMetadata的get方法,以拼接后的字符串作为key,从META-INF/spring-autoconfigure-metadata.properties文件中得到该条件对应的类:

public String get(String className, String key, String defaultValue) {
   
    //拼接自动配置类名和注解名为特定字符
    //根据字符串查询元数据中配置的类
    String value = this.properties.getProperty(className + "." + key);
    return value != null ? value : defaultValue;
}

4.根据字符串查询元数据中配置的类

5.尝试用类加载器加载该类

获得类名称之后,则采用ClassNameFilter.MISSING的matches方法进行判断:

protected static enum ClassNameFilter {
    PRESENT {
        public boolean matches(String className, ClassLoader classLoader) {
            return isPresent(className, classLoader);
        }
    },
    MISSING {
        public boolean matches(String className, ClassLoader classLoader) {
            return !isPresent(className, classLoader);
        }
    };

    private ClassNameFilter() {
    }

    public abstract boolean matches(String className, ClassLoader classLoader);

    public static boolean isPresent(String className, ClassLoader classLoader) {
        if (classLoader == null) {
            classLoader = ClassUtils.getDefaultClassLoader();
        }
	
	//加载成功则匹配成功,抛出异常则匹配失败
        try {
            forName(className, classLoader);
            return true;
        } catch (Throwable var3) {
            return false;
        }
    }

    //尝试用类加载器加载该类
    private static Class<?> forName(String className, ClassLoader classLoader) throws ClassNotFoundException {
        return classLoader != null ? classLoader.loadClass(className) : Class.forName(className);
    }
}

6.加载成功则匹配成功,抛出异常则匹配失败

参考

(《Spring Boot 技术内幕》)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值