在loadBeanDefinitions中创建了XmlBeanDefinitionReader实例,然后在IoC容器中设置该实例,最后通过loadBeanDefinitions方法来完成Bean定义在IoC容器中的载入。接下来看下真正实现加载BeanDefinitions的loadBeanDefinitions(beanDefinitionReader)方法:[url=][/url]
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); //获得Bean配置文件的资源位置 if (configResources != null) { //读取AbstractBeanDefinitionReader中定位的资源 reader.loadBeanDefinitions(configResources); } //获取ClassPathXmlApplicationContext构造方法中setConfigLocations方法设置的资源 String[] configLocations = getConfigLocations(); if (configLocations != null) { //读取AbstractBeanDefinitionReader中定位的资源,最终还是以Resource的形式去加载资源。 reader.loadBeanDefinitions(configLocations); }}[url=][/url]
在AbstractBeanDefinitionReader的loadBeanDefinitions中开始进行BeanDefinitions的载入。
[url=][/url]
@Overridepublic int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; for (Resource resource : resources) { counter += loadBeanDefinitions(resource); } return counter;}[url=][/url]
以上代码中的loadBeanDefinitions在AbstractBeanDefinitionReader中并没有实现,它只是一个在BeanDefinitionReader中定义的接口方法,具体的实现在各个子类(如:XmlBeanDefinitionReader)中。
在XmlBeanDefinitionReader中实现的loadBeanDefinitions方法会得到一个XML文件的InputStream,然后会获得一个InputResource,调用doLoadBeanDefinitions(inputSource, encodedResource.getResource())返回。doLoadBeanDefinitions方法是去从XML文件中加载BeanDefinitions,具体的过程是在该方法调用了registerBeanDefinitions(doc, resource)。
[url=][/url]
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { //这里得到BeanDefinitionDocumentReader来对XML的BeanDefinition进行解析 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); //具体的解析过程在registerBeanDefinitions中完成 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore;}[url=][/url]
通过上面的代码可以知道具体的解析XML并转换为容器内部结构的过程是在BeanDefinitionDocumentReader中完成的,registerBeanDefinitions还对载入的Bean数量进行了统计。这里使用的documentReader是通过createBeanDefinitionDocumentReader()方法创建的默认的DefaultBeanDefinitionDocumentReader。而DefaultBeanDefinitionDocumentReader中定义了Spring的Bean规则。
[url=][/url]
@Overridepublic void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root);}[url=][/url]
在doRegisterBeanDefinitions中,由BeanDefinitionParserDelegate实现了解析过程。
View Code
通过一路跟进parseBeanDefinitions方法,可以找到以下代码:
View Code
在processBeanDefinition方法中处理BeanDefinitions,具体的处理工作交给了BeanDefinitionParserDelegate的parseBeanDefinitionElement,并且得到结果BeanDefinitionHolder,然后向IoC容器注册解析到的BeanDefinition,注册完成之后发送消息。BeanDefinitionParserDelegate类包含了对各种Spring Bean定义规则的处理。BeanDefinitionHolder是BeanDefinition的封装类,封装了BeanDefinition,Bean的名字、别名。用它来完成想IoC容器注册。
View Code
以下代码是对Bean元素的详细解析:
View Code
以上就是BeanDefinition在IoC容器中的载入和解析过程。
在上面的DefaultBeanDefinitionDocumentReader类的processBeanDefinition方法中我们看到有这么一行代码:BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());。这里的作用是想IoC容器注册解析后获得到的BeanDefinition。通过追踪代码,发现DefaultListableBeanFactory实现了在BeanDefinitionRegistry中定义的registerBeanDefinition方法。
View Code
总结:
[url=][/url]
IoC容器初始化的入口是在构造方法中调用refresh()开始的。通过ResourceLoader来完成资源文件位置的定位,DefaultResourceLoader是默认的实现,同时上下文本身就给出了ResourceLoader的实现。创建的IoC容器是DefaultListableBeanFactory。IoC容器对Bean的管理和依赖注入功能的实现是通过对其持有的BeanDefinition进行相关操作来完成的。通过BeanDefinitionReader来完成定义信息的解析和Bean信息的注册。XmlBeanDefinitionReader是BeanDefinitionReader的实现类,通过它来解析XML配置中的bean定义。实际的处理过程是委托给 BeanDefinitionParserDelegate来完成的。得到bean的定义信息,这些信息在Spring中使用BeanDefinition对象来表示。BeanDefinition的注册是由BeanDefinitionRegistry实现的registerBeanDefinition方法进行的。内部使用ConcurrentHashMap来保存BeanDefinition。 |