EntityResolver

  • Author: HuiFer
  • 源码阅读仓库: huifer-spring
  • 源码路径: org.xml.sax.EntityResolver,非 Spring 类

DelegatingEntityResolver#resolveEntity

  • org.springframework.beans.factory.xml.DelegatingEntityResolver.resolveEntity
  1. @Override
  2. @Nullable
  3. public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId)
  4. throws SAXException, IOException {
  5. if (systemId != null) {
  6. if (systemId.endsWith(DTD_SUFFIX)) {
  7. return this.dtdResolver.resolveEntity(publicId, systemId);
  8. }
  9. else if (systemId.endsWith(XSD_SUFFIX)) {
  10. return this.schemaResolver.resolveEntity(publicId, systemId);
  11. }
  12. }
  13. // Fall back to the parser's default behavior.
  14. return null;
  15. }
  • 上述这段代码是针对 xml 进行校验
  1. <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xmlns="http://www.springframework.org/schema/beans"
  3. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  • 如上所示以.xsd结尾,应该执行return this.schemaResolver.resolveEntity(publicId, systemId);方法 http://www.springframework.org/schema/beans/spring-beans.xsd
  • org.springframework.beans.factory.xml.PluggableSchemaResolver.resolveEntity

PluggableSchemaResolver#resolveEntity

  1. @Override
  2. @Nullable
  3. public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId) throws IOException {
  4. if (logger.isTraceEnabled()) {
  5. logger.trace("Trying to resolve XML entity with public id [" + publicId +
  6. "] and system id [" + systemId + "]");
  7. }
  8. if (systemId != null) {
  9. // 获取当前 systemId 对应的资源
  10. // spring-framework\spring-beans\src\main\resources\org\springframework\beans\factory\xml\spring-beans.xsd
  11. String resourceLocation = getSchemaMappings().get(systemId);
  12. if (resourceLocation == null && systemId.startsWith("https:")) {
  13. // Retrieve canonical http schema mapping even for https declaration
  14. resourceLocation = getSchemaMappings().get("http:" + systemId.substring(6));
  15. }
  16. if (resourceLocation != null) {
  17. // 加载 resourceLocation 转换成 Resource
  18. Resource resource = new ClassPathResource(resourceLocation, this.classLoader);
  19. try {
  20. // 读取
  21. InputSource source = new InputSource(resource.getInputStream());
  22. source.setPublicId(publicId);
  23. source.setSystemId(systemId);
  24. if (logger.isTraceEnabled()) {
  25. logger.trace("Found XML schema [" + systemId + "] in classpath: " + resourceLocation);
  26. }
  27. return source;
  28. }
  29. catch (FileNotFoundException ex) {
  30. if (logger.isDebugEnabled()) {
  31. logger.debug("Could not find XML schema [" + systemId + "]: " + resource, ex);
  32. }
  33. }
  34. }
  35. }
  36. // Fall back to the parser's default behavior.
  37. return null;
  38. }

image-20200108081404857

image-20200108081623427

得到本地路径,后续直接返回读取资源

BeansDtdResolver#resolveEntity

创建一个 Dtd 的约束文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/dtd/spring-beans-2.0.dtd">
  5. </beans>
  1. @Override
  2. @Nullable
  3. public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId) throws IOException {
  4. if (logger.isTraceEnabled()) {
  5. logger.trace("Trying to resolve XML entity with public ID [" + publicId +
  6. "] and system ID [" + systemId + "]");
  7. }
  8. if (systemId != null && systemId.endsWith(DTD_EXTENSION)) {
  9. int lastPathSeparator = systemId.lastIndexOf('/');
  10. int dtdNameStart = systemId.indexOf(DTD_NAME, lastPathSeparator);
  11. if (dtdNameStart != -1) {
  12. // 获取静态变量组装成文件名称(spring-beans.dtd)
  13. String dtdFile = DTD_NAME + DTD_EXTENSION;
  14. if (logger.isTraceEnabled()) {
  15. logger.trace("Trying to locate [" + dtdFile + "] in Spring jar on classpath");
  16. }
  17. try {
  18. // 加载资源
  19. Resource resource = new ClassPathResource(dtdFile, getClass());
  20. InputSource source = new InputSource(resource.getInputStream());
  21. source.setPublicId(publicId);
  22. source.setSystemId(systemId);
  23. if (logger.isTraceEnabled()) {
  24. logger.trace("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
  25. }
  26. return source;
  27. }
  28. catch (FileNotFoundException ex) {
  29. if (logger.isDebugEnabled()) {
  30. logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in classpath", ex);
  31. }
  32. }
  33. }
  34. }
  35. // Fall back to the parser's default behavior.
  36. return null;
  37. }
  • systemId https://www.springframework.org/dtd/spring-beans-2.0.dtd

image-20200108082335031

总结

  • DelegatingEntityResolver#resolveEntity,是对 xml 文档的校验前置步骤,根据dtdxsd加载本地资源文件 spring-framework\spring-beans\src\main\resources\org\springframework\beans\factory\xml\spring-beans.dtd spring-framework\spring-beans\src\main\resources\org\springframework\beans\factory\xml\spring-beans.xsd
  • PluggableSchemaResolver负责加载xsd文件
  • BeansDtdResolver负责加载dtd文件