Spring Boot自动配置的原理在于@SpringBootApplication注解下的@EnableAutoConfiguration,因此我们从这个配置类开始分析,主要分析过程都写在代码中了。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {// 。。。。。。。
}
public void parse(Set<BeanDefinitionHolder> configCandidates) {for (BeanDefinitionHolder holder : configCandidates) {BeanDefinition bd = BeanDefinition();try {if (bd instanceof AnnotatedBeanDefinition) {parse(((AnnotatedBeanDefinition) bd).getMetadata(), BeanName());}else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {parse(((AbstractBeanDefinition) bd).getBeanClass(), BeanName());}else {BeanClassName(), BeanName());}}catch (BeanDefinitionStoreException ex) {throw ex;}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);}}// 执行之前添加的DefferedImportSelectorthis.deferredImportSelectorHandler.process();
}
public void process() {List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;this.deferredImportSelectors = null;try {if (deferredImports != null) {DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);deferredImports.forEach(handler::register);handler.processGroupImports();}}finally {this.deferredImportSelectors = new ArrayList<>();}
}
// DeferredImportSelectorGroupingHandler类的方法
public void register(DeferredImportSelectorHolder deferredImport) {Class<? extends Group> group = ImportSelector().getImportGroup();DeferredImportSelectorGrouping grouping = upingsputeIfAbsent((group != null ? group : deferredImport),key -> new DeferredImportSelectorGrouping(createGroup(group)));grouping.add(deferredImport);figurationClasses.ConfigurationClass().getMetadata(),ConfigurationClass());
}
public void processGroupImports() {for (DeferredImportSelectorGrouping grouping : upings.values()) {Imports().forEach(entry -> {ConfigurationClass configurationClass = (Metadata());try {processImports(configurationClass, asSourceClass(configurationClass),ImportClassName()), false);}catch (BeanDefinitionStoreException ex) {throw ex;}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" Metadata().getClassName() + "]", ex);}});}
}
public Iterable<Group.Entry> getImports() {for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {up.ConfigurationClass().getMetadata(),ImportSelector());}up.selectImports();
}
下面我们进入本文的重点,自动配置。
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,() -> String.format("Only %s implementations are supported, got %s",SimpleName(),Class().getName()));// 调用了AutoConfigurationImportSelector的getAutoConfigurationEntry方法AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector).getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);this.autoConfigurationEntries.add(autoConfigurationEntry);for (String importClassName : Configurations()) {ies.putIfAbsent(importClassName, annotationMetadata);}
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,AnnotationMetadata annotationMetadata) {// 判断配置文件的自动配置功能是否打开,即环境中是否设置了ableautoconfiguration,默认返回true,取反为falseif (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}// 获取到@EnableAutoConfiguration注解的属性AnnotationAttributes attributes = getAttributes(annotationMetadata);// 获取到META/spring.factories文件中key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的全限定类名List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);// 剔除重复的configurations = removeDuplicates(configurations);// 查找到@EnableAutoConfiguration中exclude,excludeName中的全限定类名,或者配置文件中lude添加的全限定类名// 以便剔除不需要自动配置的类Set<String> exclusions = getExclusions(annotationMetadata, attributes);// 检查上一步剔除的类,如果该排除的类可以被加载并且之前从spring.factories中没有指定过该类名,那么就是一个无效的排除,然后打印一下checkExcludedClasses(configurations, exclusions);// 删除有效的剔除类名veAll(exclusions);configurations = filter(configurations, autoConfigurationMetadata);fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);
}
org.springframework.dition.OnBeanCondition
org.springframework.dition.OnClassCondition
org.springframework.dition.OnWebApplicationCondition
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {long startTime = System.nanoTime();String[] candidates = StringArray(configurations);boolean[] skip = new boolean[candidates.length];boolean skipped = false;for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {invokeAwareMethods(filter);// 使用各个Filter对候选的自动配置类进行筛选boolean[] match = filter.match(candidates, autoConfigurationMetadata);for (int i = 0; i < match.length; i++) {// 如果不符合过滤器的条件,那么就标识该配置类为需要跳过,将候选的置为null,标志是否有任意一个需要跳过if (!match[i]) {skip[i] = true;candidates[i] = null;skipped = true;}}}// 如果全部都没有要跳过,直接返回所有的if (!skipped) {return configurations;}// 根据前面filter判断的结果,决定是否添加到结果中返回List<String> result = new ArrayList<>(candidates.length);for (int i = 0; i < candidates.length; i++) {if (!skip[i]) {result.add(candidates[i]);}}if (logger.isTraceEnabled()) {int numberFiltered = configurations.size() - result.size();ace("Filtered " + numberFiltered + " auto configuration class in "+ Millis(System.nanoTime() - startTime) + " ms");}return new ArrayList<>(result);
}
上面提供到3个过滤器都是继承自FilteringSpringBootCondition,而match方法由FilteringSpringBootCondition,getOutcomes由实现类重写
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);ConditionOutcome[] outcomes = 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) {logOutcome(autoConfigurationClasses[i], outcomes[i]);if (report != null) {dConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);}}}return match;
}
OnClassCondition类分析
protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,AutoConfigurationMetadata autoConfigurationMetadata) {// Split the work and perform half in a background thread. Using a single// additional thread seems to offer the best performance. More threads make// things worse// 二分法处理int split = autoConfigurationClasses.length / 2;// 创建一个线程用于处理前一半的数据,创建了一个ThreadedOutcomesResolver,构造器中传入StandardOutcomesResolver,// 然后在构造器中启动一个线程执行构造器中传入solveOutcomes方法,并将返回值赋值给ThreadedOutcomesResolver的// outcomes属性OutcomesResolver firstHalfResolver = createOutcomesResolver(autoConfigurationClasses, 0, split,autoConfigurationMetadata);OutcomesResolver secondHalfResolver = new StandardOutcomesResolver(autoConfigurationClasses, split,autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());// 步骤// 1. 获取META-INF/spring-autoconfigure-metadata.properties文件中的配置,key为:自动配置类名 + "." + "ConditionalOnClass"// 2. 如果上述属性获取到了,判断该属性值对应的类是否可以加载到,如果加载得到返回null,加载得到,返回一个属性为false的ConditionOutcomeConditionOutcome[] secondHalf = solveOutcomes();// 调用ThreadedOutcomesResolver的resolveOutcomes方法,调用当前方法中之前创建的thread.join方法,等待线程把solveOutcomes// 执行完成,然后把赋值好的outcomes返回ConditionOutcome[] firstHalf = solveOutcomes();// 组合返回ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];System.arraycopy(firstHalf, 0, outcomes, 0, firstHalf.length);System.arraycopy(secondHalf, 0, outcomes, split, secondHalf.length);return outcomes;
}
回到上面的代码中
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);boolean[] match = new boolean[outcomes.length];for (int i = 0; i < outcomes.length; i++) {// outcome为null或者outcome的match为true,那么就说明需要自动配置match[i] = (outcomes[i] == null || outcomes[i].isMatch());if (!match[i] && outcomes[i] != null) {// 打印不能使用自动配置的类logOutcome(autoConfigurationClasses[i], outcomes[i]);if (report != null) {dConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);}}}return match;
}
OnWebApplicationCondition,直接看getOutcomes方法,同样获取META-INF/spring-autoconfigure-metadata.properties文件中的配置,key为:自动配置类名 + “.” + “ConditionalOnWebApplication”,根据该值决定是否自动注入
protected ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,AutoConfigurationMetadata autoConfigurationMetadata) {ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];for (int i = 0; i < outcomes.length; i++) {String autoConfigurationClass = autoConfigurationClasses[i];if (autoConfigurationClass != null) {outcomes[i] = (autoConfigurationClass, "ConditionalOnWebApplication"));}}return outcomes;
}
有哪些值?
1. 未配置;
2. SERVLET:项目引入_org.t.support.GenericWebApplicationContext,返回null
3. REACTIVE:项目引入_org.active.HandlerResult,返回null
4. 其他:引入了上述两种之一即返回null
private ConditionOutcome getOutcome(String type) {if (type == null) {return null;}ConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnWebApplication.class);if (ConditionalOnWebApplication.Type.SERVLET.name().equals(type)) {if (!ClassNameFilter.isPresent(SERVLET_WEB_APPLICATION_CLASS, getBeanClassLoader())) {Match(message.didNotFind("servlet web application classes").atAll());}}if (ConditionalOnWebApplication.Type.REACTIVE.name().equals(type)) {if (!ClassNameFilter.isPresent(REACTIVE_WEB_APPLICATION_CLASS, getBeanClassLoader())) {Match(message.didNotFind("reactive web application classes").atAll());}}if (!ClassNameFilter.isPresent(SERVLET_WEB_APPLICATION_CLASS, getBeanClassLoader())&& !ClassUtils.isPresent(REACTIVE_WEB_APPLICATION_CLASS, getBeanClassLoader())) {Match(message.didNotFind("reactive or servlet web application classes").atAll());}return null;
}
OnBeanCondition,和前两种一样,获取META-INF/spring-autoconfigure-metadata.properties文件中的配置,key为:自动配置类名 + “.” + “ConditionalOnBean”,如果前一个没有过滤掉,在判断ConditionalOnSingleCandidate的类型
protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,AutoConfigurationMetadata autoConfigurationMetadata) {ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];for (int i = 0; i < outcomes.length; i++) {String autoConfigurationClass = autoConfigurationClasses[i];if (autoConfigurationClass != null) {Set<String> onBeanTypes = Set(autoConfigurationClass, "ConditionalOnBean");outcomes[i] = getOutcome(onBeanTypes, ConditionalOnBean.class);if (outcomes[i] == null) {Set<String> onSingleCandidateTypes = Set(autoConfigurationClass,"ConditionalOnSingleCandidate");outcomes[i] = getOutcome(onSingleCandidateTypes, ConditionalOnSingleCandidate.class);}}}return outcomes;
}
过滤掉条件不满足的类
/**
requiredBeanTypes: 必须要有的bean的类型全限定名
该方法用于判断任意一个需要加载的类不存在,即返回false的ConditionOutcome
*/
private ConditionOutcome getOutcome(Set<String> requiredBeanTypes, Class<? extends Annotation> annotation) {List<String> missing = filter(requiredBeanTypes, ClassNameFilter.MISSING, getBeanClassLoader());if (!missing.isEmpty()) {ConditionMessage message = ConditionMessage.forCondition(annotation).didNotFind("required type", "required types").items(Style.QUOTE, missing);Match(message);}return null;
}
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();if (!listeners.isEmpty()) {AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);for (AutoConfigurationImportListener listener : listeners) {invokeAwareMethods(listener);AutoConfigurationImportEvent(event);}}
}
onAutoConfigurationImportEvent,向ConditionEvaluationReport中记录自动配置类和排除过的类
public void onAutoConfigurationImportEvent(AutoConfigurationImportEvent event) {if (this.beanFactory != null) {ConditionEvaluationReport report = (this.beanFactory);CandidateConfigurations());Exclusions());}
}
public Iterable<Entry> selectImports() {if (this.autoConfigurationEntries.isEmpty()) {ptyList();}// 获取到所有的排除Set<String> allExclusions = this.autoConfigurationEntries.stream().map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).Set());// 所有的自动配置类Set<String> processedConfigurations = this.autoConfigurationEntries.stream().map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream).Collection(LinkedHashSet::new));// 再剔除一次veAll(allExclusions);// 排序,并且封装成List<Entry>返回return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream().map((importClassName) -> new (importClassName), importClassName)).List());
}
private List<String> sortAutoConfigurations(Set<String> configurations,AutoConfigurationMetadata autoConfigurationMetadata) {return new AutoConfigurationSorter(getMetadataReaderFactory(), autoConfigurationMetadata).getInPriorityOrder(configurations);
}
private void addToClasses(MetadataReaderFactory metadataReaderFactory,AutoConfigurationMetadata autoConfigurationMetadata, Collection<String> classNames, boolean required) {// 遍历之前扫描出来spring.factories的所有自动配置类for (String className : classNames) {// 判断是否已经添加过if (!ainsKey(className)) {// 封装成AutoConfigurationClass对象AutoConfigurationClass autoConfigurationClass = new AutoConfigurationClass(className,metadataReaderFactory, autoConfigurationMetadata);// 判断是否可用,判断条件如下// 1. 如果是spring-autoconfigure-metadata.properties中申明过的,直接返回true// 2. 如果条件1不满足,判断当前类的class文件或者内部类class文件是否能被加载到,能则返回true// 3. 上述条件不满足返回falseboolean available = autoConfigurationClass.isAvailable();// 递归的根方法中一定会添加,即从spring.factories中找到并过滤后的类一定会被添加// 被AutoConfigureBefore和AutoConfireAfter引入的类如果不满足上面available的条件,则不添加if (required || available) {this.classes.put(className, autoConfigurationClass);}if (available) {// 首先Before()方法找到指定的类,查找原则如下:// 1.如果当前类名是在spring-autoconfigure-metadata.properties中配置了, // 那么就找这个配置文件下key为 类名 + ".AutoConfigureBefore"对应类// 2.如果spring-autoconfigure-metadata.properties下未配置类名的key,就查找该类的注解上@AutoConfigureBefore对应的类// 然后递归查找addToClasses(metadataReaderFactory, Before(), false);// after的同样的逻辑addToClasses(metadataReaderFactory, After(), false);}}}
}
public List<String> getInPriorityOrder(Collection<String> classNames) {AutoConfigurationClasses classes = new adataReaderFactory,this.autoConfigurationMetadata, classNames);List<String> orderedClassNames = new ArrayList<>(classNames);// Initially sort alphabetically// 先按名称顺序排序Collections.sort(orderedClassNames);// 按前面解析出来的AutoConfigurationClass的getOrder排序,getOrder的逻辑和判断before和after类似// 即查看spring-autoconfigure-metadata.properties或者@AutoConfigureOrder注解的Value值,越小越排前orderedClassNames.sort((o1, o2) -> {int i1 = (o1).getOrder();int i2 = (o2).getOrder();return Integerpare(i1, i2);});// Then respect @AutoConfigureBefore @AutoConfigureAfter// 然后respect @AutoConfigureBefore @AutoConfigureAfter// 根据这个配置,再次排序orderedClassNames = sortByAnnotation(classes, orderedClassNames);return orderedClassNames;
}
private List<String> sortByAnnotation(AutoConfigurationClasses classes, List<String> classNames) {// 待排序的List<String> toSort = new ArrayList<>(classNames);toSort.AllNames());// 排好序的Set<String> sorted = new LinkedHashSet<>();// 正在执行排序的Set<String> processing = new LinkedHashSet<>();// 每遍历一个,remove一个while (!toSort.isEmpty()) {doSortByAfterAnnotation(classes, toSort, sorted, processing, null);}// 求交集,最终只返回spring.factories中EnableAutoConfiguration的类// 为什么求交集,因为这里排序只是为了保证我们需要的顺序,而不是决定我们后续需要执行哪些配置类的解析,如果需要在它之前执行的配置类没有,// 并不影响我当前类的配置解析,而如果要判断是否解析,应该由@Conditional来决定ainAll(classNames);return new ArrayList<>(sorted);
}private void doSortByAfterAnnotation(AutoConfigurationClasses classes, List<String> toSort, Set<String> sorted,Set<String> processing, String current) {if (current == null) {current = ve(0);}processing.add(current);// 判断当前需要排序的类是否有需要在某个类之后配置// 如果有for (String after : ClassesRequestedAfter(current)) {// 断言正在执行排序的类是不是包含了需要先配置的类,如果包含了,那么说明这两个类都需要对方在前,那么会导致死循环,因此抛出异常Assert.state(!ains(after),"AutoConfigure cycle detected between " + current + " and " + after);// 如果已经排好序的类中有需要先排序的这个类,说明需要提前把这个类先往前排,因此递归调用,递归调用时current传入需要先排序的这个类// 因此在最开始的判断current == null时不会为true,因此不会从待排序的队列中剔除,然后继续执行这个for逻辑,如果有继续递归,如果没有// 将当前的类名,添加到sorted的列表中,后续在遍历的过程中,依然会在toSort的列表中遍历到该类名,但由于sorted是一个LinkedHashSet// 不允许重复,因此即使重复遍历,也不会产生重复的数据// 如果上述条件不满足说明,需要先排序的已经在前面排好了序,那么就不用管这个类了if (!ains(after) && ains(after)) {doSortByAfterAnnotation(classes, toSort, sorted, processing, after);}}ve(current);// 最终,所有需要先排序的都提前先进入sorted,因此完成了排序sorted.add(current);
}
public void processGroupImports() {for (DeferredImportSelectorGrouping grouping : upings.values()) {Imports().forEach(entry -> {ConfigurationClass configurationClass = (Metadata());try {processImports(configurationClass, asSourceClass(configurationClass),ImportClassName()), false);}catch (BeanDefinitionStoreException ex) {throw ex;}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" Metadata().getClassName() + "]", ex);}});}
}
本文发布于:2024-01-28 16:09:46,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17064293918625.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |