一、目的
spring中加载bean的一种方式,是用户主动调用BeanFactory#getBean(java.lang.String, java.lang.Class)方法。如下:
BeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
Person myPerson = xmlBeanFactory.getBean("myPerson", Person.class);
BeanFactory是一个接口,该getBean方法由AbstractBeanFactory实现。该getBean()方法的第一步就是,转换对应的beanName。其目的是为了,把用户传入的name,解析为bean实例对应真正的beanName。供后面直接从DefaultListableBeanFactory#beanDefinitionMap中读取beanName对应的BeanDefinition信息,进而实例化该bean实例。有两种场景需要转换用户传入的name:
- 用户传入的name以&开头
对于实现FactoryBean接口的类MyFactoryBean
xml配置形如public class MyFactoryBean implements FactoryBean<Person> { @Override public Person getObject() throws Exception { Person person = new Person(); person.setName("factoryBean"); return person; } @Override public Class<?> getObjectType() { return Person.class; } }
<bean id="myPerson" class="com.kaka.spring.pojo.MyFactoryBean" />
对于获取MyFactoryBean本身的场景,就需要去掉&前缀,来获取真实的beanName// 默认情况下,获取的不是MyFactoryBean本身,而是MyFactoryBean的getObject()方法返回的实例 Person myPerson = xmlBeanFactory.getBean("myPerson", Person.class); // 想要获取MyFactoryBean本身,需要加上一个&前缀 MyFactoryBean bean = xmlBeanFactory.getBean("&myPerson", MyFactoryBean.class);
- 如果用户传入的name是bean的别名,则需要从SimpleAliasRegistry#aliasMap中获取对应的真实beanName
二、相关类及方法
- org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean:加载bean的整体过程
- org.springframework.beans.factory.BeanFactoryUtils#transformedBeanName:去掉name中的&前缀
- org.springframework.core.SimpleAliasRegistry#canonicalName:获取别名对应的beanName
三、源码分析
- 加载bean的整体流程:AbstractBeanFactory#getBean
public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 就看这第一步,转化对应的beanName
final String beanName = transformedBeanName(name);
// 忽略后续步骤
...
}
- 去掉name中的&前缀:BeanFactoryUtils#transformedBeanName
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
String beanName = name;
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
return beanName;
}
- 从SimpleAliasRegistry#aliasMap中,获取别名对应的beanName:SimpleAliasRegistry#canonicalName
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
do {
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
综上处理,用户就获取到了指定bean的真实beanName;然后进行后面,实例化bean的步骤。