被@Bean标注的方法是怎么被注册为一个bean的
在 Spring 框架中,被@Bean标注的方法会通过以下流程被注册为容器中的 bean:
1. 配置类解析阶段
- ConfigurationClassPostProcessor:Spring 的
BeanFactoryPostProcessor会扫描所有带有@Configuration或@Component注解的类 - 方法解析:识别这些类中所有被
@Bean标注的方法,并提取元数据(如方法名、返回类型、作用域等)
2. BeanDefinition 注册阶段
- BeanDefinition:为每个
@Bean方法创建一个RootBeanDefinition或ConfigurationClassBeanDefinition - 注册到容器:这些
BeanDefinition会被注册到BeanFactory的beanDefinitionMap中,键为 bean 名称(默认是方法名)
3. 实例化与依赖注入阶段
- 延迟实例化:大多数 bean 是在首次被依赖时才会实例化(单例 bean 在容器启动时实例化)
- 方法调用:容器通过反射调用
@Bean方法,获取返回的对象实例 - 依赖处理:如果方法有参数,Spring 会自动解析并注入这些依赖
4. 配置类代理机制(仅针对@Configuration类)
- CGLIB 代理:
@Configuration类会被 CGLIB 增强,确保方法调用时返回容器中的单例 bean - 拦截逻辑:当代理对象调用
@Bean方法时,会先检查容器中是否已有该 bean,而非直接执行方法 - 核心机制总结
- 元数据解析:Spring 通过 ASM 技术解析类的字节码,提取
@Bean方法信息 - 生命周期管理:
@Bean方法返回的对象由 Spring 容器管理,包括初始化、依赖注入和销毁 - 代理增强:
@Configuration类的代理确保方法调用时返回容器中的单例 bean,而非创建新实例 - 条件注册:结合
@Conditional等注解,可以根据条件决定是否注册该 bean
在bean()里面加名字是为啥
默认情况下,bean 名称是方法名。通过name属性可以覆盖这一行为,使名称更具描述性或符合特定规范。
2. 解决名称冲突
当多个@Bean方法返回相同类型的 bean 时,必须通过名称区分它们。
@Configuration
public class DataSourceConfig {
@Bean(name = "primaryDataSource")
public DataSource mysqlDataSource() { ... }
@Bean(name = "secondaryDataSource")
public DataSource oracleDataSource() { ... }
}
此时,可通过名称注入特定的 bean:
@Autowired
@Qualifier("primaryDataSource") // 指定名称
private DataSource dataSource;
在 Spring 框架中,@Autowired结合@Qualifier注入的是方法返回的对象实例,而非配置类本身。这是因为 Spring 的依赖注入系统关注的是bean 实例,而非定义 bean 的方法或类。
ctrl+h 可以对源码进行查看