这个系列分为5篇
1. @Component,@Service等注解是如何被解析的
2. @Enable驱动原理
3. @EnableAutoConfiguration处理逻辑
前言
工作中经常用到,如下注解:
@EnableEurekaClient
@EnableFeignClients
@EnableCircuitBreaker
@EnableHystrix
他们都是@Enable开头,各自实现不同的功能,解析这种@Enable的逻辑是什么呢?
@Enable驱动逻辑
找入口
@Enable的模块驱动,依赖于@Import实现。
@Import作用是装载导入类,主要包括@Configuration class,ImportSelector实现类,ImportBeanDefinitionRegistrar实现类。
XML时代,经常是@Import,context:component-scan,context:annotation-config.一起使用。
context:annotation-config(注解配置)中大概率有我们需要找的逻辑。
根据 Spring Framework2.0引入的可扩展的XML编程机制,XML Schema命名空间需要与Handler建立映射关系。
该关系配置在相对于classpath下的/META-INF/spring.handlers中。
查看ContextNamespaceHandler 源码
1public class ContextNamespaceHandler extends NamespaceHandlerSupport { 2 @Override 3 public void init() { 4 //省略其他代码 5 registerBeanDefinitionParser("annotation-config", 6 new AnnotationConfigBeanDefinitionParser()); 7 } 8}
context:annotation-config 对应AnnotationConfigBeanDefinitionParser这个就是要找的入口
找核心类
从AnnotationConfigBeanDefinitionParser的parse方法开始一路向下,找到
AnnotationConfigUtils.registerAnnotationConfigProcessors中注册了ConfigurationClassPostProcessor。

ConfigurationClassPostProcessor类注释说明
1. 用于的引导处理@Configuration类
2. context:annotation-config/或 context:component-scan/时会注册
否则需要手工编程
3. ConfigurationClassPostProcessor第一优先级,保证
@Configuration}类中声明@Bean,在其他 BeanFactoryPostProcessor执行之前被注册
扩展
AnnotationConfigApplicationContext中new AnnotationBeanDefinitionReader也调用了 AnnotationConfigUtils . registerAnnotationConfigProcessors
从类注释中,可以看出ConfigurationClassPostProcessor就是要找的核心类
找核心方法
查看 ConfigurationClassPostProcessor 的层级关系为

Aware系列注入相应资源,Ordered设置优先级,值得关注的就是
postProcessBeanDefinitionRegistry了。
postProcessBeanDefinitionRegistry其内部有2个方法
- postProcessBeanDefinitionRegistry在BeanDefinition注册之后,BeanFactoryPostProcessor执行之前,修改或重写BeanDefinition
- 继承自BeanFactoryPostProcessor的postProcessBeanFactory,BeanDefinition加载之后,Bean实例化之前,重写或添加BeanDefinition,修改BeanFactory
浏览2个方法,都有processConfigBeanDefinitions,从名称可以看出是处理配置类Bean定义

ConfigurationClassPostProcessor#processConfigBeanDefinitions就是要找的核心方法
梳理流程
1public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { 2 List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); 3 String[] candidateNames = registry.getBeanDefinitionNames(); 4 5 for (String beanName : candidateNames) { 6 BeanDefinition beanDef = registry.getBeanDefinition(beanName); 7 if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || 8 ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) { 9 if (logger.isDebugEnabled()) { 10 logger.debug("Bean definition has already been processed as a configuration class: " + beanDef); 11 } 12 } 13 else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) { 14 configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); 15 } 16 } 17 18 // 没有找到 @Configuration classes 立即返回 19 if (configCandidates.isEmpty()) { 20 return; 21 } 22 //根据@Order 值进行排序 23 configCandidates.sort((bd1, bd2) -> { 24 int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); 25 int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); 26 return Integer.compare(i1, i2); 27 }); 28 //通过封闭的应用程序上下文, 检测任何自定义bean名称生成策略 29 supplied through the enclosing application context 30 SingletonBeanRegistry sbr = null; 31 if (registry instanceof SingletonBeanRegistry) { 32 sbr = (SingletonBeanRegistry) registry; 33 if (!this.localBeanNameGeneratorSet) { 34 BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR); 35 if (generator != null) { 36 this.componentScanBeanNameGenerator = generator; 37 this.importBeanNameGenerator = generator; 38 } 39 } 40 } 41 if (this.environment == null) { 42 this.environment = new StandardEnvironment(); 43 } 44 // 解析@Configuration class 45 ConfigurationClassParser parser = new ConfigurationClassParser( 46 this.metadataReaderFactory, this.problemReporter, this.environment, 47 this.resourceLoader, this.componentScanBeanNameGenerator, registry); 48 49 Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates); 50 Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size()); 51 do { 52 parser.parse(candidates); 53 parser.validate(); 54 55 Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); 56 configClasses.removeAll(alreadyParsed); 57 // 读ConfigurationClass的信息,创建BeanDefinition 58 if (this.reader == null) { 59 this.reader = new ConfigurationClassBeanDefinitionReader( 60 registry, this.sourceExtractor, this.resourceLoader, this.environment, 61 this.importBeanNameGenerator, parser.getImportRegistry()); 62 } 63 this.reader.loadBeanDefinitions(configClasses); 64 alreadyParsed.addAll(configClasses); 65 66 candidates.clear(); 67 if (registry.getBeanDefinitionCount() > candidateNames.length) { 68 String[] newCandidateNames = registry.getBeanDefinitionNames(); 69 Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames)); 70 Set<String> alreadyParsedClasses = new HashSet<>(); 71 for (ConfigurationClass configurationClass : alreadyParsed) { 72 alreadyParsedClasses.add(configurationClass.getMetadata().getClassName()); 73 } 74 for (String candidateName : newCandidateNames) { 75 if (!oldCandidateNames.contains(candidateName)) { 76 BeanDefinition bd = registry.getBeanDefinition(candidateName); 77 if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && 78 !alreadyParsedClasses.contains(bd.getBeanClassName())) { 79 candidates.add(new BeanDefinitionHolder(bd, candidateName)); 80 } 81 } 82 } 83 candidateNames = newCandidateNames; 84 } 85 } 86 while (!candidates.isEmpty()); 87 88 // 将ImportRegistry注册为bean以支持importware@Configuration类 89 if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) { 90 sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry()); 91 } 92 if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) { 93 // Clear cache in externally provided MetadataReaderFactory; this is a no-op 94 // for a shared cache since it'll be cleared by the ApplicationContext. 95 ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache(); 96 } 97}
ConfigurationClassPostProcessor#processConfigBeanDefinitions核心如下:
- 根据@Order 值进行排序
- 解析@Configuration class 为ConfigurationClass对象
- 读ConfigurationClass的信息,创建BeanDefinition
- 将ImportRegistry注册为bean以支持importware@Configuration类
重点关注解析方法
ConfigurationClassParser#parse方法负责解析@Configuration class 为ConfigurationClass对象
查阅其源码如下:

ConfigurationClassParser#doProcessConfigurationClass代码如下:
1protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) 2 throws IOException { 3 4 if (configClass.getMetadata().isAnnotated(Component.class.getName())) { 5 // Recursively process any member (nested) classes first 6 processMemberClasses(configClass, sourceClass); 7 } 8 9 // Process any @PropertySource annotations 10 for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( 11 sourceClass.getMetadata(), PropertySources.class, 12 org.springframework.context.annotation.PropertySource.class)) { 13 if (this.environment instanceof ConfigurableEnvironment) { 14 processPropertySource(propertySource); 15 } 16 else { 17 logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + 18 "]. Reason: Environment must implement ConfigurableEnvironment"); 19 } 20 } 21 22 // Process any @ComponentScan annotations 23 Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( 24 sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); 25 if (!componentScans.isEmpty() && 26 !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { 27 for (AnnotationAttributes componentScan : componentScans) { 28 // The config class is annotated with @ComponentScan -> perform the scan immediately 29 Set<BeanDefinitionHolder> scannedBeanDefinitions = 30 this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); 31 // Check the set of scanned definitions for any further config classes and parse recursively if needed 32 for (BeanDefinitionHolder holder : scannedBeanDefinitions) { 33 BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); 34 if (bdCand == null) { 35 bdCand = holder.getBeanDefinition(); 36 } 37 if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { 38 parse(bdCand.getBeanClassName(), holder.getBeanName()); 39 } 40 } 41 } 42 } 43 44 // Process any @Import annotations 45 processImports(configClass, sourceClass, getImports(sourceClass), true); 46 47 // Process any @ImportResource annotations 48 AnnotationAttributes importResource = 49 AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); 50 if (importResource != null) { 51 String[] resources = importResource.getStringArray("locations"); 52 Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader"); 53 for (String resource : resources) { 54 String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); 55 configClass.addImportedResource(resolvedResource, readerClass); 56 } 57 } 58 59 // Process individual @Bean methods 60 Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); 61 for (MethodMetadata methodMetadata : beanMethods) { 62 configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); 63 } 64 65 // Process default methods on interfaces 66 processInterfaces(configClass, sourceClass); 67 68 // Process superclass, if any 69 if (sourceClass.getMetadata().hasSuperClass()) { 70 String superclass = sourceClass.getMetadata().getSuperClassName(); 71 if (superclass != null && !superclass.startsWith("java") && 72 !this.knownSuperclasses.containsKey(superclass)) { 73 this.knownSuperclasses.put(superclass, configClass); 74 // Superclass found, return its annotation metadata and recurse 75 return sourceClass.getSuperClass(); 76 } 77 } 78 79 // No superclass -> processing is complete 80 return null; 81}
ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass,AnnatationMetatdata)将@PropertySource, @ComponentScan, @Import,@ImportResource,@Bean等一起处理了。
看到这里基本逻辑已经理清 了,但是有一个疑问
@Configuration中的@Bean没有其他特殊处理吗?
浏览代码解决疑问

从上边浏览的代码可以看到完全模式,会被AOP增强
那什么是完全模式呢? 在ConfigurationClassUtils找到如下方法:
1public class ConfigurationClassUtils{ 2//省略其他方法 3public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) { 4 return metadata.isAnnotated(Configuration.class.getName()); 5} 6}
即 @Configuration class是完全模式,@Component,@Bean是轻量级模式
那AOP增强了作用是什么呢?查看 ConfigurationClassEnhancer 的类注释如下:
/**
* Enhances {@link Configuration } classes by generating a CGLIB subclass which
* interacts with the Spring container to respect bean scoping semantics for
* {@code @Bean} methods. Each such {@code @Bean} method will be overridden in
* the generated subclass, only delegating to the actual {@code @Bean} method
* implementation if the container actually requests the construction of a new
* instance. Otherwise, a call to such an {@code @Bean} method serves as a
* reference back to the container, obtaining the corresponding bean by name.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.0
* @see #enhance
* @see ConfigurationClassPostProcessor
*/
class ConfigurationClassEnhancer {
大概意思如下:
通过CGLIB增强@Configuration class。
每个@Bean方法会生成子类。
首次被调用时,@Bean方法会被执行用于创建bean实例;
再次被调用时,不会再执行创建bean实例,而是根据bean名称返回首次该方法被执行时创建的bean实例。
总结
1.ConfigurationClassPostProcessor负责筛选@Component Class、@Configuration Class以及@Bean定义的Bean,**
2.ConfigurationClassParser从候选的Bean定义中解析出ConfigurationClass集合,随后被3.ConfigurationClassBeanDefinitionReader转换为BeanDefinition
4.ConfigurationClassParser的解析顺序,
@PropertySource->@ComponentScan->@Import->@ImportResource->@Bean->接口的默认方法->处理父类
5.@Configuration class是完全模式,@Component,@Bean是轻量级模式
6.CGLIB增强@Configuration class。每个@Bean方法会生成子类。
首次被调用时,@Bean方法会被执行用于创建bean实例;
再次被调用时,不会再执行创建bean实例,而是根据bean名称返回首次该方法被执行时创建的bean实例。