ConfigurationClassPostProcessor是Spring框架中用于处理Java配置类的关键组件。本文将深入解析ConfigurationClassPostProcessor的源码,详细介绍其工作原理和实现细节。我们将从其基本概念和作用出发,逐步剖析ConfigurationClassPostProcessor的初始化、配置类解析、Bean定义注册等核心步骤。
概述
定义和作用
ConfigurationClassPostProcessor 是 Spring 框架中的一个关键组件,用于处理 Java 配置类(使用 @Configuration 注解的类)。它的主要作用是解析这些配置类并注册相应的 Bean 定义到 Spring 容器中。
ConfigurationClassPostProcessor 是一个实现了 BeanDefinitionRegistryPostProcessor
接口的类。
ConfigurationClassPostProcessor 的主要作用包括以下几个方面:
- 解析 @Configuration:负责扫描和解析所有标注了 @Configuration 注解的类。@Configuration 类通常包含一个或多个 @Bean 方法,这些方法定义了需要注册到 Spring 容器中的 Bean。
- 处理 @Bean 方法:在解析 @Configuration 类时,ConfigurationClassPostProcessor 会处理其中的 @Bean 方法,并将这些方法返回的对象注册为 Spring 容器中的 Bean。每个 @Bean 方法相当于一个工厂方法,用于创建和配置特定类型的 Bean。
- 解析 @ComponentScan:此注解用于指定包扫描路径,以自动发现和注册使用 @Component、@Service、@Repository 等注解的 Bean。ConfigurationClassPostProcessor 会处理这些扫描路径,并将扫描到的 Bean 定义注册到 Spring 容器中。
- 处理 @Import 注解:此注解用于导入其他配置类或特定的 ImportSelector 和 ImportBeanDefinitionRegistrar 实现。ConfigurationClassPostProcessor 会处理这些导入,并将相关的 Bean 定义注册到 Spring 容器中。
- 处理 @PropertySource 注解:此注解用于加载外部属性文件。ConfigurationClassPostProcessor 会解析这些注解并将属性文件的内容加载到 Spring 的环境中,以便在配置类或 @Value 注解中使用。
- 处理 @ImportResource 注解:此注解用于将外部的 XML 配置文件导入到 Spring 应用上下文中,这样可以将 XML 配置和 Java 配置结合使用。
常见使用场景及其影响
1.Java 配置类替代 XML 配置
使用场景:开发者希望使用 Java 配置类来替代传统的 XML 配置文件,以便利用 Java 语言的类型安全性和 IDE 提供的代码补全等功能。
影响:提高了配置的可读性和可维护性。Java 配置类能够使用面向对象的设计模式,便于重构和调试。
2.组件扫描
使用场景:通过 @ComponentScan
注解自动扫描特定包中的组件,简化 Bean 注册。
影响:减少手动注册 Bean 的工作量,自动发现和注册组件,使应用更具模块化。
3.导入其他配置类
使用场景:通过 @Import
注解导入其他配置类,实现配置的模块化和分离。
影响:可以将配置拆分成多个类,便于管理和维护,并且可以重用配置。
4.加载外部 XML 配置
使用场景:通过 @ImportResource
注解加载外部的 XML 配置文件,实现 XML 配置和 Java 配置的混合使用。
影响:在逐步迁移到 Java 配置时非常有用,可以同时使用现有的 XML 配置和新的 Java 配置。
5.属性文件加载
使用场景:通过 @PropertySource
注解加载外部属性文件,使属性配置更加灵活。
影响:能够将配置属性从代码中分离出来,方便环境配置和管理。
初始化过程
通过对于上下文 AnnotationConfigApplicationContext 的学习,我们知道,在 AnnotationConfigApplicationContext 的构造方法中,Spring 首先就会自动的注册 5 个 Bean,其中还有两个有关 Spring 事件相关的我们先忽略,剩下的还有三个重要的类型:
- ConfigurationClassPostProcessor:处理 @Configuration、@ComponentScan、@Import、@ImportResource、@PropertySource 注解。
- AutowiredAnnotationBeanPostProcessor:处理 @Autowired、@Value、@Inject 注解。
- CommonAnnotationBeanPostProcessor:处理 JSR-250 规范中的注解,比如 @Resource、@PostConstruct、@PreDestory 等。
这三个 Bean 中,ConfigurationClassPostProcessor 是 BeanFactoryPostProcessor 的实现类,而 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 都是 BeanPostProcessor 的实现类。
那么再深入一下源码,找到真正注册这五个 Bean 的地方:
AnnotationConfigApplicationContext 的无参构造会初始化 AnnotatedBeanDefinitionReader 对象,而注册这五个 Bean 的时机就是在 AnnotatedBeanDefinitionReader 的构造方法中:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
// 就是这里!
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
...
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
// 注册 org.springframework.context.annotation.internalConfigurationAnnotationProcessor
// ConfigurationClassPostProcessor 用来处理 Configuration 注解
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 注册 org.springframework.context.annotation.internalAutowiredAnnotationProcessor
// AutowiredAnnotationBeanPostProcessor 用来处理 Autowired 注解
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 注册 org.springframework.context.annotation.internalCommonAnnotationProcessor
// CommonAnnotationBeanPostProcessor 用来处理通用注解,例如:@Resource
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 注册 org.springframework.context.event.internalEventListenerProcessor
// 与 EventListener 有关
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
// 注册 org.springframework.context.event.internalEventListenerFactory
// 还是与 EventListener 有关
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
源码剖析
基于前面上下文 refresh 的学习内容,invokeBeanFactoryPostProcessors 用于调用 BeanFactoryPostProcessors 的后置处理器,执行程序员自定义的 BeanFactoryPostProcessors 和 Spring 内部自己定义的。
Spring 在这个环境会先后执行 ConfigurationClassPostProcessor 的 postProcessBeanDefinitionRegistry 和 postProcessBeanFactory 方法。本篇文章我们就主要分析这两个方法的逻辑。
postProcessBeanDefinitionRegistry
接口回调入口
ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
此方法为接口 BeanDefinitionRegistryPostProcessor 中的方法。
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
// 将 registryId 放入 registriesPostProcessed 中,在 postProcessBeanFactory 方法中就不会再执行
this.registriesPostProcessed.add(registryId);
// 根据方法名,顾名思义,处理配置 Bean
processConfigBeanDefinitions(registry);
}
处理配置类 Bean 定义
ConfigurationClassPostProcessor#processConfigBeanDefinitions
processConfigBeanDefinitions 方法的作用就是处理配置类,重要部分在 parser.parse(candidates)
这一行。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// 存放 appConfig 提供的 BeanDefinition
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 获取容器中注册的所有 BeanDefinition 名字
String[] candidateNames = registry.getBeanDefinitionNames();
// Full or Lite
for (String beanName : candidateNames) {
// 根据 beanName 拿到 BeanDefinition
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
// 根据 BeanDefinition 里面的 class 属性来判断
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)||ConfigurationClassUtils.isLiteConfigurationClass(beanDef) {
// 如果 BeanDefinition 中的 configurationClass 属性为 full 或者 lite,则意味着已经处理过了,直接跳过
} else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 判断是不是 Configuration 类,如果加了 @Configuration 注解的就是 Full
// 如果是下面四个注解就是 Lite
// candidateIndicators.add(Component.class.getName());
// candidateIndicators.add(ComponentScan.class.getName());
// candidateIndicators.add(Import.class.getName());
// candidateIndicators.add(ImportResource.class.getName());
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
if (configCandidates.isEmpty()) {
return;
}
// 排序,根据 order,不重要
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
SingletonBeanRegistry sbr = null;
// 如果 BeanDefinitionRegistry 是 SingletonBeanRegistry 子类的话,
// 由于我们当前传入的 DefaultListableBeanFactory 是 SingletonBeanRegistry 的子类
// 因此会将 registry 强转为 SingletonBeanRegistry
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
// Bean 名称生成策略器
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
// SingletonBeanRegistry 中有 id 为 org.springframework.context.annotation.internalConfigurationBeanNameGenerator
// 如果有则利用它的,否则则是 Spring 默认的
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// 实例化 ConfigurationClassParser 为了解析各个配置类
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
// 实例化两个集合,candidates 用于将之前加入的 configCandidates 进行去重,因为可能有多个配置类重复了
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
// alreadyParsed 用于存放是否已经处理过
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
// 核心解析流程,重要!
// 其实就是把类上面的特殊注解解析出来,最终封装成 BeanDefinition 注册到工厂
parser.parse(candidates);
parser.validate();
// parser.getConfigurationClasses() 方法拿到所有扫描到和 Import 导入等所有方式导入的类信息
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());
}
// 这里是去真正的注册!刚刚在解析 @Import、@Bean、@Import 等注解的时候,并没实际创建 BeanDefinition 并注册,而是将数据暂存起来
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
// 这样做主要是防止有些 Bean 没有注册
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
配置类解析 parser.parse
ConfigurationClassParser#parse
我们仔细看一下 parser.parse() 方法,在 ConfigurationClassParser 类中的 parse 方法:
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<>();
// 根据 BeanDefinition 的类型做不同的处理,一般都会调用 ConfigurationClassParser#parse 进行解析
// 此处初始传进来就是一个配置类 appConfig.class
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
// 扫描注解得到的 BeanDefinition
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
} else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
// 非扫描注解得到的 BeanDefinition
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
} else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
} catch (BeanDefinitionStoreException ex) {
throw ex;
} catch (Throwable ex) {
// 抛异常略
}
}
// 处理延迟加载的 importSelect?为什么要延迟加载,估计就是为了延迟吧
this.deferredImportSelectorHandler.process();
}
protected final void parse(AnnotationMetadata metadata, String beanName) {
// 根据注解信息和 beanName 创建一个 ConfigurationClass
// 此方法或被多处递归调用!比较难理解...
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
解析配置类 processConfigurationClass
ConfigurationClassParser#processConfigurationClass
解析配置类 processConfigurationClass 方法,重点!
protected void processConfigurationClass(ConfigurationClass configClass) {
// 根据注解信息判断是不是跳过解析
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
// 处理 Imported 的情况,就是当前这个注解类有没有被别的类 import
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
return;
} else {
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// 递归地处理配置类及其超类层次结构
SourceClass sourceClass = asSourceClass(configClass);
do {
// 处理配置类
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
真正开始解析 doProcessConfigurationClass
ConfigurationClassParser#doProcessConfigurationClass
整个过程只有 @ComponentScan 进行了 BD 的创建和注册,其他的都没有进行实际性的 BD 创建注册。
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass){
// 首先递归地处理内部类(内部类也可以使用相关注解)
processMemberClasses(configClass, sourceClass);
// 处理 @PropertySource 注解,加载外部的 properties 配置文件,通过 environment 加载
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
}
// 处理 @ComponentScan 注解
// 此处或扫描到 @ComponentScan 注解包下面的所有加了 @Component、@Service 等注解的类
// 注意的是,每扫描到一个符合条件的类,都要进行递归扫描,重新调用 doProcessConfigurationClass() 方法
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) {
// 扫描解析在这里
// 这里扫描出来所有 @Component,并且把扫描的出来的普通 bean 放到 bdMap 当中
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();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
// 检查扫描出来的配置类有没有配置类,进行再次解析,递归调用
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
/**
* 下面这个方法是处理 @Import 注解 导入类的三种情况:
* 1. ImportSelector
* 2. 普通类
* 3. ImportBeanDefinitionRegistrar
* 此处 import 导入的类并不会立刻转化为 bd 放入到 bdMap 中
*
* 这里处理的 import 是需要判断我们的配置类有 @Import 注解
* 在解析的过程中如果 @Import 指定是一个普通类,
* 比如 @Import(Student.class),那么这里便把 Student 类当做 @Configuration 类进行解析(这里就有递归)
* 虽然这里当做 @Configuration 类进行解析,但是当前 Import 的这个类不会创建 BD 进行注册
*
* 在解析的过程中如果发觉是一个 importSelector 实现类
* 首先反射创建 importSelector 对象
* 然后执行一系列 Aware 通知方法
* 然后回调 selector() 方法,返回一个字符串(类名)数组
* 继而在递归调用本方法来处理这个类
* 这里不会创建 BD,更不会注册
*
* 如果发现是 ImportBeanDefinitionRegistrar 实现类
* 首先反射创建 ImportBeanDefinitionRegistrar 对象
* 然后执行一系列 Aware 通知方法
* 然后将创建的对象添加到配置类的 importBeanDefinitionRegistrars 中
* 这样不会递归去处理,也不会创建 BD,更不会注册
*/
processImports(configClass, sourceClass, getImports(sourceClass), true);
// 处理 @ImportResource 注解
// 这里只是去解析配置文件的位置添加到配置类的 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 方法,这里也只是进行解析,并没有实际的创建 BD 和注册
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// 处理接口上的默认方法
processInterfaces(configClass, sourceClass);
// 处理超类(如果有的话)
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
这里要注意:
-
首先把配置类
appConfig.class
类转化后的的BeanDefinition
,并标记为Full
还是Lite
-
然后第一次进入到
parser.parse()
方法时,参数只有一个配置类appConfig.class
-
接着调用
parser.parse(appConfig.class)
开始扫描,此处是个循环 -
接着递归调用 doProcessConfigurationClass() 方法
-
在这个方法中,先处理
@PropertySource
注解 -
接着处理
@ComponentScan
注解,把扫描到的类符合条件的放入到集合中,遍历这个结合,再次调用parse()
扫描方法。此处扫描出来的类,会被转化为BeanDefinition
,然后直接注册到bdMap
中 -
接着处理
@Import
注解,分三种情况,分别是:ImportSelector
、ImportBeanDefinitionRegistrar
、普通导入类。此处会递归调用processConfigurationClass()
方法来确定被导入的类是否又需要解析。注意,此处导入符合条件的类,并不会立即转化为 BeanDefinition!而是在当前类解析完成后,通过reader.loadBeanDefinitions(configClasses)
创建和注册 BeanDefinition -
接着处理
@ImportResource
注解 -
接着处理处理单个的
@Bean
方法,不会立即转化为 BeanDefinition!而是在当前类解析完成后,通过reader.loadBeanDefinitions(configClasses)
创建和注册 BeanDefinition -
…
-
postProcessBeanFactory
此方法就是为全注解类生成的 CGLib 代理,至于代理类的生成,是通过使用 Enhancer
增强器。
接口回调入口
此方法为接口 BeanFactoryPostProcessor 中的方法。
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
this.factoriesPostProcessed.add(factoryId);
// registriesPostProcessed中 已经包含了 factoryId
if (!this.registriesPostProcessed.contains(factoryId)) {
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
// 根据方法名,顾名思义,增强配置类
enhanceConfigurationClasses(beanFactory);
// 向 Spring 容器中添加一个 ImportAwareBeanPostProcessor 后置处理器,主要用于将 @Import 注解的元信息注入给配置类
// 为什么在这里去添加?因为只有 ConfigurationClassPostProcesser 处理完 @Import 之后,ImportAwareBeanPostProcessor 才有意义
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
增强配置类
只对 Full 类型的配置类进行增强。为其包装代理类。
注意:这里不会实际的创建代理对象!而是先创建代理类的结构,此时的所有处理都是围绕着 @Configuration 代理类的 BeanDefinition。
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
// 此 Map 是存放具有 Full 属性的 BeanDefinition
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
// 遍历 BeanFactory 工厂中的 BeanDefinitionNames,获取所有 @Configuration 修饰的 BeanDefinition
for (String beanName : beanFactory.getBeanDefinitionNames()) {
// 根据 beanName 从 bdMap 中拿到对应的 BeanDefinition
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
// 判断 BeanDefinition 是否是 Full 类型
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
configBeanDefs.put(beanName, (AbstracteanDefinition) beanDef);
}
}
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
return;
}
// 创建一个配置类增强器
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
// 循环存放属性为 Full 的 BeanDefinition
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
// If a @Configuration class gets proxied, always proxy the target class
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
try {
// Set enhanced subclass of the user-specified bean class
Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
if (configClass != null) {
// 完成对全注解类的 CGLib 代理
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
// 替换原有的 Class 为代理后的类型
beanDef.setBeanClass(enhancedClass);
}
}
} catch (Throwable ex) {
// 抛异常代码略
}
}
}
// ConfigurationClassEnhancer#enhance
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
// 判断是否被代理过
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
return configClass;
}
// 没有被代理 CGLib 代理则创建代理
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
return enhancedClass;
}
// 创建 CGLib 动态代理
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
// 增强父类,地球人都知道 CGLib 是基于继承来的,不要求父类实现接口
enhancer.setSuperclass(configSuperClass);
// 增强接口,为什么要增强接口?便于判断,表示一个类以及被增强了
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
// 不继承 Factory 接口
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
// BeanFactoryAwareGeneratorStrategy 是一个生成策略
// 主要为生成的 CGLIB 类中添加成员变量 $$beanFactory
// 同时基于接口 EnhancedConfiguration 的父接口 BeanFactoryAware 中的 setBeanFactory 方法,
// 设置此变量的值为当前 Context 中的 beanFactory,这样一来我们这个 CGLIB 代理的对象就有了 beanFactory
// 有了 factory 就能获得对象,而不用去通过方法获得对象了,因为通过方法获得对象不能控制器过程
// 该 BeanFactory 的作用是在 this 调用时拦截该调用,并直接在 beanFactory 中获得目标 bean
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
// 过滤方法,不能每次都去 new
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}
这里增强的内容由两个拦截器提供,这两个类都是 ConfigurationClassEnhancer 的内部类:
- BeanMethodInterceptor:用于为 @Bean 方法添加作用域的支持和 BeanFactory 支持,以及解析 Bean 的依赖关系(@Bean 方法的参数注入)。
- BeanFactoryAwareMethodInterceptor:用于注入相关的 Aware 对象。
为什么要创建 CGLib 去增强?
原因是为了确保 @Configuration
类和 @Bean
方法能够按照预期的方式工作。通过代理和其他技术手段,Spring 可以确保 bean 的单例性、依赖注入、懒加载等特性都能得到正确处理,从而保证整个应用的配置和运行都符合 Spring 框架的设计规范和预期行为。
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
@Bean
public MyRepository myRepository() {
// myRepository 依赖 myService
return new MyRepositoryImpl(myService());
}
}
在这个示例中,myRepository
依赖 myService
。如果没有增强,调用 myService()
方法时,每次都会返回一个新的 MyServiceImpl
实例,而不是返回同一个单例实例。通过增强配置类,Spring 能够确保 myService()
方法返回的始终是同一个实例。
为什么使用的是 CGLib 去做动态代理而不是 JDK?
由于这些类通常不会实现任何接口,因此使用 CGLIB 动态代理更为合适。
详细步骤解析
配置类扫描:@ComponentScan 注解的解析
@ComponentScan 只会扫描 @Component 和 @Component 的衍生注解,例如 @Controller、@Service、@Repository 和没有再启动时指定的 @Configuration 注解,像 @Bean、@Import 等注解不在这里扫描。
通过上面的源码分析,我们得知,ConfigurationClassParser#doProcessConfigurationClass
在真正进行 @ComponentScan 处理的时候,将扫描和生成注册 BeanDefinition 的职责转交给 ComponentScanAnnotationParser 类处理。
// 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) {
// 扫描、创建 BD、注册 BD,都是由 ComponentScanAnnotationParser 处理
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());
}
}
}
}
接下来我们详细看一下 ComponentScanAnnotationParser 的 parse 方法。
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
// Spring 自己 new 的一个 ClassPathBeanDefinitionScanner 进行扫描!这个类见到很多次了
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
// 下面这一堆都是在配置扫描策略...
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
// 设置扫描器的 BeanName 生成器
scanner.setBeanNameGenerator(useInheritedGenerator ?
this.beanNameGenerator : BeanUtils.instantiateClass(generatorClass));
// 设置 componentScan 的代理模式
ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
scanner.setScopedProxyMode(scopedProxyMode);
} else {
Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
}
// 设置扫描器的资源模式
scanner.setResourcePattern(componentScan.getString("resourcePattern"));
// 看看 componentScan 注解是否设置了 includeFilters 属性
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
// 看看 componentScan 注解是否设置了 excludeFilters 属性
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addExcludeFilter(typeFilter);
}
}
// 看看 componentScan 注解是否设置了 lazyInit 属性
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
// 此集合放的是扫描的路径
Set<String> basePackages = new LinkedHashSet<>();
// 获取componentScan注解的basePackages属性
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);
}
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
// 开始扫描
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
这里就是 ClassPathBeanDefinitionScanner 发挥作用的地方,用于扫描、注册指定包下的所有 Bean(创建 BeanDefinition 并注册到上下文)。这里传入的是可变参数是 Spring 对于多个扫描包情况的考虑。具体逻辑可以查看 ClassPathBeanDefinitionScanner 的 doScan 方法:
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
// 存储创建出的 BeanDefinitionHolder
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 依次扫描每个包中的相关注解,创建获取到所有的 BeanDefinition
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// 生成 Bean 的名称
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
// 包装成 BeanDefinitionHolder
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
// 创建代理
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注册到上下文工厂
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
扫描的核心是 findCandidateComponents 方法,这个方法就是寻找到 @Component 和 @Component 的衍生注解的类。
关于 ClassPathBeanDefinitionScanner 的详解,可以查看文章:《深入解析Spring BeanDefinition:理解加载、解析与注册的全过程》