文章目录
- 前言
- 一、ConfigurationClassPostProcessor是什么?
- 二、ConfigurationClassPostProcessor是如何工作的?
- 1.开始创建拦截器实例并执行
- 2.解析前置处理
- 3.开始解析配置类
前言
在使用Spring框架的过程中,我们经常会声明一些配置文件及配置类从而达到自动装配目的,Spring在启动过程中会识别并解析这些声明的配置,最后实例化成对应的对象Bean装载到Spring容器中。常见的如:我们标注了@ComponentScan,则指定的路径下或者指定的类都能自动装载到Spring容器中,而负责这一步骤的重要角色就是ConfigurationClassPostProcessor。
一、ConfigurationClassPostProcessor是什么?
ConfigurationClassPostProcessor其实就是一个Spring容器生命周期中的一个拦截器实现类,即BeanDefinitionRegistryPostProcessors
的实现类,作用的时机就是在Spring容器启动即BeanFactory实例化后进行拦截处理,读取并解析配置类,并将解析到的Bean封装为BeanDenifition
注册到Spring容器中交由后续步骤进行统一的实例化。
关于BeanDefinitionRegistryPostProcessors
定义如下:
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
可以看出,它继承于标准的BeanFactoryPostProcessor
接口并提供了一个额外的扩展方法#postProcessBeanDefinitionRegistry
,该方法优先级比BeanFactoryPostProcessor#postProcessBeanFactory
高,
该接口方法入参提供了一个 BeanDefinitionRegistry
,从字面意思我们可以得知,该拦截器方法的主要作用就是注册BeanDenifition
。
这里的
二、ConfigurationClassPostProcessor是如何工作的?
说在前面的话:
如果是对Spring容器是如何启动不是太了解的话,建议先从玩转Spring 之 IOC容器这篇文章开始哦。
1.开始创建拦截器实例并执行
在刷新容器的第5步,即 AbstractApplicationContext#invokeBeanFactoryPostProcessors
,首先通过getBeanFactoryPostProcessors()
方法获取到所有的拦截器实例(正常情况下,这一步容器中还没有拦截器的实例),但是在容器实例化的阶段,Spring已经内置注册了一些BeanFactoryPostProcessor的Bean定义信息(具体见【玩转Spring 之 IOC容器】),所以PostProcessorRegistrationDelegate
会根据已经注册的BeanFactoryPostProcessor定义信息去执行拦截器的创建及触发,源码如下:
@Override
public void refresh() throws BeansException, IllegalStateException {
......省略部分源码
// 容器启动第5步
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
......省略部分源码
}
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 通过getBeanFactoryPostProcessors()
// 在此处交由PostProcessorRegistrationDelegate委托执行
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
......省略部分源码
}
首先看一下ConfigurationClassPostProcessor
定义:
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
ConfigurationClassPostProcessor
实现了BeanDefinitionRegistryPostProcessor
和 PriorityOrdered
,在这一步就是根据实现这两个接口进行优先级的排序,即:
- 首先,实例化并执行实现了
BeanDefinitionRegistryPostProcessor
和PriorityOrdered
- 其次,实例化并执行实现了
BeanDefinitionRegistryPostProcessor
和Ordered
- 最后,实例化并执行其他的
BeanDefinitionRegistryPostProcessor
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// 首先, 实例化并执行实现了PriorityOrdered的BeanDefinitionRegistryPostProcessors
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// beanFactory.getBean()方式实例化BeanDefinitionRegistryPostProcessor
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 执行,这一步就是解析配置类的入口
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// 接下来, 实例化并执行实现了Ordered的BeanDefinitionRegistryPostProcessors .
// 最后, 实例化并执行剩余的 BeanDefinitionRegistryPostProcessors
// 执行BeanDefinitionRegistryPostProcessors的postProcessBeanFactory方法作为回调
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
// 实例化并执行所有BeanFactoryPostProcessor,和上述优先级规则相同,都是根据实现PriorityOrdered,Ordered 进行排序
...
}
至此,ConfigurationClassPostProcessor
已经实例化并开始执行,见ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
......
// 开始解析
processConfigBeanDefinitions(registry);
}
2.解析前置处理
调用流程如下:
ConfigurationClassPostProcessor ConfigurationClassParser processConfigBeanDefinitions 实例化 parse ConfigurationClassPostProcessor ConfigurationClassParser
- 获取BeanFactory中所有的BeanDefinition (这里除了在容器启动前期加入的一些BeanDefinition外,剩下的应该就是我们@Configuration配置类 )依次判断是否是需要解析的配置类,规则如下:
- 标注了
@Configuration
则为FullConfiguration。 - 标注了
@Component
,@ComponentScan
,@Import
,@ImportResource
则为LiteConfiguration
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 1. 获取BeanFactory中所有的BeanDefinition 依次判断是否是需要解析的配置类
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
// 重点关注该方法ConfigurationClassUtils.checkConfigurationClassCandidate
// 该方法会判断是否是FullConfigurationClass(即加有@Configuration注解)
// 是否是LiteConfigurationClass(即是否加了@Component,@Import,@ComponentScan,ImportResource)
// 是否含有加了@Bean注解的方法
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 以上条件满足,则标记为需要解析的配置类
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
......
}
- 对第一步确定下来的配置类进行排序。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// 1. 获取BeanFactory中所有的BeanDefinition 依次判断是否是需要解析的配置类
......接上述方法
// 2. 对配置类进行排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
......
}
- 实例化ConfigurationClassParser解析器:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// 1. 获取BeanFactory中所有的BeanDefinition 依次判断是否是需要解析的配置类
......
// 2. 对配置类进行排序
......接上述方法
// 3. 实例化解析器
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
......
}
- 调用
ConfigurationClassParser #parse(configCandidates)
方法开始解析步骤1中的configCandidates:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// 1. 获取BeanFactory中所有的BeanDefinition 依次判断是否是需要解析的配置类
......
// 2. 对配置类进行排序
......
// 3. 实例化解析器
......
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
// 4. 开始解析
parser.parse(candidates);
parser.validate();
......
}
while (!candidates.isEmpty());
}
- 将需要解析的信息封装为
ConfigurationClass
进行统一的解析:
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
// 如果是基于注解的则会从这里开始解析
if (bd instanceof AnnotatedBeanDefinition) {
// 将配置类的Metadata传入封装为ConfigurationClass
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());
}
}
......
}
this.deferredImportSelectorHandler.process();
}
// 对ConfigurationClass 开始解析
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
......
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
// 开始解析
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
3.开始解析配置类
doProcessConfigurationClass(configClass, sourceClass);
解析的注解如下:
- @Component
- @PropertySource
- @ComponentScan
- @Import
- @ImportResource
- @Bean
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
// 判断是否加了@Component注解
// 注:@Configuration继承于@Component,所以这一步会去解析Config类
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
// 递归的去解析内部类
processMemberClasses(configClass, sourceClass);
}
// 解析 @PropertySource
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
......
}
// 解析 @ComponentScan
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
// shouldSkip会解析@Conditional判断当前扫描的类是否跳过
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
// 循环扫描@ComponentScan指定的包路径下的类
for (AnnotationAttributes componentScan : componentScans) {
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// 对扫描到的类信息进行递归解析
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
// 递归解析
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 解析 @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
// 解析 @ImportResource
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));
}
......
// null 表示当前类解析结束
return null;
}
下面具体看一下每个注解是如何解析的:
@Component
注解解析:
在解析@Component
注解时,会判断当前类是否会有嵌套类的存在,如果存在,则判断嵌套类是否也需要解析:
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
// 获取当前configClassd的内部类
Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
if (!memberClasses.isEmpty()) {
List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
for (SourceClass memberClass : memberClasses) {
// 对内部类进行判断是否标注了@Configuration
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
candidates.add(memberClass);
}
}
OrderComparator.sort(candidates);
for (SourceClass candidate : candidates) {
if (this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
// 将内部类封装为CofigurationClass开始解析
processConfigurationClass(candidate.asConfigClass(configClass));
}
finally {
this.importStack.pop();
}
}
}
}
}
@ComponentScan
@ComponentScan
的解析依赖于ComponentScanAnnotationParser
,该解析器在实例化ConfigurationClassParser
的构造方法中就已经创建了:
获取@ComponentScan
注解信息:- 对
@ComponentScan
指定的包路径进行扫描: -
@Import
,@ImportResource
,@Bean
这些注解,在上面的解析过程中并没有真正的开始,只是将这些注解引入的一些基础信息准备好,等到上述的步骤都完成后才开始真正解析需要的BeanDenifition
:ConfigurationClassBeanDefinitionReader#loadBeanDefinitions
:
// Process any @ComponentScan annotations
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) {
// 开始解析 ComponentScan 进行扫描
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 needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
// 对扫描到的 BeanDenifition 进行判断,满足@Configuration,@Component 注解的才会作为ConfigurationClass进行解析
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
...... 省略的内容主要是解析@ComponentScan的其他配置属性,如useDefaultFilters, lazyInit
// basePackage 属性值
Set<String> basePackages = new LinkedHashSet<>();
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Collections.addAll(basePackages, tokenized);
}
// basePackageClasses 属性值
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
// 如果没有指定对应的包路径或者class路径,则默认扫描声明@ComponentScan类的所在包
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
// exclude当前的声明@ComponentScan的class,因为在容器初始阶段就已经注册,这里不会重复扫描并解析
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
// 开始扫描
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
// 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());
}
// 注册BeanDefinition
this.reader.loadBeanDefinitions(configClasses);
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
// 判断是否需要过滤掉的configClass
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注解引入的
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// 从@Bean方式引入的
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 从@ImportResource配置文件引入的
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 如果是实现了ImportBeanDefinitionRegistrar
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
到这里,ConfigurationClassPostProcessor
的职责就全部完成了,所有需要交由Spring实例化的BeanDenifition
都已经注册到容器中,交由后续的步骤进行统一的实例化和初始化。