@Configuration 与 @Bean 深度 - Full/Lite 模式与 CGLIB 代理原理
概述
@Configuration 与 @Bean 是 Spring 框架中基于 Java 的容器配置的核心注解。自 Spring 3.0 引入以来,它们逐渐取代了传统的 XML 配置方式,成为 Spring 应用配置的主流选择。理解这两个注解的底层原理,对于深入掌握 Spring IoC 容器至关重要。
本文将从源码层面深入剖析 @Configuration 的 Full/Lite 模式差异、CGLIB 代理原理、@Bean 的处理流程,以及 ConfigurationClassPostProcessor 的核心工作机制。
1. @Configuration 注解的 Full 模式和 Lite 模式
1.1 注解定义
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(annotation = Component.class)
String value() default "";
boolean proxyBeanMethods() default true;
}从 Spring 5.2 开始,@Configuration 增加了 proxyBeanMethods 属性,默认值为 true。这个属性直接决定了配置类是运行在 Full 模式 还是 Lite 模式。
1.2 Full 模式
当 proxyBeanMethods = true(默认值)时,配置类处于 Full 模式。Spring 会通过 CGLIB 为该配置类创建一个代理对象,拦截所有 @Bean 方法的调用,确保单例 Bean 的 Scope 语义正确。
@Configuration
public class AppConfig {
@Bean
public Foo foo() {
return new Foo(bar()); // 这里调用 bar() 会被 CGLIB 拦截
}
@Bean
public Bar bar() {
return new Bar();
}
}在 Full 模式下,foo() 方法内部调用 bar() 时,Spring 会拦截该方法调用,从容器中返回已有的单例 Bean,而不是创建一个新的 Bar 实例。这保证了 单例 Bean 的复用。
1.3 Lite 模式
当 proxyBeanMethods = false,或者类上标注的是 @Component / @Import 而非 @Configuration 时,配置类处于 Lite 模式。Lite 模式下 不会创建 CGLIB 代理,每个 @Bean 方法调用都是直接的 Java 调用。
@Configuration(proxyBeanMethods = false)
public class LiteConfig {
@Bean
public Foo foo() {
return new Foo(bar()); // 这里 bar() 是普通方法调用,每次都会 new 一个 Bar
}
@Bean
public Bar bar() {
return new Bar();
}
}注意:在 Lite 模式下,foo() 内部调用的 bar() 会每次创建新的实例,不会被 Spring 容器拦截。这意味着如果 foo() 和 bar() 都是单例 Bean,foo 中持有的 bar 对象 不是 Spring 容器托管的那个单例实例。
1.4 Full 与 Lite 的核心区别
| 特性 | Full 模式 | Lite 模式 |
|---|---|---|
proxyBeanMethods | true(默认) | false |
| CGLIB 代理 | 是 | 否 |
| 单例语义保障 | 拦截 @Bean 间调用,返回容器实例 | 不拦截,每次调用创建新对象 |
| 启动性能 | 较慢(需生成 CGLIB 代理) | 较快 |
| 适用场景 | 配置类内部 @Bean 方法互相调用 | 每个 @Bean 方法独立,无相互调用 |
2. CGLIB 代理原理
2.1 为什么需要 CGLIB 代理
在 Full 模式下,当一个 @Bean 方法调用另一个 @Bean 方法时,Spring 需要确保返回的是容器中的单例实例,而不是新创建的对象。由于配置类是一个普通的 Java 类,方法间的直接调用无法被 Spring 容器感知,因此需要 通过代理拦截这些方法调用。
CGLIB(Code Generation Library)是一个强大的、高性能的代码生成库,它可以在运行时动态生成类的子类。Spring 使用 CGLIB 创建配置类的子类代理,覆盖所有 @Bean 方法。
2.2 代理增强的核心逻辑
Spring 对 @Configuration 类的增强实现在 ConfigurationClassEnhancer 类中。其核心逻辑如下:
class ConfigurationClassEnhancer {
// 使用 CGLIB 创建配置类的代理
public Class<?> enhance(Class<?> configClass, ClassLoader classLoader) {
// 如果已经实现了 EnhancedConfiguration 接口,说明已经被增强过
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
return configClass;
}
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configClass);
enhancer.setInterfaces(new Class<?>[]{EnhancedConfiguration.class});
enhancer.setUseFactory(true);
enhancer.setCallbackFilter(new BeanMethodCallbackFilter());
enhancer.setCallbacks(new Callback[]{
new BeanMethodInterceptor(), // 拦截 @Bean 方法
new BeanFactoryAwareMethodInterceptor(), // 设置 BeanFactory
NoOp.INSTANCE // 其他方法不做处理
});
return enhancer.createClass();
}
}关键点:
EnhancedConfiguration接口:标记接口,继承自BeanFactoryAware,让代理类持有BeanFactory引用。BeanMethodInterceptor:核心拦截器,负责拦截@Bean方法的调用。BeanFactoryAwareMethodInterceptor:在代理实例创建时注入BeanFactory。
2.3 BeanMethodInterceptor 拦截逻辑
private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 获取配置类的 BeanFactory
ConfigurableBeanFactory beanFactory = getBeanFactory(obj);
// 获取 @Bean 方法的信息
MethodMetadata methodMetadata = resolveMethodMetadata(method);
// 核心逻辑:尝试从容器中获取 Bean
String beanName = methodMetadata.getBeanName();
// 检查是否是 ScopedProxy 等特殊情况
if (isScopedBean(methodMetadata)) {
// 处理 Scope 代理
return createScopedProxy(obj, methodMetadata, args, beanFactory);
}
// 从容器中获取 Bean 实例(单例或 Scope 内的复用)
if (factoryContainsBean(beanFactory, beanName)) {
// 检查是否有依赖其他 Bean 的方法调用
Object beanInstance = beanFactory.getBean(beanName, method.getReturnType());
// 如果当前方法调用是容器外部发起的(非内部 @Bean 调用),直接返回
if (isCurrentlyInvokedBean(beanName)) {
return proxy.invokeSuper(obj, args);
}
return beanInstance;
}
// 首次调用:执行真实的方法体
return proxy.invokeSuper(obj, args);
}
}上述代码的逻辑可以简化为:
- 当代理对象上的
@Bean方法被调用时,拦截器会检查该方法对应的 Bean 是否已经在容器中。 - 如果 Bean 已在容器中,返回容器中的实例(不执行方法体)。
- 如果 Bean 不在容器中,调用代理父类(即原始配置类)的真实方法执行,并将结果注册到容器。
2.4 方法调用流程图
外部调用 config.foo()
│
▼
CGLIB 代理拦截 foo() 方法
│
├─ 检查 BeanFactory 中是否已有名为 "foo" 的 Bean
│ │
│ ├─ 已有 → 直接返回容器中的 Bean 实例
│ │
│ └─ 没有 → 执行代理父类的真实 foo() 方法
│ │
│ ▼
│ foo() 内部调用 bar()
│ │
│ ▼
│ CGLIB 再次拦截 bar() 调用
│ │
│ ├─ 已有 → 返回容器中的 bar 实例 ✅(单例保障)
│ │
│ └─ 没有 → 执行真实 bar() 方法,注册到容器
│
▼
返回完整的 Foo 对象3. @Bean 注解的完整处理流程
3.1 @Bean 注解定义
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
String[] value() default {};
@AliasFor("value")
String[] name() default {};
Autowire autowire() default Autowire.NO;
String initMethod() default "";
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
boolean autowireCandidate() default true;
}3.2 处理流程概览
@Bean 方法的处理发生在 Spring 容器的 配置类解析阶段,整体流程如下:
ConfigurationClassPostProcessor.processConfigBeanDefinitions()
│
▼
解析配置类上的 @Bean 方法
│
▼
构建 BeanMethod 元数据
│
▼
创建 BeanDefinition(通过 ConfigurationClassBeanDefinitionReader)
│
▼
注册 BeanDefinition 到 BeanFactory
│
▼
BeanFactory 在后续阶段实例化 Bean3.3 BeanDefinition 的构建
当 ConfigurationClassBeanDefinitionReader 处理 @Bean 方法时,会构建一个 ConfigurationClassBeanDefinition:
class ConfigurationClassBeanDefinitionReader {
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
// 创建 BeanDefinition
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition();
beanDef.setBeanClassName(configClass.getBeanClassName());
beanDef.setFactoryMethodName(metadata.getMethodName());
beanDef.setFactoryBeanName(configClass.getBeanName());
// 设置 Scope
String scope = determineScope(metadata);
beanDef.setScope(scope);
// 设置 Bean 名称
String[] beanNames = determineBeanNames(metadata);
for (String beanName : beanNames) {
// 注册
this.registry.registerBeanDefinition(beanName, beanDef);
}
// 处理自动装配模式
Autowire autowire = metadata.getAnnotationAttributes(Bean.class.getName())
.getEnum("autowire");
beanDef.setAutowireMode(autowire.value());
// 处理 initMethod / destroyMethod
String initMethod = metadata.getAnnotationAttributes(Bean.class.getName())
.getString("initMethod");
if (StringUtils.hasText(initMethod)) {
beanDef.setInitMethodName(initMethod);
}
// destroyMethod 默认值为 AbstractBeanDefinition.INFER_METHOD
// 会触发对 close/shutdown 等方法的自动推断
String destroyMethod = metadata.getAnnotationAttributes(Bean.class.getName())
.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethod);
// 处理条件注解(@Conditional)
if (configClass.getMetadata().isAnnotated(Conditional.class.getName())) {
beanDef.setAttribute(ConditionEvaluator.SKIP_ATTR, Boolean.TRUE);
}
}
}3.4 Bean 实例化阶段
@Bean 方法的实际调用发生在 Bean 实例化阶段。当 BeanFactory 创建 Bean 时,会通过 ConfigurationClassEnhancer 生成的代理调用配置类上的 @Bean 方法。
以下是 SimpleInstantiationStrategy 中处理工厂方法调用的逻辑:
class SimpleInstantiationStrategy implements InstantiationStrategy {
@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
// 如果 BeanDefinition 通过工厂方法创建
if (bd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(bd, beanName, owner);
}
// ...
}
private Object instantiateUsingFactoryMethod(RootBeanDefinition bd,
String beanName, BeanFactory owner) {
// 获取工厂 Bean(即配置类实例)
Object factoryBean = bd.getFactoryBeanName() != null ?
owner.getBean(bd.getFactoryBeanName()) : null;
// 获取工厂方法(@Bean 方法)
Method factoryMethod = bd.getResolvedFactoryMethod();
// 调用工厂方法创建 Bean 实例
// 注意:这里的 factoryBean 是 CGLIB 代理对象
// 因此对 @Bean 方法的调用会被拦截
Object result = ReflectionUtils.invokeMethod(factoryMethod, factoryBean);
return result;
}
}4. ConfigurationClassPostProcessor.processConfigBeanDefinitions() 源码精读
ConfigurationClassPostProcessor 是 Spring 框架中一个极其重要的 BeanFactoryPostProcessor。它实现了 BeanDefinitionRegistryPostProcessor 接口,在 Spring 容器启动的早期阶段被调用,负责解析所有 @Configuration、@Import、@ComponentScan 等注解,并将它们定义的 Bean 注册到容器中。
4.1 整体流程
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, EnvironmentAware {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException("...");
}
this.registriesPostProcessed.add(registryId);
// 核心入口:处理配置类 BeanDefinition
processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// ============= 阶段一:收集候选配置类 =============
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
// 已经处理过,跳过
continue;
}
// 检查是否为配置类(Full 或 Lite)
if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
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);
});
// ============= 阶段三:创建解析器并解析配置类 =============
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory,
this.problemReporter,
this.environment,
this.resourceLoader,
this.componentScanBeanNameGenerator,
registry
);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
// 在第一次解析前已经注册的 BeanDefinition 数量
int initialBeanDefinitionCount = registry.getBeanDefinitionCount();
boolean alreadyParsed = false;
do {
// === 核心解析:parse() ===
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = parser.getConfigurationClasses();
configClasses.removeIf(configClass ->
this.metadataReaderFactory.getMetadataReader(configClass.getMetadata().getClassName()) == null);
if (configClasses.isEmpty()) {
alreadyParsed = true;
}
if (!alreadyParsed) {
// ============= 阶段四:读取 BeanDefinition =============
ConfigurationClassBeanDefinitionReader reader = new ConfigurationClassBeanDefinitionReader(
registry,
this.sourceExtractor,
this.resourceLoader,
this.environment,
this.resourceLoader,
this.componentScanBeanNameGenerator
);
reader.loadBeanDefinitions(configClasses);
// ============= 阶段五:处理新产生的配置类 =============
alreadyParsed = true;
}
}
while (!alreadyParsed);
// ============= 阶段六:清除缓存的元数据 =============
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
}4.2 各阶段详解
阶段一:收集候选配置类
ConfigurationClassUtils.checkConfigurationClassCandidate() 方法判断一个 BeanDefinition 是否为配置类:
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
String className = beanDef.getBeanClassName();
if (className == null || beanDef.getFactoryMethodName() != null) {
return false;
}
AnnotationMetadata metadata;
if (beanDef instanceof AnnotatedBeanDefinition &&
className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
// 注解元数据已可用(如通过 @ComponentScan 扫描的类)
metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
} else {
// 需要读取 class 文件获取元数据
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
metadata = metadataReader.getAnnotationMetadata();
}
// 检查是否标注了 @Configuration(Full 模式)
if (metadata.isAnnotated(Configuration.class.getName())) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
// 检查是否标注了 @Component、@ComponentScan、@Import、@ImportResource,或拥有 @Bean 方法(Lite 模式)
else if (metadata.isAnnotated(Component.class.getName()) ||
metadata.hasAnnotatedMethods(Bean.class.getName()) ||
metadata.isAnnotated(Import.class.getName()) ||
metadata.isAnnotated(ImportResource.class.getName()) ||
metadata.isAnnotated(ComponentScan.class.getName())) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
} else {
return false;
}
// 解析 @Order 值
Integer order = metadata.getAnnotationAttributes(Order.class.getName());
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}判断逻辑总结:
- 类上标注了
@Configuration→ Full 模式 - 类上标注了
@Component/@ComponentScan/@Import/@ImportResource,或方法上标注了@Bean→ Lite 模式 - 其他情况 → 不是配置类
阶段二:排序
按照 @Order 注解的值对配置类进行排序,确保优先级高的配置类优先解析。这一点在多个配置类存在依赖关系时非常重要。
阶段三:核心解析(ConfigurationClassParser.parse())
ConfigurationClassParser 是真正的解析引擎,逐一处理每个配置类。它的解析逻辑是一个 递归过程:
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 (Exception ex) {
throw new BeanDefinitionStoreException("Failed to parse configuration class", ex);
}
}
// 处理延迟导入的配置类(由 ImportSelector 产生)
this.deferredImportSelectorHandler.process();
}// 递归解析配置类
protected void processConfigurationClass(ConfigurationClass configClass) {
// 条件注解评估,如果条件不满足则跳过
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
// 检查是否已经处理过
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
// 如果已存在且当前类是被导入的,直接返回
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
return;
}
// 否则用当前类覆盖
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 是解析的核心方法,按照优先级依次处理各种注解:
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
// ===== 1. 处理 @ComponentScan 注解 =====
Set<Path> scannedPackages = processComponentScan(configClass, sourceClass);
// 处理扫描出的配置类(递归)
processImports(configClass, sourceClass, scannedPackageClasses, true);
// ===== 2. 处理 @Import 注解 =====
processImports(configClass, sourceClass, getImports(sourceClass), true);
// ===== 3. 处理 @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) {
configClass.addImportedResource(resource, readerClass);
}
}
// ===== 4. 处理 @Bean 方法 =====
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// ===== 5. 处理父类/接口的默认方法 =====
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (!superclass.startsWith("java") && !superclass.equals(Object.class.getName())) {
return sourceClass.getSuperClass();
}
}
// 没有更多需要处理的父类
return null;
}解析器按以下优先级处理配置类上的注解:
@PropertySource:加载属性文件到 Environment@ComponentScan:执行包扫描,注册扫描到的 Bean@Import:处理导入的配置类、ImportSelector 和 ImportBeanDefinitionRegistrar@ImportResource:导入 XML 配置@Bean方法:收集配置类中所有标注了@Bean的方法
阶段四:读取 BeanDefinition
解析完成后,ConfigurationClassBeanDefinitionReader 负责将解析结果转换为 BeanDefinition 并注册到容器:
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
// 加载 @ImportResource 中定义的 Bean
loadBeanDefinitionsForImportedResources(configClass);
// 加载 @Bean 方法定义的 Bean
loadBeanDefinitionsForBeanMethod(configClass);
// 加载 ImportBeanDefinitionRegistrar 中注册的 Bean
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
}阶段五:处理新产生的配置类
在解析过程中,可能会产生新的配置类(例如 @ComponentScan 扫描到的类,或 ImportSelector 返回的新类)。需要循环处理,直到不再产生新的配置类。
阶段六:清除缓存
清理 CachingMetadataReaderFactory 中的缓存,释放内存。
4.3 方法调用时序图
BeanFactory 初始化
│
▼
ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()
│
▼
processConfigBeanDefinitions()
│
├── 1. 收集所有候选配置类 BeanDefinition
│
├── 2. 按 @Order 排序
│
├── 3. ConfigurationClassParser.parse()
│ │
│ ├── 处理 @ComponentScan → 扫描包 → 产生新 BeanDefinition
│ ├── 处理 @Import → 导入其他配置、ImportSelector 等
│ ├── 处理 @ImportResource → 导入 XML
│ └── 处理 @Bean → 收集 BeanMethod 元数据
│
├── 4. ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()
│ │
│ ├── 为每个 @Bean 方法创建 BeanDefinition
│ ├── 注册 ImportedResource 中的 BeanDefinition
│ └── 执行 ImportBeanDefinitionRegistrar 注册 Bean
│
├── 5. 循环检查是否产生新配置类 → 有则回到步骤 3
│
└── 6. 清理元数据缓存5. @Import 注解的处理机制
5.1 @Import 注解
@Import 注解允许在一个配置类中导入其他配置类,它是 Spring 组合配置的核心机制:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
Class<?>[] value();
}@Import 支持三种类型的导入目标:
- 普通配置类(
@Configuration类) ImportSelector接口实现类ImportBeanDefinitionRegistrar接口实现类
5.2 处理流程:processImports()
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
} else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignableTo(ImportSelector.class)) {
// ===== 处理 ImportSelector =====
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(
candidateClass, ImportSelector.class, this.environment,
this.resourceLoader, this.registry);
// 如果是 DeferredImportSelector,延迟处理
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(
configClass, (DeferredImportSelector) selector);
} else {
// 立即执行 selectImports
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importClasses = asSourceClasses(importClassNames);
// 递归处理 ImportSelector 返回的类
processImports(configClass, currentSourceClass, importClasses, false);
}
} else if (candidate.isAssignableTo(ImportBeanDefinitionRegistrar.class)) {
// ===== 处理 ImportBeanDefinitionRegistrar =====
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(
candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
} else {
// ===== 处理普通配置类 =====
// 作为导入的配置类处理,递归解析
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
} catch (Exception ex) {
// 异常处理
} finally {
this.importStack.pop();
}
}
}5.3 ImportSelector 与 DeferredImportSelector
// 普通 ImportSelector:立即执行
public interface ImportSelector {
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
// 延迟 ImportSelector:在所有配置类解析完成后再执行
public interface DeferredImportSelector extends ImportSelector {
@Nullable
default Class<? extends Group> getImportGroup() {
return null;
}
}普通 ImportSelector 在 processImports() 中立即执行,返回的类名会被递归解析。
DeferredImportSelector 的处理被推迟到所有常规配置类解析完成之后:
// DeferredImportSelector 的延迟处理
private class DeferredImportSelectorHandler {
private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
if (this.deferredImportSelectors == null) {
// 已经在处理延迟导入阶段,立即执行
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
handler.register(holder);
handler.processGroupImports();
} else {
// 还在常规解析阶段,暂存
this.deferredImportSelectors.add(holder);
}
}
public void process() {
if (this.deferredImportSelectors != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
// 先按 Group 分组注册
this.deferredImportSelectors.forEach(handler::register);
// 再处理各组导入
handler.processGroupImports();
this.deferredImportSelectors = null;
}
}
}5.4 ImportBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar 提供了最灵活的方式,可以直接手动注册 BeanDefinition:
public interface ImportBeanDefinitionRegistrar {
void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry);
}使用示例:
public class MyImportRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
// 手动创建和注册 BeanDefinition
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(MyServiceImpl.class)
.addPropertyValue("name", "example");
registry.registerBeanDefinition("myService", builder.getBeanDefinition());
}
}
@Configuration
@Import(MyImportRegistrar.class)
public class AppConfig {
}6. @ComponentScan 的扫描和注册流程
6.1 注解定义
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
// 是否使用默认过滤器
boolean useDefaultFilters() default true;
// 包含过滤器
Filter[] includeFilters() default {};
// 排除过滤器
Filter[] excludeFilters() default {};
// 是否延迟初始化
boolean lazyInit() default false;
}6.2 扫描处理流程
@ComponentScan 的处理在 ConfigurationClassParser.doProcessConfigurationClass() 中完成:
private Set<BeanDefinitionHolder> processComponentScan(
ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
// 获取 @ComponentScan 注解属性
AnnotationAttributes componentScan = AnnotationConfigUtils.attributesFor(
sourceClass.getMetadata(), ComponentScan.class);
if (componentScan == null) {
// 尝试获取 @ComponentScans(Java 8 多注解支持)
AnnotationAttributes[] componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (componentScans == null) {
return Collections.emptySet();
}
// 递归处理每个 @ComponentScan
for (AnnotationAttributes cs : componentScans) {
// ... 同上
}
}
// 创建类路径扫描器
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(
this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment,
this.resourceLoader);
// 设置 BeanNameGenerator
scanner.setBeanNameGenerator(this.componentScanBeanNameGenerator);
// 应用 includeFilters 和 excludeFilters
for (Filter filter : componentScan.getClassArray("includeFilters")) {
// 根据 filter.type(ANNOTATION、ASSIGNABLE_TYPE、ASPECTJ、REGEX、CUSTOM)创建 TypeFilter
scanner.addIncludeFilter(createTypeFilter(filter));
}
for (Filter filter : componentScan.getClassArray("excludeFilters")) {
scanner.addExcludeFilter(createTypeFilter(filter));
}
// 解析扫描包路径
Set<String> basePackages = new LinkedHashSet<>();
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
String[] tokenized = StringUtils.tokenizeToStringArray(pkg, ",");
Collections.addAll(basePackages, tokenized);
}
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
if (basePackages.isEmpty()) {
// 默认扫描配置类所在的包
basePackages.add(ClassUtils.getPackageName(sourceClass.getMetadata().getClassName()));
}
// 执行扫描
return scanner.doScan(StringUtils.toStringArray(basePackages));
}6.3 ClassPathBeanDefinitionScanner.doScan()
public class ClassPathBeanDefinitionScanner extends AbstractBeanDefinitionScanner {
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 在指定包路径下查找候选组件
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// 解析 Scope 注解
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) {
// 处理 @Primary、@Lazy、@DependsOn 等常用注解
AnnotationConfigUtils.processCommonDefinitionAnnotations(
(AnnotatedBeanDefinition) candidate);
}
// 检查 BeanDefinition 是否已存在
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder holder = new BeanDefinitionHolder(candidate, beanName);
// 注册到容器
registerBeanDefinition(holder, this.registry);
beanDefinitions.add(holder);
}
}
}
return beanDefinitions;
}
}6.4 findCandidateComponents 的扫描过程
底层使用 ASM 元数据读取器 扫描 class 文件,无需加载类即可获取注解信息:
public class ClassPathScanningCandidateComponentProvider {
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
// 将包名转换为资源路径
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(basePackage) + "/**/*.class";
// 查找所有 class 文件资源
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
Set<BeanDefinition> candidates = new LinkedHashSet<>();
for (Resource resource : resources) {
if (resource.isReadable()) {
try {
// 使用 ASM 读取元数据
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// 应用类型过滤器判断是否为候选组件
if (isCandidateComponent(metadataReader)) {
// 创建 ScannedGenericBeanDefinition
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
// 确认是否为具体的、非接口的候选类
if (isCandidateComponent(sbd)) {
candidates.add(sbd);
}
}
} catch (Exception ex) {
// 异常处理
}
}
}
return candidates;
}
}7. Full 模式 vs Lite 模式的 @Bean 方法调用拦截
7.1 对比示例
Full 模式:方法调用被拦截
@Configuration
public class FullConfig {
@Bean
public User user() {
return new User("张三");
}
@Bean
public UserService userService() {
// 此处的 user() 调用会被 CGLIB 拦截
// 返回的是容器中的单例 User 实例
return new UserService(user());
}
}CGLIB 生成的代理类等价逻辑(简化):
public class FullConfig$$EnhancerByCGLIB extends FullConfig implements EnhancedConfiguration {
private BeanFactory beanFactory;
@Override
public User user() {
// 检查容器中是否有 "user" 这个 Bean
if (beanFactory.containsBean("user")) {
return beanFactory.getBean("user", User.class);
}
// 首次调用:执行父类真实方法,并注册到容器
return super.user();
}
@Override
public UserService userService() {
if (beanFactory.containsBean("userService")) {
return beanFactory.getBean("userService", UserService.class);
}
// 调用 user() 时再次触发拦截器
return super.userService();
}
}Lite 模式:方法调用不被拦截
@Configuration(proxyBeanMethods = false)
public class LiteConfig {
@Bean
public User user() {
return new User("张三");
}
@Bean
public UserService userService() {
// 此处的 user() 是普通 Java 方法调用
// 每次都会创建新的 User 对象
return new UserService(user());
}
}
// 测试验证
UserService userService1 = context.getBean(UserService.class);
UserService userService2 = context.getBean(UserService.class);
// userService1 中的 user 对象 != userService2 中的 user 对象(不同实例)
// 而 Full 模式下两个是同一个容器实例7.2 为什么 Lite 模式下不会拦截?
Lite 模式下,配置类不会被 CGLIB 增强。Spring 在实例化时直接使用原始类,通过反射调用 @Bean 方法:
// Lite 模式:没有代理对象
// context.getBean("userService") 时直接调用原始对象的 userService() 方法
Object configInstance = configClass.getDeclaredConstructor().newInstance();
Method method = configInstance.getClass().getMethod("userService");
Object result = method.invoke(configInstance); // 直接调用,无拦截在上述调用中,userService() 内部的 user() 调用就是普通的 Java 方法调用,不受 Spring 容器管控。
7.3 两种模式的选择指导
// 场景 1:@Bean 方法之间有相互调用 → 必须使用 Full 模式
@Configuration
public class ServiceConfig {
@Bean
public A a() {
return new A();
}
@Bean
public B b() {
// 需要 A 的单例实例,内部方法调用依赖拦截
return new B(a());
}
}
// 场景 2:@Bean 方法完全独立,无相互调用 → 可以使用 Lite 模式提升性能
@Configuration(proxyBeanMethods = false)
public class IndependentConfig {
@Bean
public A a() { return new A(); }
@Bean
public B b() { return new B(); } // 不依赖 a()
}
// 场景 3:使用 @Component 而不是 @Configuration(自动 Lite 模式)
@Component
public class ComponentWithBean {
@Bean
public A a() { return new A(); }
@Bean
public B b() { return new B(a()); } // 注意:这里的 a() 每次创建新实例!
}
// 场景 4:通过方法参数注入替代内部调用(Lite 模式也可以保持单例)
@Configuration(proxyBeanMethods = false)
public class ParamInjectionConfig {
@Bean
public A a() { return new A(); }
@Bean
public B b(A a) { // 通过参数注入,避免内部方法调用
return new B(a); // 这里的 a 是容器中的单例
}
}7.4 Spring 框架文档的推荐做法
Spring 官方文档明确推荐:如果一个配置类中的 @Bean 方法不依赖于其他 @Bean 方法,应该使用 Lite 模式(proxyBeanMethods = false),以获得更好的启动性能。
每次应用启动时,CGLIB 的类生成和代理创建都会消耗额外的时间和内存。对于大型微服务架构,如果大量配置类可以使用 Lite 模式,这种优化将非常可观。
总结
@Configuration 与 @Bean 是 Spring 基于 Java 配置的基石。深入理解其底层原理,可以帮助开发者:
- 正确使用配置类:理解 Full/Lite 模式差异,避免因错误使用导致 Bean 状态不一致
- 应用启动性能优化:在合适的场景使用
proxyBeanMethods = false提升启动速度 - 深入理解 IoC 容器:掌握
ConfigurationClassPostProcessor的工作流程,完整理解 Spring 容器从配置到注册的全部环节 - 调试能力提升:当遇到 CGLIB 代理相关的诡异问题时(例如
BeanCreationException中看到EnhancerByCGLIB类名),能够快速定位问题根因
核心要点回顾
| 知识点 | 要点 |
|---|---|
| Full 模式 | proxyBeanMethods = true,CGLIB 代理,保障 @Bean 间方法调用的单例语义 |
| Lite 模式 | proxyBeanMethods = false,无代理,方法调用不拦截,性能更优 |
| CGLIB 原理 | 通过 Enhancer 生成子类,BeanMethodInterceptor 拦截 @Bean 方法调用,从容器返回 Bean |
| 处理入口 | ConfigurationClassPostProcessor.processConfigBeanDefinitions() |
| 解析流程 | 收集 → 排序 → 解析(@ComponentScan → @Import → @Bean)→ 注册 BeanDefinition |
| @Import | 支持导入配置类、ImportSelector(含 DeferredImportSelector)、ImportBeanDefinitionRegistrar |
| @ComponentScan | 使用 ASM 元数据读取器扫描 class 文件,无需加载类即可获取注解信息 |
参考资料:Spring Framework 6.x 源码 (
spring-context模块)
org.springframework.context.annotation.ConfigurationClassPostProcessororg.springframework.context.annotation.ConfigurationClassParserorg.springframework.context.annotation.ConfigurationClassBeanDefinitionReaderorg.springframework.context.annotation.ConfigurationClassEnhancerorg.springframework.context.annotation.ClassPathBeanDefinitionScanner