@AutoConfigureAfter和@AutoConfigureBefore排序无效?文聊一下SpringBootBean加载和自动配置的顺序。下面我们就以实际的误区来看一下实际开发中存在的问题。我们想要的结果是A-->B-->C。以下是最常见的错误。@ConfigurationpublicclassConfigurationA{ConfigurationA(){System.out.println("ConfigurationA已经初始化!");}}@Configuration@AutoConfigureAfter(ConfigurationA.class)publicclassConfigurationB{ConfigurationB(){System.out.println("ConfigurationB已经初始化!");}}@Configuration@AutoConfigureAfter(ConfigurationB.class)publicclassConfigurationC{ConfigurationC(){System.out.println("ConfigurationC已经初始化!");}}来执行吧。...执行结果:ConfigurationA已经初始化!ConfigurationB已经初始化!ConfigurationC已经初始化!卧槽!!!!!!!!有没有问题?不用担心!!调整代码,想要的结果是C-->B-->A,调整代码:@Configuration@AutoConfigureAfter(ConfigurationB.class)publicclassConfigurationA{ConfigurationA(){System.out.println("ConfigurationAAlreadyinitialized!”);}}@Configuration@AutoConfigureAfter(ConfigurationC.class)publicclassConfigurationB{ConfigurationB(){System.out.println("ConfigurationB已经初始化!");}}@ConfigurationpublicclassConfigurationC{ConfigurationC(){System.out.println("ConfigurationC已经初始化!");}}让我们打开桌子!!!!执行结果:ConfigurationA已经初始化!ConfigurationB已经初始化!ConfigurationC已经初始化!从上面的结果可以看出@AutoConfigureAfter是没有用的。上帝保佑你第一次就做对了。....那么我们来看看源码:*@AutoConfigureAfter归结为受益于SpringBoot自动配置(@EnableAutoConfiguration);@EnableAutoConfiguration通过@Import引入EnableAutoConfigurationImportSelector,这里主要看EnableAutoConfigurationImportSelector-->selectImports()方法*publicString[]selectImports(AnnotationMetadatametadata){if(!isEnabled(metadata)){returnNO_IMPORTS;}try{AnnotationAttributesattributes=getAttributes(metadata);//加载META-INF下的spring.factories配置类Listconfigurations=getCandidateConfigurations(metadata,attributes);配置=removeDuplicates(配置);设置<字符串>exclusions=getExclusions(metadata,attributes);配置.removeAll(排除);//对配置类进行排序,sort方法最终会调用getInPriorityOrder()configurations=sort(configurations);recordWithConditionEval记录uationReport(配置,排除);返回configurations.toArray(newString[configurations.size()]);}catch(IOExceptionex){thrownewIllegalStateException(ex);}}protectedListgetCandidateConfigurations(AnnotationMetadatametadata,AnnotationAttributesattributes){List配置=SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());Assert.notEmpty(configurations,"在META-INF/spring.factories中未找到自动配置类。如果你"+"正在使用自定义包装,请确保该文件是正确的。");返回配置;}看这里法外狂徒"张三"默默的在META-INF下spring.factories加上了......org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.*******。Demo.ConfigurationA,\com.********.Demo.ConfigurationB,\com.********.Demo.ConfigurationC张三:就这个,就这个……?张三激活核按钮:执行结果:ConfigurationA已经初始化!ConfigurationB已经初始化!ConfigurationC已经初始化!这里再简单理解一下易错点。当配置类在Spring扫描路径(scanBasePackages)时,会先解析,然后通过ImportSelector加载进来的配置(spring.factories加载的是实现该接口加载的配置类)类不会被处理,相当于一个类有两种加载方式,谁先加载,谁就最厉害。..这里加载会调用processConfigurationClass()方法,下面会介绍!!!!空口无凭:ConfigurationClassParser-->doProcessConfigurationClass()方法加载顺序为@ComponentScan(扫描文件路径,路径中元注解为@Component(@Configuration元注解也是@Component)会被扫描)--->load@Import注解(带ImportSelector接口)--->load@ImportResource--->load@Bean--->......大体顺序明确。protectedfinalSourceClassdoProcessConfigurationClass(ConfigurationClassconfigClass,SourceClasssourceClass)throwsIOException{//首先递归处理任何成员(嵌套)类processMemberClasses(configClass,sourceClass);//处理任何@PropertySource注解(AnnotationAttributespropertySource:AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(),PropertySources.class,org.springframework.context.annotation.PropertySource.class)){if(this.environmentinstanceofConfigurableEnvironment){processPropertySource(财产来源);}else{logger.warn("忽略["+sourceClass.getMetadata().getClassName()+"]上的@PropertySource注释。原因:环境必须实现ConfigurableEnvironment");}}//处理任何@ComponentScan注释SetcomponentScans=AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(),ComponentScans.class,ComponentScan.class);if(!componentScans.isEmpty()&&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(),ConfigurationPhase.REGISTER_BEAN)){for(AnnotationAttributescomponentScan:componentScans){//配置类使用@ComponentScan注解->执行立即扫描//@1@Configuration注解的类会被解析到SetscandenBeanDefinitions=this.componentScanParser.parse(componentScan,sourceClass.getMetadata().getClassName());//检查任何进一步配置类的扫描定义集,并在必要时递归解析(BeanDefinitionHolderholder:scandenBeanDefinitions){if(ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(),this.metadataReaderFactory)){//@2对加载的类进行必须的解析parse(holder.getBeanDefinition().getBeanClassName(),holder.getBeanName());}}}}//处理任何@Import注释processImports(configClass,sourceClass,getImports(sourceClass),true);//处理任何@ImportResource注解if(sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())){String[]resources=importResource.getStringArray("locations");类readerClass=importResource.getClass("reader");For(Stringresource:resources){StringresolvedResource=this.environment.resolveRequiredPlaceholders(resource);configClass.addImportedResource(resolvedResource,readerClass);}}//处理单个@Bean方法SetbeanMethods=sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());for(MethodMetadatamethodMetadata:beanMethods){configClass.addBeanMethod(newBeanMethod(methodMetadata,configClass));}//处理接口上的默认方法processInterfaces(configClass,sourceClass);//处理超类,如果有的话if(sourceClass.getMetadata().hasSuperClass()){Stringsuperclass=sourceClass.getMetadata().getSuperClassName();如果(!superclass.startsWith("java")&&!this.knownSuperclasses.containsKey(superclass)){this.knownSuperclasses.put(超类,configClass);//找到超类,返回其注释元数据并递归返回sourceClass.getSuperClass();}}//没有超类->处理完成returnnull;}@1会扫描@Configuration注解处理@2会对@1扫描到的类进行必要的处理,@2最后会调用ConfigurationClassParser-->processConfigurationClass()方法。此方法会将解析后的类放入configurationClasses缓存中。当同一个类通过不同的方法解析时,会被合并或跳过protectedvoidprocessConfigurationClass(ConfigurationClassconfigClass)throwsIOException{if(this.conditionEvaluator.shouldSkip(configClass.getMetadata(),ConfigurationPhase.PARSE_CONFIGURATION)){返回;}ConfigurationClassexistingClass=this.configurationClasses.get(configClass);if(existingClass!=null){if(configClass.isImported()){if(existingClass.isImported()){existingClass.mergeImportedBy(configClass);}//否则忽略新导入的配置类;现有的非导入类覆盖它。返回;}else{//省略}}}//递归处理配置类及其超类层次结构。SourceClasssourceClass=asSourceClass(configClass);做{sourceClass=doProcessConfigurat离子类(配置类,源类);}while(sourceClass!=null);this.configurationClasses.put(configClass,configClass);}来来来,你认识张三吗?张三:明白了,有两种解决方法:1.把我们的配置类放在Spring扫描路径之外(scanBasePackages)2.如果还想放在扫描路径里面,需要去掉@Configuration注解