自定义ORM(mybatis)源码(一)-解析config.xml

自定义ORM(mybatis)源码(一)-解析config.xml

模仿mybatis

配置文件

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<config>
    <datasource>
        <property key="driverName" value="com.mysql.cj.jdbc.Driver"></property>
        <property key="url" value="jdbc:mysql://localhost:3306"></property>
        <property key="username" value="test"></property>
        <property key="password" value="test"></property>
    </datasource>

    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</config>

解析这个xml ,我们使用 Xpath

Resource

资源读取

java 复制代码
public class Resource {


    /**
     * 读取资源文件
     * @param path
     * @return
     */
    public static InputStream getResourceAsStream(String path) {
        System.out.println(Resource.class.getClassLoader().getSystemResource("").getPath());
        return Resource.class.getClassLoader().getResourceAsStream(path);
    }
}

XNodeParser

XPath 解析 document工具

java 复制代码
public class XNodeParser {

    private Document document;
    private XPath xPath;


    public XNodeParser(Document document) {
        this.document = document;
        this.xPath = XPathFactory.newInstance().newXPath();
    }


    /**
     *
     *   <config>
     *          <mappers>
     *             <mapper resource="mapper/UserMapper.xml"/>
     *          </mappers>
     *      </config>
     *
     * expression=/config/mappers//mapper 即获取 mappers 下面所有 mapper  node 对象节点列表
     * @param expression
     * @return
     * @throws XPathExpressionException
     */
    public NodeList getNodeList(String expression) throws XPathExpressionException {
        return (NodeList) xPath.compile(expression).evaluate(document, XPathConstants.NODESET);
    }

    /**
     *    <config>
     *          <mappers>
     *             <mapper resource="mapper/UserMapper.xml"/>
     *          </mappers>
     *      </config>
     *
     * expression=/config/mappers 即获取 mappers node 对象节点
     * @param expression
     * @return
     * @throws XPathExpressionException
     */
    public Node getNodeObject(String expression) throws XPathExpressionException {
        return (Node) xPath.compile(expression).evaluate(document, XPathConstants.NODE);
    }

    /**
     * <mapper namespace="org.example.sample.dal.UserMapper">
     *  获取 namespace 值 即 org.example.sample.dal.UserMapper
     * @param node
     * @param attributeName
     * @return
     */
    public static String getAttributeValue(Node node, String attributeName) {
        return ((DeferredElementNSImpl) node).getAttribute(attributeName);
    }
}

XmlConfigParser

解析 config.xml

java 复制代码
public abstract class BaseXmlParser {

    @Getter
    protected Configuration configuration;

    public BaseXmlParser(Configuration configuration) {
        this.configuration = configuration;
    }


    protected Document createDocument(InputSource source) {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true); // never forget this!
            DocumentBuilder documentBuilder = factory.newDocumentBuilder();
            Document xml = documentBuilder.parse(source);
            xml.getDocumentElement().normalize();
            return xml;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public abstract Configuration parse();
}


public class XmlConfigParser extends BaseXmlParser {

    private Document document;

    public XmlConfigParser(Configuration configuration, InputStream inputStream) {
        super(configuration);
        this.document = createDocument(new InputSource(inputStream));
    }


    public Configuration parse() {
        parseProperties(this.document, getConfiguration());
        return getConfiguration();
    }

    private Properties parseProperties(Document document, Configuration configuration) {
        Properties properties = new Properties();

        try {
            XNodeParser xNodeParser = new XNodeParser(document);
            //解析datasource
            extractedDataSource(xNodeParser.getNodeList("/config/datasource//property"), properties, configuration);
            //解析xml-mapper
            extractedMapper(xNodeParser.getNodeList("/config/mappers//mapper"), properties, configuration);
            System.out.println(properties);
            return properties;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    private void extractedMapper(NodeList nodeList, Properties properties, Configuration configuration) {
        List<String> mapperLocation = new ArrayList<>();
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node item = nodeList.item(i);
            String resource = XNodeParser.getAttributeValue(item, "resource");
            mapperLocation.add(resource);
            //解析mapper.xml
            XmlMapperParser xmlMapperParser = new XmlMapperParser(Resource.getResourceAsStream(resource), properties, configuration);
            xmlMapperParser.parse();
        }
        properties.put("mapperLocation", mapperLocation);
    }


    private void extractedDataSource(NodeList nodeList, Properties properties, Configuration configuration) throws Exception {
        BeanWrapperImpl beanWrapper = new BeanWrapperImpl(DataSourceProperties.class);
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node item = nodeList.item(i);
            String key = ((DeferredElementNSImpl) item).getAttribute("key");
            String value = ((DeferredElementNSImpl) item).getAttribute("value");
            beanWrapper.setPropertyValue(key, value);
            properties.put(key, value);
        }
        DataSourceProperties dataSourceProperties = (DataSourceProperties) beanWrapper.getWrappedInstance();
        configuration.setDataSourceFactory(new MysqlDataSourceFactory(dataSourceProperties));
    }

}

通用的 xml 解析都可以这样处理

Configuration

java 复制代码
public class Configuration {


    @Getter
    @Setter
    private DataSourceFactory dataSourceFactory;

    //Map<stmtId[namespace+sqlId],MappedStatement>
    private Map<String, MappedStatement> statements = new ConcurrentHashMap<>();

    private MapperRegistry mapperRegistry = new MapperRegistry();

    /**
     * 注册mapper
     * @param mapperClz
     */
    public void addMapper(Class<?> mapperClz) {
        mapperRegistry.addMapper(mapperClz);
    }

    /**
     * 注册 sql-map
     * @param mappedStatement
     */
    public void addMappedStatement(MappedStatement mappedStatement) {
        statements.put(mappedStatement.getFullId(), mappedStatement);
    }

    public <T> T getMapper(Class<T> mapper, SqlSession sqlSession) {
        return mapperRegistry.getMapper(mapper, sqlSession);
    }

    /**
     * 获取绑定的sql
     * mapper.namespace+id
     * @param stmtId
     * @return
     */
    public MappedStatement getMappedStatement(String stmtId){
        return statements.get(stmtId);
    }
}

good luck!

相关推荐
秋恬意4 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
张铁铁是个小胖子14 小时前
MyBatis学习
java·学习·mybatis
hanbarger18 小时前
mybatis框架——缓存,分页
java·spring·mybatis
乘风御浪云帆之上1 天前
数据库操作【JDBC & HIbernate & Mybatis】
数据库·mybatis·jdbc·hibernate
向阳12182 天前
mybatis 动态 SQL
数据库·sql·mybatis
新手小袁_J2 天前
JDK11下载安装和配置超详细过程
java·spring cloud·jdk·maven·mybatis·jdk11
xlsw_2 天前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
cmdch20172 天前
Mybatis加密解密查询操作(sql前),where要传入加密后的字段时遇到的问题
数据库·sql·mybatis
秋恬意3 天前
什么是MyBatis
mybatis
CodeChampion3 天前
60.基于SSM的个人网站的设计与实现(项目 + 论文)
java·vue.js·mysql·spring·elementui·node.js·mybatis