毫无疑问,spring的核心是bean,一个简单的获取bean的过程如下:
ClassPathResource resource = new ClassPathResource("services.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(resource);
SayService sayService = (SayService)factory.getBean("sayService");
services.xml就是spring的[配置文件,sayService就是配置文件里面配置的bean.
spring生成bean并不是一气呵成,因为bean之间是有相互依赖关系的.只能先把xml都解析完后才能生成最终需要调用的bean.BeanDefinition就是配置文件与最终生成bean之间的桥梁.本文主要分析spring如何解析bean的配置文件到生成包含bean元信息对象BeanDefinition的过程.下面是这个过程的一个简单的时序图:
spring解析xml生成BeanDefinition对象的过程主要涉及到XmlBeanDefinitionReader,DocumentLoader,DefaultBeanDefinitionDocumentReader,BeanDefinitionParserDelegate,DefaultListableBeanFactory这几个类,几个类的职责分别是:
1. XmlBeanDefinitionReader根据xml的文件路径生成InputStream对象,进而得到InputStream的xml的包装类InputSource对象.
2. DocumentLoader解析InputSource得到Document对象.
3. DefaultBeanDefinitionDocumentReader类委托BeanDefinitionParserDelegate类解析Document对象生成BeanDefinition对象,BeanDefinition对象中包含xml中配置的bean的元信息.
4.生成的BeanDefinition对象最终都会注册到DefaultListableBeanFactory,供后续生成bean对象使用.
spring的配置文件中bean的配置元素id和name的关系
一个bean可以同时配置id,name.name里面 可以配置多个名称,多个名称之间可以重复, 名称之间用逗号隔开,如果没有配置id,默认名称的第一作为id.并且整个容器不同bean之间不能有相同的id和name,spring在解析xml配置文件时会有校验,校验代码如下:
protected void checkNameUniqueness(String beanName, List aliases, Element beanElement) {
String foundName = null;
if (StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) {
foundName = beanName;
}
if (foundName == null) {
foundName = (String) CollectionUtils.findFirstMatch(this.usedNames, aliases);
}
if (foundName != null) {
error("Bean name '" + foundName + "' is already used in this file", beanElement);
}
this.usedNames.add(beanName);
this.usedNames.addAll(aliases);
}
在调用getBean(String name)方法时,会将name转换为id,具体代码如下:
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing.
String resolvedName = null;
do {
resolvedName = (String) this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
}