自定义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!

相关推荐
用户3126874877203 小时前
分页插件到底怎么拦截 SQL?MyBatis-Plus 插件机制原理一次讲透
mybatis
马优晨6 小时前
pring Boot + MyBatis + Redis 项目分层架构详解 —— 各层职责、关系与工作流程
架构·mybatis·spring项目分层架构详解·spring项目架构详解·spring各层职责·spring关系与工作流程
Listen·Rain9 小时前
用AI开发出一个AI
java·人工智能·spring boot·tomcat·intellij-idea·mybatis·visual studio
马优晨13 小时前
Spring Boot + MyBatis + Redis 整合实战 —— 项目源码深度解析
spring boot·redis·mybatis·mybatis + redis·redis实战·spring实战·mybatis实战
阿里云云原生1 天前
AI Agent 上线容易稳定难?阿里云 AgentLoop 推出“经验自进化”闭环治理方案
人工智能·阿里云·mybatis·agentscope
CodeStats2 天前
【Spring事务】Spring事务注解 @Transactional 完整体系:从 MySQL 隔离级别到 MyBatis 原理详解
java·spring·mybatis·事务·transactional
Nuanyt2 天前
SSM 学习记录 第二部分 Spring整合Mybatis&Junit AOP核心概念 Spring事务管理 SpringMVC 请求与响应 Rest风格
java·spring·junit·mybatis·restful
米码收割机2 天前
【SSM】Spring MVC_MyBatis SSM商城系统(源码+论文)【独一无二】
spring·mvc·mybatis
Devin~Y3 天前
互联网大厂 Java 面试实录:Spring Boot、MyBatis、Redis、Kafka、Spring Security、RAG 与 MCP 全链路问答
java·redis·kafka·mybatis·spring security·spring mvc·sprint boot
VX_bysjlw9854 天前
基于微信小程序的宠物用品商城系统-后端74346-计算机毕设原创(免费领源码+带部署教程)
java·redis·微信小程序·eclipse·mybatis·idea·微信开发者工具