死磕源码系列【springboot之OnClassCondition、OnBeanCondition、OnWebApplicationCondition条件注解源码解析】

Myth丶恋晨 2022-12-26 08:17 188阅读 0赞

在spring-boot-autoconfigurejar包中的spring.factories配置文件中有一个org.springframework.boot.autoconfigure.AutoConfigurationImportFilter自动化配置import过滤器,配置如下:

  1. # Auto Configuration Import Filters
  2. org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
  3. org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
  4. org.springframework.boot.autoconfigure.condition.OnClassCondition,\
  5. org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

上述三个类都是AutoConfigurationImportFilter自动化配置是否匹配接口的实现类,用于过滤自动化配置类及其它类是否符合条件,该类是在org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationImportFilters方法中加载到内存之中的:

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

之前的一篇文章死磕源码系列【AutoConfigurationMetadataLoader之加载自动化配置元数据源码详解】已经讲解过通过这三个过滤器取过滤掉不符合条件的配置类,本文不再详解;

1.OnClassCondition类在这三个类中优先级最高(@ConditionalOnClass、@ConditionalOnMissingClass),所以先讲解此类
  1. private interface OutcomesResolver {
  2. ConditionOutcome[] resolveOutcomes();
  3. }

此接口是一个条件解析接口,返回当前配置类是否符合条件及日志信息,其有两个实现类StandardOutcomesResolver和ThreadedOutcomesResolver,其中ThreadedOutcomesResolver是采用线程异步的方式解析配置类,最终还是调用StandardOutcomesResolver的实现方法;

StandardOutcomesResolver标准条件匹配解析类:
  1. private static final class StandardOutcomesResolver implements OutcomesResolver {
  2. //配置类集合
  3. private final String[] autoConfigurationClasses;
  4. //开始索引
  5. private final int start;
  6. //结束索引
  7. private final int end;
  8. //配置类注解元数据
  9. private final AutoConfigurationMetadata autoConfigurationMetadata;
  10. //类加载器
  11. private final ClassLoader beanClassLoader;
  12. //新建一个标准的条件匹配解析实例对象
  13. private StandardOutcomesResolver(String[] autoConfigurationClasses, int start, int end,
  14. AutoConfigurationMetadata autoConfigurationMetadata, ClassLoader beanClassLoader) {
  15. this.autoConfigurationClasses = autoConfigurationClasses;
  16. this.start = start;
  17. this.end = end;
  18. this.autoConfigurationMetadata = autoConfigurationMetadata;
  19. this.beanClassLoader = beanClassLoader;
  20. }
  21. //解析配置类是否符合条件并返回结果集
  22. @Override
  23. public ConditionOutcome[] resolveOutcomes() {
  24. return getOutcomes(this.autoConfigurationClasses, this.start, this.end, this.autoConfigurationMetadata);
  25. }
  26. //解析配置类是否符合条件并返回结果集
  27. private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, int start, int end,
  28. AutoConfigurationMetadata autoConfigurationMetadata) {
  29. //新建一个条件匹配解析后的结果集数组
  30. ConditionOutcome[] outcomes = new ConditionOutcome[end - start];
  31. for (int i = start; i < end; i++) {
  32. //获取配置类
  33. String autoConfigurationClass = autoConfigurationClasses[i];
  34. if (autoConfigurationClass != null) {
  35. //获取自动化配置元数据key对应的值
  36. String candidates = autoConfigurationMetadata.get(autoConfigurationClass, "ConditionalOnClass");
  37. //自动化配置条件注解的条件存在
  38. if (candidates != null) {
  39. //解析条件类是否存在,如果不存在返回ConditionOutcome对象match为false及日志信息
  40. //如果符合条件,即类实例存在,则返回null
  41. outcomes[i - start] = getOutcome(candidates);
  42. }
  43. }
  44. }
  45. return outcomes;
  46. }
  47. //解析条件类是否存在,如果不存在返回ConditionOutcome对象match为false及日志信息
  48. //如果符合条件,即类实例存在,则返回null
  49. private ConditionOutcome getOutcome(String candidates) {
  50. try {
  51. //如果只有一个条件类存在
  52. if (!candidates.contains(",")) {
  53. //获取条件类验证的结果集
  54. return getOutcome(candidates, this.beanClassLoader);
  55. }
  56. //如果有多个条件类存在
  57. for (String candidate : StringUtils.commaDelimitedListToStringArray(candidates)) {
  58. //获取条件类验证的结果集
  59. ConditionOutcome outcome = getOutcome(candidate, this.beanClassLoader);
  60. if (outcome != null) {
  61. return outcome;
  62. }
  63. }
  64. }
  65. catch (Exception ex) {
  66. // We'll get another chance later
  67. }
  68. return null;
  69. }
  70. //获取条件类验证的结果集
  71. private ConditionOutcome getOutcome(String className, ClassLoader classLoader) {
  72. //如果条件类不存在,则返回不匹配信息
  73. if (ClassNameFilter.MISSING.matches(className, classLoader)) {
  74. return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
  75. .didNotFind("required class").items(Style.QUOTE, className));
  76. }
  77. //如果条件类存在,则返回null
  78. return null;
  79. }
  80. }
ClassNameFilter类是FilteringSpringBootCondition类的一个内部枚举类:
  1. protected enum ClassNameFilter {
  2. PRESENT {
  3. @Override
  4. public boolean matches(String className, ClassLoader classLoader) {
  5. return isPresent(className, classLoader);
  6. }
  7. },
  8. MISSING {
  9. @Override
  10. public boolean matches(String className, ClassLoader classLoader) {
  11. //如果条件类存在,则返回false,否则返回true
  12. return !isPresent(className, classLoader);
  13. }
  14. };
  15. abstract boolean matches(String className, ClassLoader classLoader);
  16. //通过反射的方式获取条件类是否存在
  17. static boolean isPresent(String className, ClassLoader classLoader) {
  18. if (classLoader == null) {
  19. classLoader = ClassUtils.getDefaultClassLoader();
  20. }
  21. try {
  22. //通过反射的方式获取指定的条件类的class实例对象
  23. //如果存在,则返回true,否则返回false
  24. resolve(className, classLoader);
  25. return true;
  26. }
  27. catch (Throwable ex) {
  28. return false;
  29. }
  30. }
  31. }
  32. protected static Class<?> resolve(String className, ClassLoader classLoader) throws ClassNotFoundException {
  33. if (classLoader != null) {
  34. //通过反射的方式获取指定的条件类的class实例对象
  35. return Class.forName(className, false, classLoader);
  36. }
  37. //通过反射的方式获取指定的条件类的class实例对象
  38. return Class.forName(className);
  39. }
ThreadedOutcomesResolver基于线程的条件注解解析类
  1. private static final class ThreadedOutcomesResolver implements OutcomesResolver {
  2. //线程对象
  3. private final Thread thread;
  4. //配置类注解解析后的结果集
  5. private volatile ConditionOutcome[] outcomes;
  6. //根据给定的解析器构建ThreadedOutcomesResolver实例对象
  7. private ThreadedOutcomesResolver(OutcomesResolver outcomesResolver) {
  8. //使用异步线程的模式在后台解析给定的配置类
  9. this.thread = new Thread(() -> this.outcomes = outcomesResolver.resolveOutcomes());
  10. this.thread.start();
  11. }
  12. @Override
  13. public ConditionOutcome[] resolveOutcomes() {
  14. try {
  15. this.thread.join();
  16. }
  17. catch (InterruptedException ex) {
  18. Thread.currentThread().interrupt();
  19. }
  20. return this.outcomes;
  21. }
  22. }
OnClassCondition条件注解解析类
  1. @Order(Ordered.HIGHEST_PRECEDENCE)
  2. class OnClassCondition extends FilteringSpringBootCondition {
  3. //根据给定的配置类元数据及配置类集合判定配置类是否符合条件
  4. @Override
  5. protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
  6. AutoConfigurationMetadata autoConfigurationMetadata) {
  7. // 如果有多个处理器可用,则将工作拆分并在后台线程中执行一半,使用一个额外的线程似乎可以童工最好的性能。
  8. // 线程越多,并不见得性能会更好,可能会更糟糕
  9. if (autoConfigurationClasses.length > 1 && Runtime.getRuntime().availableProcessors() > 1) {
  10. //如果配置类有多个,并且有多个处理器,则选择拆分处理的方法
  11. return resolveOutcomesThreaded(autoConfigurationClasses, autoConfigurationMetadata);
  12. }
  13. else {
  14. //如果只有一个配置类,则使用StandardOutcomesResolver解析类对配置类进行处理
  15. OutcomesResolver outcomesResolver = new StandardOutcomesResolver(autoConfigurationClasses, 0,
  16. autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());
  17. return outcomesResolver.resolveOutcomes();
  18. }
  19. }
  20. //如果配置类有多个,并且有多个处理器,则选择拆分处理的方法
  21. private ConditionOutcome[] resolveOutcomesThreaded(String[] autoConfigurationClasses,
  22. AutoConfigurationMetadata autoConfigurationMetadata) {
  23. //获取配置类一半的数量
  24. int split = autoConfigurationClasses.length / 2;
  25. //创建线程解析器解析第一部分配置类
  26. OutcomesResolver firstHalfResolver = createOutcomesResolver(autoConfigurationClasses, 0, split,
  27. autoConfigurationMetadata);
  28. //创建标准的解析器解析第二部分配置类
  29. OutcomesResolver secondHalfResolver = new StandardOutcomesResolver(autoConfigurationClasses, split,
  30. autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());
  31. //使用标准解析器解析第二部分配置类
  32. ConditionOutcome[] secondHalf = secondHalfResolver.resolveOutcomes();
  33. //使用线程解析器解析第一部分配置类
  34. ConditionOutcome[] firstHalf = firstHalfResolver.resolveOutcomes();
  35. //创建解析后的结果数据集
  36. ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
  37. //将第一部分解析的结果放入数组
  38. System.arraycopy(firstHalf, 0, outcomes, 0, firstHalf.length);
  39. //将第二部分解析的结果放入数组
  40. System.arraycopy(secondHalf, 0, outcomes, split, secondHalf.length);
  41. return outcomes;
  42. }
  43. private OutcomesResolver createOutcomesResolver(String[] autoConfigurationClasses, int start, int end,
  44. AutoConfigurationMetadata autoConfigurationMetadata) {
  45. //新建一个标准的解析器
  46. OutcomesResolver outcomesResolver = new StandardOutcomesResolver(autoConfigurationClasses, start, end,
  47. autoConfigurationMetadata, getBeanClassLoader());
  48. try {
  49. //以标准解析器为参数新建线程异步解析器
  50. return new ThreadedOutcomesResolver(outcomesResolver);
  51. }
  52. catch (AccessControlException ex) {
  53. return outcomesResolver;
  54. }
  55. }
  56. }
2.OnWebApplicationCondition用来检测容器的类型是否符合条件(@ConditionalOnWebApplication、ConditionalOnNotWebApplication),其优先级低于OnClassCondition类
  1. @Order(Ordered.HIGHEST_PRECEDENCE + 20)
  2. class OnWebApplicationCondition extends FilteringSpringBootCondition {
  3. //servlet对应的应用上下文类
  4. private static final String SERVLET_WEB_APPLICATION_CLASS = "org.springframework.web.context.support.GenericWebApplicationContext";
  5. //reactive应用上下文类
  6. private static final String REACTIVE_WEB_APPLICATION_CLASS = "org.springframework.web.reactive.HandlerResult";
  7. //根据自动化配置注解元数据获取指定配置类集合注解条件的匹配结果集
  8. @Override
  9. protected ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
  10. AutoConfigurationMetadata autoConfigurationMetadata) {
  11. //新建配置类大小的结果集数组
  12. ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
  13. for (int i = 0; i < outcomes.length; i++) {
  14. //获取自动化配置类
  15. String autoConfigurationClass = autoConfigurationClasses[i];
  16. if (autoConfigurationClass != null) {
  17. //首先根据自动化配置类获取对应条件ConditionalOnWebApplication的配置,将其作为参数获取匹配结果
  18. //如果匹配则返回null,否则返回匹配结果及错误日志信息对象
  19. outcomes[i] = getOutcome(
  20. autoConfigurationMetadata.get(autoConfigurationClass, "ConditionalOnWebApplication"));
  21. }
  22. }
  23. return outcomes;
  24. }
  25. //首先根据自动化配置类获取对应条件ConditionalOnWebApplication的配置,将其作为参数获取匹配结果
  26. //如果匹配则返回null,否则返回匹配结果及错误日志信息对象
  27. private ConditionOutcome getOutcome(String type) {
  28. //如果类型为null,直接返回null(默认为已经匹配)
  29. if (type == null) {
  30. return null;
  31. }
  32. ConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnWebApplication.class);
  33. //如果容器类型为servlet
  34. if (ConditionalOnWebApplication.Type.SERVLET.name().equals(type)) {
  35. //如果上下文类不存在,则返回不匹配信息
  36. if (!ClassNameFilter.isPresent(SERVLET_WEB_APPLICATION_CLASS, getBeanClassLoader())) {
  37. return ConditionOutcome.noMatch(message.didNotFind("servlet web application classes").atAll());
  38. }
  39. }
  40. //如果容器类型是reactive
  41. if (ConditionalOnWebApplication.Type.REACTIVE.name().equals(type)) {
  42. //如果上下文类不存在,则返回不匹配信息
  43. if (!ClassNameFilter.isPresent(REACTIVE_WEB_APPLICATION_CLASS, getBeanClassLoader())) {
  44. return ConditionOutcome.noMatch(message.didNotFind("reactive web application classes").atAll());
  45. }
  46. }
  47. //如果两个上下文类都不存在,则返回不匹配信息
  48. if (!ClassNameFilter.isPresent(SERVLET_WEB_APPLICATION_CLASS, getBeanClassLoader())
  49. && !ClassUtils.isPresent(REACTIVE_WEB_APPLICATION_CLASS, getBeanClassLoader())) {
  50. return ConditionOutcome.noMatch(message.didNotFind("reactive or servlet web application classes").atAll());
  51. }
  52. //上下文存在,返回null
  53. return null;
  54. }
  55. }
3.OnBeanCondition类用来检测bean是否存在(@ConditionalOnBean、@ConditionalOnMissingBean、@ConditionalOnSingleCandidate)
  1. //优先级在三个过滤其中最低
  2. @Order(Ordered.LOWEST_PRECEDENCE)
  3. class OnBeanCondition extends FilteringSpringBootCondition implements ConfigurationCondition {
  4. //获取bean所处的阶段
  5. @Override
  6. public ConfigurationPhase getConfigurationPhase() {
  7. return ConfigurationPhase.REGISTER_BEAN;
  8. }
  9. //根据自动化配置注解元数据判定指定配置类是否符合条件
  10. @Override
  11. protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
  12. AutoConfigurationMetadata autoConfigurationMetadata) {
  13. //创建自动化配置类匹配结果集类
  14. ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
  15. for (int i = 0; i < outcomes.length; i++) {
  16. //获取自动化配置类
  17. String autoConfigurationClass = autoConfigurationClasses[i];
  18. if (autoConfigurationClass != null) {
  19. //获取自动化配置对应的条件注解元数据信息
  20. Set<String> onBeanTypes = autoConfigurationMetadata.getSet(autoConfigurationClass, "ConditionalOnBean");
  21. //获取条件匹配结果
  22. outcomes[i] = getOutcome(onBeanTypes, ConditionalOnBean.class);
  23. if (outcomes[i] == null) {
  24. //获取配置类条件注解ConditionalOnSingleCandidate的元数据
  25. Set<String> onSingleCandidateTypes = autoConfigurationMetadata.getSet(autoConfigurationClass,
  26. "ConditionalOnSingleCandidate");
  27. //获取条件匹配结果
  28. outcomes[i] = getOutcome(onSingleCandidateTypes, ConditionalOnSingleCandidate.class);
  29. }
  30. }
  31. }
  32. return outcomes;
  33. }
  34. //根据条件注解bean的类型及注解获取匹配结果
  35. private ConditionOutcome getOutcome(Set<String> requiredBeanTypes, Class<? extends Annotation> annotation) {
  36. //通过过滤器及反射的方式确定bean是否存在
  37. List<String> missing = filter(requiredBeanTypes, ClassNameFilter.MISSING, getBeanClassLoader());
  38. //如果不存在,则返回不匹配信息
  39. if (!missing.isEmpty()) {
  40. ConditionMessage message = ConditionMessage.forCondition(annotation)
  41. .didNotFind("required type", "required types").items(Style.QUOTE, missing);
  42. return ConditionOutcome.noMatch(message);
  43. }
  44. //如果存在则返回null
  45. return null;
  46. }

父类FilteringSpringBootCondition#filter方法源码:

  1. protected final List<String> filter(Collection<String> classNames, ClassNameFilter classNameFilter,
  2. ClassLoader classLoader) {
  3. //如果类名不存在,则直接返回空数组
  4. if (CollectionUtils.isEmpty(classNames)) {
  5. return Collections.emptyList();
  6. }
  7. List<String> matches = new ArrayList<>(classNames.size());
  8. for (String candidate : classNames) {
  9. //根据反射的方式确定确定指定的类是否存在,如果不存在则返回true,否则返回false
  10. if (classNameFilter.matches(candidate, classLoader)) {
  11. matches.add(candidate);
  12. }
  13. }
  14. return matches;
  15. }
4.上述三个过滤器类都是FilteringSpringBootCondition抽象类的子类,其getOutcomes方法都是通过此类作为入口调用的
  1. abstract class FilteringSpringBootCondition extends SpringBootCondition
  2. implements AutoConfigurationImportFilter, BeanFactoryAware, BeanClassLoaderAware {
  3. private BeanFactory beanFactory;
  4. private ClassLoader beanClassLoader;
  5. @Override
  6. public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
  7. //获取条件评估报告类
  8. ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
  9. //获取配置类匹配结果集
  10. ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
  11. //创建boolean数组
  12. boolean[] match = new boolean[outcomes.length];
  13. for (int i = 0; i < outcomes.length; i++) {
  14. //如果结果为null,则匹配,否则根据具体结果集判定
  15. match[i] = (outcomes[i] == null || outcomes[i].isMatch());
  16. //如果不匹配,则将配置类及匹配信息存入条件评估报告对象中
  17. if (!match[i] && outcomes[i] != null) {
  18. //打印trace级别的日志
  19. logOutcome(autoConfigurationClasses[i], outcomes[i]);
  20. if (report != null) {
  21. //将数据存入条件评估报告对象集合
  22. report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
  23. }
  24. }
  25. }
  26. return match;
  27. }
  28. //获取配置类匹配结果集,具体由子类实现
  29. protected abstract ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
  30. AutoConfigurationMetadata autoConfigurationMetadata);
  31. }

总结:上述三个条件过滤器类判定class、bean及容器类别都是通过反射的方式来进行判定。

GitHub地址:https://github.com/mingyang66/spring-parent

发表评论

表情:
评论列表 (有 0 条评论,188人围观)

还没有评论,来说两句吧...

相关阅读