spring源码(八)--ResourceEntityResolver(dtd xsd及其它)

验证文件的默认加载方式是网络加载,这样可能很慢,体验不好。所以自定义EntityResolver加载本地的校验文件。
类层次图:
这里写图片描述

EntityResolver是jdk中rt.jar包中的接口,接口中只有一个方法

public abstract InputSource resolveEntity (String publicId,String systemId)
        throws SAXException, IOException;

DelegatingEntityResolver类实现了接口中的方法,把具体的解析工作委托给了dtdResolver、schemaResolver。

public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
        if(systemId != null) {
            if(systemId.endsWith(".dtd")) {
                return this.dtdResolver.resolveEntity(publicId, systemId);
            }

            if(systemId.endsWith(".xsd")) {
                return this.schemaResolver.resolveEntity(publicId, systemId);
            }
        }

        return null;
    }

如果没有指定dtdResolver、schemaResolver,则默认的是:

public DelegatingEntityResolver(ClassLoader classLoader) {
        this.dtdResolver = new BeansDtdResolver();
        this.schemaResolver = new PluggableSchemaResolver(classLoader);
    }

ResourceEntityResolver相较于父类,多了一个ResourceLoader,并重新实现了接口中的方法
这个ResourceLoader一般是PathMatchingResourcePatternResolver,在第七篇有解析
这个方法做的事情有:

  1. 委托父类解析出inputsource,如果父类解析成功(父类只解析dtd文件和xsd文件),则结束
  2. 解析文件资源的相对路径(相对于系统根路径)
  3. resourceLoader通过上面获得的相对路径解析资源
  4. 创建inputsource,把上面的Resource转换为inputsource
  public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
        InputSource source = super.resolveEntity(publicId, systemId);
        if(source == null && systemId != null) {
            String resourcePath = null;

            try {
                String decodedSystemId = URLDecoder.decode(systemId, "UTF-8");
                String givenUrl = (new URL(decodedSystemId)).toString();
                String systemRootUrl = (new File("")).toURI().toURL().toString();
                if(givenUrl.startsWith(systemRootUrl)) {
                    resourcePath = givenUrl.substring(systemRootUrl.length());
                }
            } catch (Exception var8) {
                resourcePath = systemId;
            }

            if(resourcePath != null) {           
                Resource resource = this.resourceLoader.getResource(resourcePath);
                source = new InputSource(resource.getInputStream());
                source.setPublicId(publicId);
                source.setSystemId(systemId);
            }
        }

        return source;
    }

父类针对dtd和xsd文件有不同的解析方式

dtd文件解析:
判断文件是不是dtd结尾,并且文件名包含spring-beans
默认返回spring-beans-2.0.dtd的inputsource

public InputSource resolveEntity(String publicId, String systemId) throws IOException {
        if(systemId != null && systemId.endsWith(".dtd")) {
            int lastPathSeparator = systemId.lastIndexOf("/");
            int dtdNameStart = systemId.indexOf("spring-beans", lastPathSeparator);
            if(dtdNameStart != -1) {
                String dtdFile = "spring-beans-2.0.dtd";

                try {
                    Resource resource = new ClassPathResource(dtdFile, this.getClass());
                    InputSource source = new InputSource(resource.getInputStream());
                    source.setPublicId(publicId);
                    source.setSystemId(systemId);

                    return source;
                } catch (IOException var8) {
                }
            }
        }

        return null;
    }

xsd文件解析:
把xsd的虚拟路径转换为实际路径,然后解析为inputsource。

public InputSource resolveEntity(String publicId, String systemId) throws IOException {
        if(systemId != null) {
            String resourceLocation = (String)this.getSchemaMappings().get(systemId);
            if(resourceLocation != null) {
                ClassPathResource resource = new ClassPathResource(resourceLocation, this.classLoader);

                try {
                    InputSource source = new InputSource(resource.getInputStream());
                    source.setPublicId(publicId);
                    source.setSystemId(systemId); 
                    return source;
                } catch (FileNotFoundException var6) {
                }
            }
        }

        return null;
    }
//获取spring.schemas中定义的所有属性吧,比如
//http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd

 private Map<String, String> getSchemaMappings() {
        if(this.schemaMappings == null) {
            synchronized(this) {
                if(this.schemaMappings == null) {
                    try {
                        Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.schemaMappingsLocation, this.classLoader);

                        Map<String, String> schemaMappings = new ConcurrentHashMap(mappings.size());
                        CollectionUtils.mergePropertiesIntoMap(mappings, schemaMappings);
                        this.schemaMappings = schemaMappings;
                    } catch (IOException var5) {
                        throw new IllegalStateException("Unable to load schema mappings from location [" + this.schemaMappingsLocation + "]", var5);
                    }
                }
            }
        }

        return this.schemaMappings;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值