Spring中有各类注解,好比@Configuration、@Import、@ComponentScan、@Autowired等等,那Spring是怎么识别和解析这些注解的呢。是经过BeanFactoryPostProcessor和BeanPostProcessor这两种扩展的机制来实现解析和识别的。那么咱们来认识下这些处理注解的各类BeanFactoryPostProcessor和BeanPostProcessor,包括:java
它们都是经过方法AnnotationConfigUtils#registerAnnotationConfigProcessors()向容器中注册的,所以咱们能够得出这么一个结论,不管是经过SpringBoot、xml文件的<context:/>扩展标签仍是纯JavaConfig形式的标准应用,最终底层都会调用这个方法向容器注册这些BeanFactoryPostProcessor和BeanPostProcessor的,这样才能识别这些注解起到配置的做用。ui
ConfigurationClassPostProcessor会处理全部BeanDefinition中的符合注解条件的BeanDefinition,(@Configuration注解的、@Component、@ComponentScan、@Import、@ImportResource或者@Bean注解的),使用ConfigurationClassParser解析出javaconfig配置类,使用ConfigurationClassBeanDefinitionReader对解析出的结果进行加载。this
PS:ConfigurationClassPostProcessor是对全部注册到Spring容器中的BeanDefinition进行处理,是已经注册的是关键,无论是手动注册仍是扫描机制。lua
对全部BeanDefinition进行筛查,符合条件的是带有注解@Configuration、@Component、@ComponentScan、@Import、@ImportResource或者@Bean注解的。spa
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) { configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); }
带有@Configuration注解的Bean Class上面的注解@ComponentScan、@Import、@ImportResource、@Bean这些注解是怎么解析的呢,就是使用ConfigurationClassParser类来依依解析的。根据注解的不一样进行不一样的处理,目的是找出全部的配置类。咱们抽出重要的部分看下,对应方法为processConfigurationClass():code
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { // Recursively process any member (nested) classes first ... // Process any @PropertySource annotations ... // Process any @ComponentScan annotations <1>、处理@ComponentScan注解 // Process any @Import annotations <2>、处理@Import注解 // Process any @ImportResource annotations <3>、处理@ImportResource注解 // Process individual @Bean methods <4>、处理单独的@Bean注解方法 // Process superclass, if any ... // No superclass -> processing is complete return null; }
直接使用ClassPathBeanDefinitionScanner进行扫描,对扫描出的候选配置类在进行步骤2的处理component
// Process any @ComponentScan annotations AnnotationAttributes componentScan = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ComponentScan.class); if (componentScan != null && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { // The config class is annotated with @ComponentScan -> perform the scan immediately // 使用ClassPathBeanDefinitionScanner扫描 Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // Check the set of scanned definitions for any further config classes and parse recursively if necessary for (BeanDefinitionHolder holder : scannedBeanDefinitions) { if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) { // 若是是配置类,递归处理 parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName()); } } }
找出全部Import注解(包括注解的层级关系,父子注解)的属性Class,根据Class的类型不一样进行不一样处理,对应方法processImports()orm
2.一、ImportSelectorxml
若是类型是ImportSelector,会建立ImportSelector的实例调用selectImports方法,将返回值做为@Import注解的class属性,递归调用processImports()对象
2.二、ImportBeanDefinitionRegistrar
若是类型是ImportBeanDefinitionRegistrar,建立ImportBeanDefinitionRegistrar的对象先加入importBeanDefinitionRegistrars属性中
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
2.三、其余类型
若是不是,也不是,就把当当成@Configuration类型的,调用processConfigurationClass()从新处理
for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports Class<?> candidateClass = candidate.loadClass(); ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); ParserStrategyUtils.invokeAwareMethods( selector, this.environment, this.resourceLoader, this.registry); if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { this.deferredImportSelectors.add( new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); } else { String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); processImports(configClass, currentSourceClass, importSourceClasses, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // Candidate class is an ImportBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); ParserStrategyUtils.invokeAwareMethods( registrar, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass)); } }
分别获取@ImportResource设置的location属性,放入到importedResources中
AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); if (importResource != null) { String[] resources = importResource.getStringArray("locations"); Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader"); for (String resource : resources) { String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); configClass.addImportedResource(resolvedResource, readerClass); } }
带有@Bean注解的方法,都加入到beanMethods中
// Process individual @Bean methods Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); }
使用ConfigurationClassParser解析每一个带有@Configuration注解的Bean的类以后,这个类上面的@ComponentScan、@Import、@ImportResource、@Bean这些注解都已经被解析过了。须要使用
ConfigurationClassBeanDefinitionReader来将解析的结果加载到Spring容器中。
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) { TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator(); for (ConfigurationClass configClass : configurationModel) { loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator); } } private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { // // if (configClass.isImported()) { // 一、这个表示这个Class是被其余@Configuration的类导入的(使用@Import),就这个Class定义为BeanDefinition注册到Spring容器中 registerBeanDefinitionForImportedConfigurationClass(configClass); } 二、每一个@Bean注解的方法,解析@Bean的属性,而且将这个方法定义为BeanDefinition注册到Spring容器中 for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } 三、加载@ImportResource定义的配置文件,xml格式或者groovy格式 loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); 四、调用每一个ImportBeanDefinitionRegistrar的registerBeanDefinitions方法,由ImportBeanDefinitionRegistrar来实现注册的逻辑 loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
说明:
Spring中的@Configuration、@ComponentScan、@Import、@ImportResource、@Bean这些注解是ConfigurationClassPostProcessor来负责处理的。ConfigurationClassPostProcessor是BeanFactoryPostProcessor,在Spring注册完全部的BeanDefinition以后实例化Bean以前进行扩展。ConfigurationClassPostProcessor负责处理这些,其中根据注解的不一样可能会向Spring注册新的BeanDefinition。
@Configuration注解描述的类自己会被注册到容器,@Bean描述的方法会被注册到容器,@ImportResource描述的配置文件会被加载会解析出BeanDefinition注册到Spring中
@Import导入的普通类会当作ConfigClass处理,@Import导入的ImportSelector类会执行ImportSelector#selectImports()方法,方法返回的类也做为导入进行处理@Import的逻辑,@Import导入的ImportBeanDefinitionRegistrar类,会调用它的registerBeanDefinitions()方法,由它来自定义注册BeanDefinition的逻辑。