day10 - Spring 之配置类源码解析
摘要:
本文深入解析Spring配置类源码,重点分析BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor的区别,以及checkConfigurationClassCandidate()方法的实现逻辑。前者是父接口,用于修改现有Bean定义;后者继承前者并新增方法,可直接操作Bean定义注册中心。checkConfigurationClassCandidate()方法通过多种方式获取注解元数据,判断候选类是否为配置类,并处理代理Bean方法等特
**前言:**主分享对spring源码配置类源码的理解。
流程图如下:

1、BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor区别
1)接口集成关系
BeanFactoryPostProcessor是Spring提供的后置处理器,定义如下
c
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
postProcessBeanFactory 允许在我们所有Bean定义,(BeanDefinition)已加载完成后、Bean实例化之前,对ConfigurableListableBeanFactory 进行定制化操作。比如:修改Bean定义的属性值、添加PropertyEditor等。
BeanDefinitionRegistryPostProcessor 它是 BeanFactoryPostProcessor 的子接口
c
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
允许我们直接操作Bean的定义注册中心,即可以项向容器中注册新的Bean的定义,移除已有的Bean定义,或对注册表进行其他的修改。
| 对比维度 | BeanDefinitionRegistryPostProcessor | BeanFactoryPostProcessor |
|---|---|---|
| 集成关系 | 继承 BeanFactoryPostProcessor | 父接口 |
| 新增方法 | postProcessBeanDefinitionRegistry() | 无,仅有 postProcessBeanFactory() |
| 操作对象 | BeanDefinitionRegistry 可增删改Bean的定义 (Bean的新注册) | ConfigurableListableBeanFactory 修改现有的Bean |
| 调用时机 | 在 postProcessBeanFactory 之前执行 | 在所有 BeanDefinitionRegistryPostProcessor 的 方法 postProcessBeanDefinitionRegistry 完毕后执行 |
| 典型实现 | ConfigurationClassPostProcessor(处理 @Configuration、@ComponentScan 等)CachingMetadataReaderFactoryPostProcessor 等 | PropertySourcesPlaceholderConfigurer(处理占位符)CustomScopeConfigurer(注册自定义作用域)EventListenerMethodProcessor 等 |
2、checkConfigurationClassCandidate()方法讲解
全路径:org.springframework.context.annotation.ConfigurationClassUtils#checkConfigurationClassCandidate
c
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
// 1)获取类名,如果类名为空 说明bean的定义无法确定类
// 检查工厂方法名, getFactoryMethodName() 不为null,说明这个bean是通过@Bean 方法定义的
// 对于通过 @Bean 方法创建的 Bean,其定义本身不携带配置类注解信息(配置类注解在包含 @Bean 方法的类上),因此不应作为配置类候选处理,直接返回
// false。
String className = beanDef.getBeanClassName();
if (className == null || beanDef.getFactoryMethodName() != null) {
return false;
}
// 2)获取注解元数据 AnnotationMetadata
AnnotationMetadata metadata;
// 2.1)AnnotatedBeanDefinition 类名匹配 AnnotatedBeanDefinition 内部已经持有 AnnotationMetadata ,直接复用可以提高性能。
// 检查类名一致,确保元数据对应当前类
if (beanDef instanceof AnnotatedBeanDefinition &&
className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
// Can reuse the pre-parsed metadata from the given BeanDefinition...
metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
}
// 2.2)hasBeanClass() 为true表示 Bean的Class已经被加载到JVM中。
else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
// Check already loaded Class if present...
// since we possibly can't even load the class file for this Class.
Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
// 如果该类实现了特定的接口比如:BeanFactoryPostProcessor、BeanPostProcessor... 直接返回false。
// 因为这些接口实现的视线类需要在配置类处理之前就实例化,如果它们本身又是配置类,可能会导致循环依赖或过早初始化的问题。Spring明确不允许这类的Bean作为配置类
if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
BeanPostProcessor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
EventListenerFactory.class.isAssignableFrom(beanClass)) {
return false;
}
metadata = AnnotationMetadata.introspect(beanClass);
}
// 其他情况:通过metadataReaderFactory 读取字节码,对于既不是AnnotatedBeanDefinition又未加载类的BeanDefinition
// 使用 metadataReaderFactory 读取 .class文件(ASM方式),获取元数据而不加载类
else {
try {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
metadata = metadataReader.getAnnotationMetadata();
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not find class file for introspecting configuration annotations: " +
className, ex);
}
return false;
}
}
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}
// It's a full or lite configuration candidate... Let's determine the order value, if any.
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}
检查 @Configuration 注解并标记FULL/LITE
c
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}
- FULL 模式:如果 @Configuration 存在且 proxyBeanMethods 不为 false(即 true 或未显式设置,默认为 true),则标记为 FULL。FULL 模式下,Spring 会为配置类创建 CGLIB 代理,确保 @Bean 方法之间调用遵循单例语义(每次调用返回同一个 Bean)。
- LITE 模式:有两种情况进入 LITE:
a.存在 @Configuration 但 proxyBeanMethods = false。
b.不存在 @Configuration,但满足 isConfigurationCandidate(metadata) 条件。
isConfigurationCandidate(metadata) 实现检查
1)类上是否标注了 @Component 、@ComponentScan、@Import、@ImportResource中的任意一个。
2)或者类中是否存在至少一个带有@Bean注解的方法,满足任一条即视为LITE配置类(即普通的Spring组件,但包含@Bean定义)。LITE模式下不会创建CGLIB代理,@Bean方法之间的调用是普通的JAVA调用,不会拦截。
3)如果以上都不满足,返回false,表示该Bean定义不需要作为配置类处理。
补充:FULL和LITE的区别
FULL: 对应 @Configuration(proxyBeanMethods=true),Spring 会创建 CGLIB 代理,保证@Bean方法内部调用另一个@Bean方法时返回的是容器中的单例Bean,而不是新实例。通常用于集中定义Bean的配置类。
LITE:对应普通类 (可能带有@Bean方法或@Component等),不会创建代理,@Bean方法间调用是普通JAVA调用,可能会导致同一个Bean被多次实例化。通常用于简单配置或自动扫描的组件中内嵌的@Bean方法。
3、Spring框架中处理导入配置类的方法
registerBeanDefinitionForImportedConfigurationClass 方法用于为通过@Import注解导入的配置类注册Bean定义。
c
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
// 获取配置类元数据
AnnotationMetadata metadata = configClass.getMetadata();
// 创建bean的定义:基于元数据创建一个带注解的通用Bean定义对象
AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
// 解析作用域,比如:singleton、prototype 等
ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
configBeanDef.setScope(scopeMetadata.getScopeName());
// 生成bean的名称
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
// 处理常见注解 @Lazy、@DependsOn、@Role...将这些注解信息设置到bean定义中
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
// 创建作用域代理
// 1.检查作用域配置中是否设置了代理模式
// 2.如果配置了proxyMode = ScopedProxyMode.TARGET_CLASS,会创建一个作用域代理工厂Bean
// 3.这样可以在单例Bean安全的注入原型(prototype)或其他作用域的Bean
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 注册Bean定义
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
configClass.setBeanName(configBeanName);
if (logger.isTraceEnabled()) {
logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
}
}
4、Spring处理@ComponentScan核心方法
作用是解析配置类上的@ComponentScan注解,并根据注解扫描指定的包来注册Bean定义。
c
// 主要作用是解析@ComponentScan注解的所有属性,并配置扫描器来扫描制定的包
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
// 创建一个ClassPathBeanDefinitionScanner扫描器
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
// 获取用户自定义的Bean名称生成器(通过nameGenerator属性)
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
// 默认是AnnotationBeanNameGenerator
scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
BeanUtils.instantiateClass(generatorClass));
// 设置作用域、代理模式
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"));
// 处理包含 |排除过滤器
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addExcludeFilter(typeFilter);
}
}
// 设置懒加载,如果lazyInit = true ,则扫描到所有的Bean都为懒加载
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
// 确定要扫描的基础包路径
// basePackages:直接指定包名字符串(支持占位符和多个包)
// basePackageClasses:通过指定类来获取它们所在的包
// 默认值:如果都没指定,就使用声明 @ComponentScan 注解的类所在的包
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);
}
// 添加排除过滤器:添加一个排除过滤器,排除掉@ComponentScan 类本身,为了避免将配置类自己也扫描进去造成循环
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));
}
5、Spring框架中处理配置类的逻辑
c
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
Predicate<String> filter) throws IOException {
// 获取内部类
Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
if (!memberClasses.isEmpty()) {
List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
for (SourceClass memberClass : memberClasses) {
// 排除自身
// 检查内部类是否是配置类候选者(是否有 @Configuration、@Component、@Import 等注解)
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 {
processConfigurationClass(candidate.asConfigClass(configClass), filter);
}
finally {
this.importStack.pop();
}
}
}
}
}
核心作用;
1)支持在配置类中定义内部配置类
2)检测并防止循环导入
3)确保所有配置类(包括内部类)都被正确处理
比如;
c
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
return new DataSource();
}
// 内部配置类
@Configuration
public static class DatabaseConfig {
@Bean
public Connection connection() {
return new Connection();
}
}
}
这个方法会发现 DatabaseConfig 这个内部类也是配置类,然后递归地处理它,将其中的 @Bean 方法也注册到 Spring 容器中。
这段代码是 Spring 框架中处理配置类所实现的接口的逻辑。
c
// 用于递归处理配置类实现的所有接口,检查接口中是否有 @Bean 方法,并将其注册到配置类中。
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
for (SourceClass ifc : sourceClass.getInterfaces()) {
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
for (MethodMetadata methodMetadata : beanMethods) {
if (!methodMetadata.isAbstract()) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
}
processInterfaces(configClass, ifc);
}
}
实际应用场景:
示例 1:接口中有 default 的 @Bean 方法
c
@Configuration
public class AppConfig implements DatabaseConfig {
// 继承自接口的 default @Bean 方法也会被识别
}
public interface DatabaseConfig {
@Bean
default DataSource dataSource() {
return new HikariDataSource();
}
@Bean
default TransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
在这种情况下:
AppConfig 实现了 DatabaseConfig 接口
接口中的 dataSource() 和 transactionManager() 是 default 方法(非抽象)
Spring 会通过这个方法将它们识别为 Bean 定义
最终容器中会注册 DataSource 和 TransactionManager 两个 Bean
示例 2:接口继承层次
c
@Configuration
public class AppConfig implements ServiceConfig {
}
public interface ServiceConfig extends DaoConfig {
@Bean
default Service service() {
return new ServiceImpl();
}
}
public interface DaoConfig {
@Bean
default Dao dao() {
return new DaoImpl();
}
}
通过递归处理(第 422 行),Spring 会:
处理 ServiceConfig 接口,发现 service() 方法
递归处理 DaoConfig 接口,发现 dao() 方法
最终 AppConfig 会注册 service 和 dao 两个 Bean
核心接口和作用
✅ 支持接口中的默认 Bean 方法:识别并注册接口中的 default @Bean 方法
✅ 递归处理接口层次:处理接口继承关系,不遗漏任何层级的 Bean 定义
✅ Java 8+ 特性支持:充分利用 Java 8 的 default 方法特性,提供更灵活的配置方式
这种机制让 Spring 配置更加模块化,可以通过接口组合的方式复用配置!
有不足之处欢迎指出,一起学习。喜欢我的文章希望点个在看,或者点赞,持续更新中ing... ♥️