创建工厂:
package com.laoxu.mybatis.executor;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class start {
public static void main(String[] args) throws IOException {
// user.dir指定了当前的路径
String userDir = System.getProperty("user.dir");
System.out.println(userDir);
// 获取类路径
String classPath = start.class.getResource("/").getPath();
System.out.println(classPath);
// 根据当前类路径下的相对路径 (classPath + {path})
String resource = "mapper/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
}
实例化一个xml配置构造器:
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.session;
import org.apache.ibatis.builder.xml.XMLConfigBuilder;
import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory;
import java.io.InputStream;
import java.util.Properties;
/**
*构建{@link SqlSession}实例。
*
* @作者克林顿·贝京
*/
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return new DefaultSqlSessionFactory();
}
}
对xml配置构造器进行构造:
/**
* Copyright 2009-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.builder.xml;
import org.apache.ibatis.builder.BaseBuilder;
import org.apache.ibatis.parsing.XPathParser;
import java.io.InputStream;
import java.util.Properties;
/**
* @author Clinton Begin
* @author Kazuki Shimizu
*/
public class XMLConfigBuilder extends BaseBuilder {
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
}
}
该类继承基础构造器抽象类BaseBuilder
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.builder;
/**
* @author Clinton Begin
*/
public abstract class BaseBuilder {
}
构造一个xpath解析器:
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.parsing;
import org.xml.sax.EntityResolver;
import java.io.InputStream;
import java.util.Properties;
/**
* @author Clinton Begin
* @author Kazuki Shimizu
*/
public class XPathParser {
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
}
}
- new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()) 构造一个xpath解析器
1、创建公共构造器
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.parsing;
import org.xml.sax.EntityResolver;
import java.io.InputStream;
import java.util.Properties;
/**
* @author Clinton Begin
* @author Kazuki Shimizu
*/
public class XPathParser {
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
}
private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
}
}
2、初始化创建XPath类
private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
this.validation = validation;
this.entityResolver = entityResolver;
this.variables = variables;
XPathFactory factory = XPathFactory.newInstance();
this.xpath = factory.newXPath();
}
3、创建文档
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.parsing;
import org.w3c.dom.Document;
import org.xml.sax.*;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import java.io.InputStream;
import java.util.Properties;
/**
* @author Clinton Begin
* @author Kazuki Shimizu
*/
public class XPathParser {
private final Document document;
private boolean validation;
private EntityResolver entityResolver;
private Properties variables;
private XPath xpath;
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
this.document = createDocument(new InputSource(inputStream));
}
private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
this.validation = validation;
this.entityResolver = entityResolver;
this.variables = variables;
XPathFactory factory = XPathFactory.newInstance();
this.xpath = factory.newXPath();
}
private Document createDocument(InputSource inputSource) {
// TODO 创建文档
}
}
4、实例化一个文档构造器工厂进行创建文档
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.parsing;
import org.apache.ibatis.builder.BuilderException;
import org.w3c.dom.Document;
import org.xml.sax.*;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import java.io.InputStream;
import java.util.Properties;
/**
* @author Clinton Begin
* @author Kazuki Shimizu
*/
public class XPathParser {
private final Document document;
private boolean validation;
private EntityResolver entityResolver;
private Properties variables;
private XPath xpath;
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
this.document = createDocument(new InputSource(inputStream));
}
private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
this.validation = validation;
this.entityResolver = entityResolver;
this.variables = variables;
XPathFactory factory = XPathFactory.newInstance();
this.xpath = factory.newXPath();
}
private Document createDocument(InputSource inputSource) {
// 重要提示:这个函数只能在通用构造函数之后调用
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 功能安全处理
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
// 验证
factory.setValidating(validation);
// 命名空间
factory.setNamespaceAware(false);
// 忽略注释
factory.setIgnoringComments(true);
// 忽略元素内容空白
factory.setIgnoringElementContentWhitespace(false);
// 合并
factory.setCoalescing(false);
// 扩展实体引用
factory.setExpandEntityReferences(true);
// 实例化一个文档构造器
DocumentBuilder builder = factory.newDocumentBuilder();
// 实体解析器
builder.setEntityResolver(entityResolver);
// 错误处理器
builder.setErrorHandler(new ErrorHandler() {
@Override
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void warning(SAXParseException exception) throws SAXException {
// NOP
}
});
// 文档构造器解析 mybatis核心配置文件 mybatis-config.xml
// 返回 Document 对象
return builder.parse(inputSource);
} catch (Exception e) {
throw new BuilderException("Error creating document instance. Cause: " + e, e);
}
}
}
- new XMLMapperEntityResolver() xml映射实体解析器
1、实体解析器接口
/*
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
// SAX entity resolver.
// http://www.saxproject.org
// No warranty; no copyright -- use this as you will.
// $Id: EntityResolver.java,v 1.2 2004/11/03 22:44:52 jsuttor Exp $
package org.xml.sax;
import java.io.IOException;
/**
* Basic interface for resolving entities.
*
* <blockquote>
* <em>This module, both source code and documentation, is in the
* Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
* See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
* for further information.
* </blockquote>
*
* <p>If a SAX application needs to implement customized handling
* for external entities, it must implement this interface and
* register an instance with the SAX driver using the
* {@link org.xml.sax.XMLReader#setEntityResolver setEntityResolver}
* method.</p>
*
* <p>The XML reader will then allow the application to intercept any
* external entities (including the external DTD subset and external
* parameter entities, if any) before including them.</p>
*
* <p>Many SAX applications will not need to implement this interface,
* but it will be especially useful for applications that build
* XML documents from databases or other specialised input sources,
* or for applications that use URI types other than URLs.</p>
*
* <p>The following resolver would provide the application
* with a special character stream for the entity with the system
* identifier "http://www.myhost.com/today":</p>
*
* <pre>
* import org.xml.sax.EntityResolver;
* import org.xml.sax.InputSource;
*
* public class MyResolver implements EntityResolver {
* public InputSource resolveEntity (String publicId, String systemId)
* {
* if (systemId.equals("http://www.myhost.com/today")) {
* // return a special input source
* MyReader reader = new MyReader();
* return new InputSource(reader);
* } else {
* // use the default behaviour
* return null;
* }
* }
* }
* </pre>
*
* <p>The application can also use this interface to redirect system
* identifiers to local URIs or to look up replacements in a catalog
* (possibly by using the public identifier).</p>
*
* @since SAX 1.0
* @author David Megginson
* @see org.xml.sax.XMLReader#setEntityResolver
* @see org.xml.sax.InputSource
*/
public interface EntityResolver {
/**
* Allow the application to resolve external entities.
*
* <p>The parser will call this method before opening any external
* entity except the top-level document entity. Such entities include
* the external DTD subset and external parameter entities referenced
* within the DTD (in either case, only if the parser reads external
* parameter entities), and external general entities referenced
* within the document element (if the parser reads external general
* entities). The application may request that the parser locate
* the entity itself, that it use an alternative URI, or that it
* use data provided by the application (as a character or byte
* input stream).</p>
*
* <p>Application writers can use this method to redirect external
* system identifiers to secure and/or local URIs, to look up
* public identifiers in a catalogue, or to read an entity from a
* database or other input source (including, for example, a dialog
* box). Neither XML nor SAX specifies a preferred policy for using
* public or system IDs to resolve resources. However, SAX specifies
* how to interpret any InputSource returned by this method, and that
* if none is returned, then the system ID will be dereferenced as
* a URL. </p>
*
* <p>If the system identifier is a URL, the SAX parser must
* resolve it fully before reporting it to the application.</p>
*
* @param publicId The public identifier of the external entity
* being referenced, or null if none was supplied.
* @param systemId The system identifier of the external entity
* being referenced.
* @return An InputSource object describing the new input source,
* or null to request that the parser open a regular
* URI connection to the system identifier.
* @exception org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @exception java.io.IOException A Java-specific IO exception,
* possibly the result of creating a new InputStream
* or Reader for the InputSource.
* @see org.xml.sax.InputSource
*/
public abstract InputSource resolveEntity (String publicId,
String systemId)
throws SAXException, IOException;
}
// end of EntityResolver.java
2、实现实体解析器接口
/**
* Copyright 2009-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.builder.xml;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* MyBatis dtd的离线实体解析器。
*
* @author Clinton Begin
* @author Eduardo Macarron
*/
public class XMLMapperEntityResolver implements EntityResolver {
/**
* 将公共DTD转换为本地DTD。
*
* @param publicId
* 公共id,在" public "后面
* @param systemId
* 在公共id之后的系统id。
* @return DTD的InputSource
*
* @throws org.xml.sax.SAXException
* 如果出了什么差错
*/
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
return new InputSource();
}
}
3、解析实体,获取数据源
/**
* Copyright 2009-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.builder.xml;
import org.apache.ibatis.io.Resources;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;
/**
* MyBatis dtd的离线实体解析器。
*
* @author Clinton Begin
* @author Eduardo Macarron
*/
public class XMLMapperEntityResolver implements EntityResolver {
private static final String IBATIS_CONFIG_SYSTEM = "ibatis-3-config.dtd";
private static final String IBATIS_MAPPER_SYSTEM = "ibatis-3-mapper.dtd";
private static final String MYBATIS_CONFIG_SYSTEM = "mybatis-3-config.dtd";
private static final String MYBATIS_MAPPER_SYSTEM = "mybatis-3-mapper.dtd";
private static final String MYBATIS_CONFIG_DTD = "org/apache/ibatis/builder/xml/mybatis-3-config.dtd";
private static final String MYBATIS_MAPPER_DTD = "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd";
/**
* 将公共DTD转换为本地DTD。
*
* @param publicId
* 公共id,在" public "后面
* @param systemId
* 在公共id之后的系统id。
* @return DTD的InputSource
*
* @throws org.xml.sax.SAXException
* 如果出了什么差错
*/
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
// 去读取mybatis-config.xml头标签<!DOCTYPE configuration ...param>的两个参数
try {
if (systemId != null) {
// 系统id小写处理
String lowerCaseSystemId = systemId.toLowerCase(Locale.ENGLISH);
if (lowerCaseSystemId.contains(MYBATIS_CONFIG_SYSTEM) ||
lowerCaseSystemId.contains(IBATIS_CONFIG_SYSTEM)) {
// 如果系统id包含 系统配置 标识
return getInputSource(MYBATIS_CONFIG_DTD, publicId, systemId);
} else if (lowerCaseSystemId.contains(MYBATIS_MAPPER_SYSTEM) ||
lowerCaseSystemId.contains(IBATIS_MAPPER_SYSTEM)) {
// 如果系统id包含 映射系统 标识
return getInputSource(MYBATIS_MAPPER_DTD, publicId, systemId);
}
}
return null;
} catch (Exception e) {
throw new SAXException(e.toString());
}
}
/**
* 获取输入源
* @param path 路径
* @param publicId 公共id
* @param systemId 系统Id
* @return
*/
private InputSource getInputSource(String path, String publicId, String systemId) {
InputSource source = null;
if (path != null) {
try {
// 去类路径获取输入流
InputStream in = Resources.getResourceAsStream(path);
source = new InputSource(in);
source.setPublicId(publicId);
source.setSystemId(systemId);
} catch (IOException e) {
// 忽略,null也可以
}
}
return source;
}
}
读取mybatis-config.xml的<!DOCTYPE configuration ...param>标签
根据系统id进行系统配置
获取输入源
遇到问题:在编译非java文件时,未被编译进类路径
解决参考:https://blog.csdn.net/weixin_42135693/article/details/107514126
要在maven的build标签中加上编译非java文件声明
<build>
<!-- 编译非java文件 -->
<resources>
<resource>
<directory>${project.build.sourceDirectory}</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
</build>
加上后成功编译非java文件
两个重要的格式校验文件
mybatis-3-config.dtd和mybatis-3-mapper.dtd
mybatis-3-config.dtd 为 mybatis-config.xml 格式校验文件
校验:
mybatis-3-mapper.dtd 为 我们自定义的*.Mapper.xml 格式校验文件
校验:
说明:
格式:<!--
<!ELEMENT 父标签 (字标签)>
<!ATTLIST 标签名
属性名 类型 属性特点
...
-->
类型: CDATA 为标签定义一个属性,属性值是字符串
NMTOKEN/NMTOKENS NMTOKEN同CDATA,但是属性值只能是字母、数字、下划线、句号、破折号、冒号,不能含有空格;NMTOKENS在NMTOKEN基础上可以出现多个空格分隔的字符
ID 属性值唯一
IDREF/IDREFS IDREF属性值指向其他地方声明的ID值;IDREFS在IDREF基础上可以指向由空格分隔开的ID值
Enumerated 定义好一些值,属性的值必须在所列出的值的范围内
属性特点: #REQUIRED 标签必须有该属性的值(NOT NULL) <!ATTLIST 标签名 属性名 属性类型 #REQUIRED>
#IMPLIED 标签中可以忽略该属性(NULL) <!ATTLIST 标签名 属性名 属性类型 #IMPLIED>
#FIXED value 标签必须为属性指定的固定值 <!ATTLIST 标签名 属性名 属性类型 #FIXED "value">
Default value 为属性提供一个默认的值 <!ATTLIST 标签名 属性名 属性类型 "value">