在 Spring 框架中,getBean 方法是获取 Bean 实例的核心入口。但你是否想过,当传入的 Bean 名称包含别名、特殊符号(比如 &)时,Spring 是如何准确找到目标 Bean 的?这背后的秘密就藏在 transformedBeanName 方法中。本文从源码层面解析 transformedBeanName 的作用,并带你走一遍 Bean 获取的全流程!
一、transformedBeanName 是做什么的?
一句话总结:transformedBeanName 的核心作用是对传入的 Bean 名称进行规范化处理,确保后续流程能正确找到目标 Bean。具体来说,它主要解决两类问题:
- 处理别名:将别名转换为真实的 Bean 名称。
- 处理工厂前缀:去掉
&符号(获取 FactoryBean 本身时需要用到)。
举个例子:
- 如果传入的 Bean 名称是
myBeanAlias(别名),transformedBeanName会将其转换为真实的 Bean 名称(如myBean)。 - 如果传入的 Bean 名称是
&myFactoryBean,transformedBeanName会去掉&,返回myFactoryBean,以便后续获取 FactoryBean 实例。
二、从源码看 transformedBeanName 的实现
Spring 源码中,transformedBeanName 方法位于 AbstractBeanFactory 类中。以下是关键代码片段:
protected String transformedBeanName(String name) {
// 1. 处理别名:将别名转换为真实名称
String beanName = canonicalName(name);
// 2. 处理工厂前缀:去掉开头的 "&"
return (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX) ?
beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()) : beanName;
}
步骤解析:
- 处理别名:通过
canonicalName方法,将别名转换为注册的真实 Bean 名称。 - 处理工厂前缀:如果 Bean 名称以
&开头(例如&myFactoryBean),则去掉&,返回真正的 Bean 名称(myFactoryBean)。
三、Bean 的获取流程全解析
理解了 transformedBeanName 的作用后,我们再来看 getBean 方法的整体流程。以 getBean(String name) 为例:
1. 调用 getBean 方法
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
2. 进入 doGetBean 方法
在 doGetBean 方法中,第一步就是调用 transformedBeanName:
protected <T> T doGetBean(String name, ...) {
// 关键步骤1:转换 Bean 名称
String beanName = transformedBeanName(name);
// 关键步骤2:尝试从缓存获取 Bean
Object sharedInstance = getSingleton(beanName);
// 缓存未命中,则创建 Bean
if (sharedInstance == null) {
// 创建 Bean 的流程...
}
return (T) beanInstance;
}
3. 流程总结
复制
1. 转换名称 → 2. 查缓存 → 3. 缓存命中则返回 → 4. 缓存未命中则创建 Bean
四、transformedBeanName 的实际场景
场景1:处理别名
假设定义了一个别名:
<bean id="myBean" class="com.example.MyBean"/>
<alias name="myBean" alias="myBeanAlias"/>
运行 HTML
调用 getBean("myBeanAlias") 时:
transformedBeanName会将myBeanAlias转换为myBean。- 后续流程直接根据
myBean查找 Bean。
场景2:获取 FactoryBean 本身
假设有一个 FactoryBean:
@Component("myFactoryBean")
public class MyFactoryBean implements FactoryBean<Object> { ... }
调用 getBean("&myFactoryBean") 时:
transformedBeanName会去掉&,得到myFactoryBean。- 后续流程会返回
MyFactoryBean的实例(而不是它生产的对象)。
五、为什么需要处理工厂前缀?
FactoryBean 是 Spring 中用于生产 Bean 的特殊接口。默认情况下,getBean("myFactoryBean") 返回的是 FactoryBean 生产的对象,而非 FactoryBean 本身。如果用户想获取 FactoryBean 实例,必须在名称前加 &。例如:
// 获取 FactoryBean 生产的对象
Object product = context.getBean("myFactoryBean");
// 获取 FactoryBean 本身
FactoryBean<?> factory = context.getBean("&myFactoryBean");
transformedBeanName 的作用就是去掉 &,让后续流程能正确找到 FactoryBean 的实例。
六、Bean 获取流程中的其他关键步骤
除了 transformedBeanName,doGetBean 方法还包含以下核心逻辑:
- 检查缓存:优先从单例缓存(
singletonObjects)中获取 Bean,避免重复创建。 - 处理原型作用域 Bean:如果 Bean 是
prototype,每次都会创建新实例。 - 解决依赖循环:通过三级缓存提前暴露半成品 Bean。
- 初始化 Bean:调用
@PostConstruct、InitializingBean等生命周期方法。
七、总结
-
transformedBeanName 的作用:规范化 Bean 名称,处理别名和工厂前缀。
-
核心流程:
getBean→transformedBeanName→ 查缓存 → 创建 Bean。 -
注意事项:
- 使用别名时,确保别名已正确注册。
- 获取 FactoryBean 实例时,名称前需加
&。