1. XML读取
一、Xml 文件读取流程
1. 通过继承自 AbstractBeanDefinitionReader 中的方法,来使用 ResourceLoader 将资源文件路径转换为对应的 Resource 文件;
2. 通过 DocumentLoader 对 Resource 文件进行转换,将 Resource 文件转换为 Document 文件;
3. 通过实现接口 BeanDefinitionDocumentReader 的 DefaultBeanDefinitionDocumentReader 类对 Document 进行解析,并使用 BeanDefinitionParserDelegate 对 Element 进行解析。
二、源代码阅读入口
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); BookService bookService = (BookService) bf.getBean("bookService");
三、源码解析
1. Resource创建
创建 Resource 对象,并对成员变量 path、classLoader(用于加载文件流:java.lang.ClassLoader#getResourceAsStream(String)) 赋值。
public ClassPathResource(String path) { this(path, (ClassLoader) null); } public ClassPathResource(String path, ClassLoader classLoader) { Assert.notNull(path, "Path must not be null"); String pathToUse = StringUtils.cleanPath(path); if (pathToUse.startsWith("/")) { pathToUse = pathToUse.substring(1); } this.path = pathToUse; this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader()); }
扩展:Resource 有多种实现类,用于读取不同场景下的文件。读取文件(FileSystemResource)、读取Classpath资源(ClassPathResource)、读取Url资源(UrlResource)、读取InputStream资源(InputStreamResource),等等。
2. 忽略给定接口自动装配功能
先说结论:将影响初始化的条件先忽略掉。
举个例子:在Bean初始化时,如果存在 A 依赖 B,Spring会自动初始化 B,但是当 B 实现了 BeanNameAware 接口时,就无法初始化,这个时候,我们就需要先将影响初始化的条件忽略掉。
public XmlBeanFactory(Resource resource) throws BeansException { this(resource, null); } public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { super(parentBeanFactory); this.reader.loadBeanDefinitions(resource); } public DefaultListableBeanFactory(BeanFactory parentBeanFactory) { super(parentBeanFactory); } public AbstractAutowireCapableBeanFactory(BeanFactory parentBeanFactory) { this(); setParentBeanFactory(parentBeanFactory); } public AbstractAutowireCapableBeanFactory() { super(); ignoreDependencyInterface(BeanNameAware.class); ignoreDependencyInterface(BeanFactoryAware.class); ignoreDependencyInterface(BeanClassLoaderAware.class); }
3. 将 Resource 转换为 Document 文件
1. 使用 EncodedResource 对 Resource 进行封装,对资源文件进行编码处理
2. 使用 ThreadLocal 检测是否存在循环加载
3. 从 Resource 中获取 InputStream 构造 InputSource
4. 将 Resource 转换为 Document(DOM解析)
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); } public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } // resourcesCurrentlyBeingLoaded是一个ThreadLocal Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<EncodedResource>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } // 如果无法加进去,说明该文件已解析过了,存在循环加载问题 if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } // 解析Xml文件 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } } protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource); } // ... // 一堆catch和throw } // getValidationModeForResource(resource):获取Xml验证格式(DTD or XSD) // getEntityResolver():获取EntityResolver(该类用于自定义寻找DTD文件方法,DTD文件默认从网络读取) protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception { return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, getValidationModeForResource(resource), isNamespaceAware()); } // 创建Document并解析,创建Factory,然后再创建实例,最后通过Source转换为Document(DOM解析) public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception { DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware); if (logger.isDebugEnabled()) { logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]"); } DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); return builder.parse(inputSource); }
4. 解析Xml
1. 解析前准备:创建documentReader、记录之前的BeanDefinition个数
2. 处理Profile属性,如果当前文件环境与Profile不一致,则不解析
3. 对root节点进行解析:
3.1 对于beans节点,使用bean解析
3.2 针对其他类型节点,使用自定义解析器解析
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // 使用DefaultBeanDefinitionDocumentReader实例化BeanDefinitionDocumentReader BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); // 设置环境变量,XmlBeanDefinitionReader初始化时创建的 documentReader.setEnvironment(getEnvironment()); // 记录之前加载的BeanDefinition个数 int countBefore = getRegistry().getBeanDefinitionCount(); // Bean加载 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); // 返回本次加载的BeanDefinition个数 return getRegistry().getBeanDefinitionCount() - countBefore; } public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); // 解析 root 下面所有节点 doRegisterBeanDefinitions(root); } protected void doRegisterBeanDefinitions(Element root) { //专门处理解析 BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); // 处理profile属性,如果当前环境与profile不同,则不解析 if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { return; } } } // 解析前处理,由子类实现 preProcessXml(root); parseBeanDefinitions(root, this.delegate); // 解析后处理,由子类实现 postProcessXml(root); this.delegate = parent; } protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { // 判断节点是否为beans(使用节点的命名空间与Spring固定的命名空间进行比较http://www.springframework.org/schema/beans,如果一致说明是默认的,否则是自定义标签) if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } // 自定义标签解析,例如 <tx:annotation-driven /> else { delegate.parseCustomElement(root); } }