2.5容器的基础XmlBeanFactory
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactory.xml"));
初始化XmlBeanFactory逻辑的时序图:

2.5.1读取配置文件(资源)的方式
对于不同来源的资源文件都有相应的Resource实现。文件(FileSystemResource)、ClassPath资源(ClassPathResource)、URL资源(URLResource)、InputStream资源(InputStreamResource)、Byte数组(ByteArrayResoure)。
public XmlBeanFactory(Resource resource) throws BeansException { //构造函数内部再次调用构造函数XmlBeanFactory(Resource resource,BeanFactory parentBeanFactory) this(resource, null); } public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { //parentBeanFactory可以为空 //跟踪代码到父类AbstractAutowireCapableBeanFactory的构造方法 super(parentBeanFactory); this.reader.loadBeanDefinitions(resource); } AbstractAutowireCapableBeanFactory public AbstractAutowireCapableBeanFactory() { super(); //ignoreDependencyInterface的主要功能还是忽略给定接口的自动装配功能。 //举例来说就是A中有属性B,如果Spring获取A的Bean时,如果属性属性B还没有 //初始化,那么Spring就会自动初始化B,这也是Spring提供的一个重要特性。 //但是,某些情况下B不会初始化,其中一种情况就是B实现了BeanNameAware接口。 ignoreDependencyInterface(BeanNameAware.class); ignoreDependencyInterface(BeanFactoryAware.class); ignoreDependencyInterface(BeanClassLoaderAware.class); if (IN_NATIVE_IMAGE) { this.instantiationStrategy = new SimpleInstantiationStrategy(); } else { this.instantiationStrategy = new CglibSubclassingInstantiationStrategy(); } }
2.5.2加载Bean

1.封装资源文档。当进入XmlBeanDefinition后首先对参数Resource使用EncodedResource类进行封装。
2.获取输入流。从Resource中获取对应InputStream并构造InputSource。
3.通过InputSource实例与Resource实例继续调用doLoadBeanDefinitions。
loadBeanDefinitions函数的实现:
XmlBeanDefinitionReader public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); } EncodedResource public EncodedResource(Resource resource) { this(resource, null, null); } EncodedResource private EncodedResource(Resource resource, @Nullable String encoding, @Nullable Charset charset) { super(); Assert.notNull(resource, "Resource must not be null"); this.resource = resource; this.encoding = encoding; this.charset = charset; }
EncodedResource为Resource设置了编码。
下面是数据准备阶段:
XmlBeanDefinitionReader public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isTraceEnabled()) { logger.trace("Loading XML bean definitions from " + encodedResource); } //通过属性来记录已经加载过的资源 Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } //从encodedResource中获取已经封装的Resource对象并再次从Resource中获取其中的InputStream try (InputStream inputStream = encodedResource.getResource().getInputStream()) { //InputSource不是来源于Spring,它的全路径是org.xml.sax.InoutSource InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } //进入真正的逻辑核心部分 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } }
首先对Resource进行封装,考虑到Resource可能存在编码要求的情况。其次通过SAX的方式读取XML文件来准备InputSource对象。最后将准备的数据传入核心处理部分doLoadBeanDefinition。
核心方法doLoadBeanDefinition:
XmlBeanDefinitionReader protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); int count = registerBeanDefinitions(doc, resource); if (logger.isDebugEnabled()) { logger.debug("Loaded " + count + " bean definitions from " + resource); } return count; } catch (BeanDefinitionStoreException ex) { throw ex; } catch (SAXParseException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex); } catch (SAXException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", ex); } catch (ParserConfigurationException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, ex); } catch (IOException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, ex); } catch (Throwable ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, ex); } } XmlBeanDefinitionReader protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception { return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, getValidationModeForResource(resource), isNamespaceAware()); }
在上面冗余的代码中如果不考虑异常代码,其实就做了三件事:
- 获取对XML文件的验证模式
- 加载XML文件,并得到对应的Document
- 根据返回的Document注册Bean信息
下面我们开始获取XML文件的验证模式。

浙公网安备 33010602011771号