使用XSD校验Mybatis的SqlMapper配置文件(2)

编写好XSD文件,而后来看怎么使用XSD文件校验,并解析SqlMapper文件,也就是实现doParseSqlMapperResourceWithSchema()方法。spring

为了实现这个功能,有两个基本要求:apache

(1)兼容性:须要兼容mybatis的原生配置,兼容有两种层级,一种是使用DTD校验,这个前面已经说了,走原来的流程,兼容性没有问题;另外一种就是走XSD校验,但也须要兼容mybatis原生配置,这种兼容性一方面从上面修改的XSD文件去保证,另外一方面也须要从XML的解析去保证。mybatis

(2)扩展性:修改的目的就是为了扩展性,因此扩展性也是一个基本要求。可是扩展性不是随意性,也须要按照规范来扩展,这个规范就是自定义的XSD文件。并发

 

为了达到这两个基本要求,下面是个人一种思路,主要借鉴于Spring的自定义命名空间:app

一、建立一个EntityResolver,读取类路径下指定模式的配置文件,好比:"classpath*:**/dysd-*-namespaces.ini"ide

二、在ini文件中定义命名空间元信息,如:函数

使用命名空间做为Section的名称,下面的schema、parser分别表示命名空间的xsd文件和解析器实现类,这样就能够根据XML中的XSD命名空间找到校验文件,而且有一个解析入口了。spa

说明:code

  1. apache的commons-configuration提供了ini格式文件的读取API
  2. Spring中使用META-INF/spring.schemas和META-INF/spring.handlers来存储XSD文件和解析器实现类,这里我修改成使用ini文件集中配置
  3. 由于读取的是全部类路径下知足通配符的ini文件,所以能够很是简单的扩展其它命名空间,至于在Java中具体怎么使用XSD来校验,这里就不细说了

我把XML的解析分解为三要素:解析上下文、解析器、被解析文件。doParseSqlMapperResourceWithSchema()方法也很简洁:对象

protected void doParseSqlMapperResourceWithSchema(Configuration configuration, Resource mapperLocation){
    ISqlMapperParserContext context = new SqlMapperParserContext(configuration);
    XmlParserUtils.parseXml(context, mapperLocation);
}

解析器接口以下:

public interface IParser<E extends IParserContext> {
    public void parse(E parserContext, String location);
    public void parse(E parserContext, String[] locationPatterns);
    public void parse(E parserContext, InputStream inputStream);
    public void parse(E parserContext, Resource resource);
}

解析上下文和解析器实现类又依次分为三个层级:

(1)通用解析上下文:

public interface IParserContext { 
    public ProblemReporter getProblemReporter();
    public EventListener getEventListener();
    public SourceExtractor getSourceExtractor();
    public Environment getEnvironment();
}

相应层级的解析器实现类主要负责加载被解析文件(好比将字符串通配符加载为Resource对象集合),保证不重复解析,保证可并发执行等。

(2)XML解析上下文

public interface IXmlParserContext extends IParserContext{
    public boolean isNamespaceAware();  
    public DocumentLoader getDocumentLoader();
    public EntityResolver getEntityResolver();
    public ErrorHandler getErrorHandler();
    public XmlParserDelegate getDelegate();
}

相应层级的解析器实现类主要负责将Resource转换为Document对象,并在转换的过程当中进行校验。

(3)SqlMapper解析上下文

public interface ISqlMapperParserContext extends IXmlParserContext{
    public Configuration getConfiguration();
}

相应层级的解析器实现类主要负责查找根元素所在命名空间的解析器,并使用解析器对Document进行解析。

最终,将解析委托给ini配置文件中的SchemaSqlMapperNamespaceParser类,可是由于这个类须要在文本文件中配置,不方便有参数的构造函数,于是进一步委托给SchemaSqlMapperParserDelegate:

public class SchemaSqlMapperNamespaceParser implements INamespaceParser<ISqlMapperParserContext> {

    @Override
    public void init() {
        
    }

    @Override
    public void parse(ISqlMapperParserContext parserContext, Document document, Resource resource) {
        SchemaSqlMapperParserDelegate delegate = new SchemaSqlMapperParserDelegate(parserContext, document, resource);
        delegate.parse();
    }
    
    @Override
    public void destory() {
        
    }
}

至此,XSD校验已经完成,也已经找到XML解析入口,后续就是在SchemaSqlMapperParserDelegate中真正的解析了。

相关文章
相关标签/搜索