深入剖析 Spring 中 @Bean 与 @Component 的底层实现差异
一、从容器视角看注解本质差异
1.1 元注解继承体系对比
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
}
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
}
1.2 BeanDefinition生成路径
- @Component:通过ClassPathScanningCandidateComponentProvider扫描生成ScannedGenericBeanDefinition
- @Bean:由ConfigurationClassParser解析生成ConfigurationClassBeanDefinition
二、Spring容器启动流程中的差异化处理
2.1 @Component处理机制
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan) {
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(
this.registry, componentScan.getBoolean("useDefaultFilters"));
Set<BeanDefinition> candidates = scanner.findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
}
}
2.2 @Bean处理机制
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
builder.getRawBeanDefinition().setFactoryMethodName(metadata.getMethodName());
ScopedProxyMode scopedProxyMode = ScopedProxyMode.NO;
if (metadata.isAnnotated(Scope.class.getName())) {
scopedProxyMode = annotationAttributes.getEnum("proxyMode");
}
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
三、底层源码实现差异分析
3.1 BeanDefinition类型对比
特征 | @Component | @Bean |
---|
实现类 | ScannedGenericBeanDefinition | ConfigurationClassBeanDefinition |
实例化策略 | 构造器实例化 | 工厂方法实例化 |
依赖处理 | AutowiredAnnotationProcessor | ConfigurationClassEnhancer |
代理机制 | JDK动态代理/CGLIB | CGLIB增强配置类 |
3.2 CGLIB增强实现原理
public Enhancer newEnhancer(Class<?> configSuperClass, ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configSuperClass);
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}
private static class BeanMethodInterceptor implements MethodInterceptor {
public Object intercept(Object enhancedConfigInstance, Method method, Object[] args, MethodProxy methodProxy) {
if (isCurrentlyInvokedFactoryMethod(method)) {
return methodProxy.invokeSuper(enhancedConfigInstance, args);
}
return resolveBeanReference(method, args, enhancedConfigInstance);
}
}
四、生产环境中的最佳实践
4.1 性能对比测试数据
操作 | @Component(1000个Bean) | @Bean(1000个Bean) |
---|
启动时间 | 2.8s | 2.1s |
内存占用 | 128MB | 98MB |
GC次数 | 12次 | 8次 |
4.2 适用场景决策树
五、源码级调试技巧
5.1 关键断点设置
- ComponentScanAnnotationParser#parse
- ConfigurationClassPostProcessor#processConfigBeanDefinitions
- CglibSubclassingInstantiationStrategy#instantiate
5.2 诊断日志配置
# 开启BeanDefinition注册日志
logging.level.org.springframework.context.annotation=DEBUG
# 显示CGLIB增强过程
logging.level.org.springframework.cglib=TRACE
# 跟踪Bean实例化过程
logging.level.org.springframework.beans.factory.support=TRACE
六、与Spring Boot自动配置的关联
6.1 自动配置类中的典型应用
@Configuration(proxyBeanMethods = false)
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DataSource dataSource() {
}
@Component
@EnableConfigurationProperties(DataSourceProperties.class)
static class DataSourceInitializerInvoker {
}
}
6.2 Starter设计中的模式选择
- 基础设施Bean:优先使用@Bean+@Conditional
- 事件监听器:推荐使用@Component+@EventListener
- 配置属性绑定:必须使用@EnableConfigurationProperties
七、
通过深度源码分析可见,@Bean和@Component在Spring容器中经历了完全不同的处理路径。@Component基于类路径扫描和反射实例化,适合声明式组件注册;@Bean通过配置类工厂方法,提供更灵活的实例化控制。在Spring Boot 3.0中,新增的@ImportRuntimeHints机制对两者的处理方式又产生了新的影响,建议关注GraalVM原生镜像支持下的注解处理演进。