Spring源码解析之 ——ConfigurationClassPostProcessor
思考:
(1) @Configuration,@Component,@Bean,@Import 注解的作用是什么? 什么时候被解析的。
这里就ConfigurationClassPostProcessor就上场了
先看张图,这个就是ConfigurationClassPostProcessor解决的构建节点。ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor,
而BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor,所以 ConfigurationClassPostProcessor 中须要重写postProcessBeanDefinitionRegistry()
办法和postProcessBeanFactory()办法。而ConfigurationClassPostProcessor类的作用就是通过这两个办法去实现的。
ConfigurationClassPostProcessor做些什么?
1:postProcessBeanDefinitionRegistry()将@Configuration,@Component,@Bean,@Import等注解的对象,解析为BeanDefinition,放在容器中,期待被解析为Spring bean;
这里会将@Configuration注解的类的BeanDefinition增加个属性,标记是FULL,还是LITE
2:postProcessBeanFactory()被标记FULL的BeanDefinition的beanClass替换为Cglib代理的class名
processConfigBeanDefinitions()代码解析
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); String[] candidateNames = registry.getBeanDefinitionNames(); //.....省略 // 将候选者进行排序 configCandidates.sort((bd1, bd2) -> { int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); return Integer.compare(i1, i2); }); // Detect any custom bean name generation strategy supplied through the enclosing application context SingletonBeanRegistry sbr = null; if (registry instanceof SingletonBeanRegistry) { sbr = (SingletonBeanRegistry) registry; if (!this.localBeanNameGeneratorSet) { BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton( AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR); if (generator != null) { this.componentScanBeanNameGenerator = generator; this.importBeanNameGenerator = generator; } } } if (this.environment == null) { this.environment = new StandardEnvironment(); } //创立@Configuration解析器 ConfigurationClassParser parser = new ConfigurationClassParser( this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry); Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates); Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size()); do { StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse"); // 解析配置类,在此处会解析配置类上的注解(ComponentScan扫描出的类,@Import注册的类,以及@Bean办法定义的类) // 留神:这一步只会将加了@Configuration注解以及通过@ComponentScan注解扫描的类才会退出到BeanDefinitionMap中 // 通过其余注解(例如@Import、@Bean)的形式,在parse()办法这一步并不会将其解析为BeanDefinition放入到BeanDefinitionMap中, // 而是先解析成ConfigurationClass类 // 真正放入到map中是在上面的this.reader.loadBeanDefinitions()办法中实现的 parser.parse(candidates); parser.validate(); Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); configClasses.removeAll(alreadyParsed); // Read the model and create bean definitions based on its content if (this.reader == null) { this.reader = new ConfigurationClassBeanDefinitionReader( registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry()); } // 将上一步parser解析出的ConfigurationClass类加载成BeanDefinition // 实际上通过上一步的parse()后,解析进去的bean曾经放入到BeanDefinition中了,然而因为这些bean可能会引入新的bean,例如实现了ImportBeanDefinitionRegistrar或者ImportSelector接口的bean,或者bean中存在被@Bean注解的办法 // 因而须要执行一次loadBeanDefinition(),这样就会执行ImportBeanDefinitionRegistrar或者ImportSelector接口的办法或者@Bean正文的办法 this.reader.loadBeanDefinitions(configClasses); alreadyParsed.addAll(configClasses); processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end(); candidates.clear(); //....省略代码 } while (!candidates.isEmpty()); //.....省略代码 }
1.parser.parse()
依据BeanDefinition类型的不同,调用parse()不同的重载办法。理论是调用ConfigurationClassParser中的processConfigurationClass()办法
parse()具体代码
public void parse(Set<BeanDefinitionHolder> configCandidates) { for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { if (bd instanceof AnnotatedBeanDefinition) { parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } this.deferredImportSelectorHandler.process(); }
processConfigurationClass()办法中理论解析的办法为doProcessConfigurationClass()办法
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException { //.....省略代码 SourceClass sourceClass = asSourceClass(configClass, filter); do { sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter); } while (sourceClass != null); this.configurationClasses.put(configClass, configClass); }
doProcessConfigurationClass()办法中就开始了Spring一些注解的解析
protected final SourceClass doProcessConfigurationClass( ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter) throws IOException { //解析@Component注解的类 if (configClass.getMetadata().isAnnotated(Component.class.getName())) { //遍历被注解类的外部类,这个也是为什么一些外部类一样会被spring获取到的起因 processMemberClasses(configClass, sourceClass, filter); } // 解析@PropertySource注解 for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { if (this.environment instanceof ConfigurableEnvironment) { processPropertySource(propertySource); } else { logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } // 解析@ComponentScans , @ComponentScan注解 Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { for (AnnotationAttributes componentScan : componentScans) { //解析@ComponentScans , @ComponentScan扫描包下的@Component,@Service,@Controller,@Repository注解。 //将扫描进去的类转为bd增加到beanDefinitionMap中 Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); //对@Configuration注解进行非凡解决 for (BeanDefinitionHolder holder : scannedBeanDefinitions) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } //checkConfigurationClassCandidate给@Configuration注解的类打上FULL标记 if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } } //解析Import注解注册的bean,这一步只会将import注册的bean变为ConfigurationClass,不会变成BeanDefinition processImports(configClass, sourceClass, getImports(sourceClass), filter, true); //引入配置文件 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注解 Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } //......省略代码 // No superclass -> processing is complete return null; }
componentScanParser.parse()在扫描时会通过includeFilters和excludeFilters条件去决定具体扫描的bean,然而理论includeFilters中只有
@Component注解,然而理论中扫描的到的bean,也会将@Service,@Controller,@Repository,@Controller都会被扫描进去。
这里大略是@Component元注解,Spring在读取@Service,@Controller,@Repository,@Controller,也读取了它的元注解,并将作为@Component解决。这里就不做具体分析了。
2.this.reader.loadBeanDefinitions()
在执行parse()办法后@Component,@Service等注解的bean会被注解增加到beanDefinitionMap,而@Import,@Bean这些会被转为ConfigurationClass进行下一步解析。
这里是loadBeanDefinitions()外面外围办法
private void loadBeanDefinitionsForConfigurationClass( ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { if (trackedConditionEvaluator.shouldSkip(configClass)) { String beanName = configClass.getBeanName(); if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) { this.registry.removeBeanDefinition(beanName); } this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName()); return; } //注册@Import润饰的bean if (configClass.isImported()) { registerBeanDefinitionForImportedConfigurationClass(configClass); } //注册@Bean润饰的bean for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } //注册@ImportResources配置的信息 loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); //@Import注解的bean,且bean实现了ImportBeanDefinitionRegistrar loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
3.postProcessBeanFactory()办法
postProcessBeanFactory()对加了@Configuration注解的类进行CGLIB代理和向Spring中增加一个后置处理器ImportAwareBeanPostProcessor。
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { //.....省略代码 //@Configuration注解的类进行CGLIB代理 enhanceConfigurationClasses(beanFactory); //增加一个后置处理器ImportAwareBeanPostProcessor beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory)); }