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

相关推荐
risc1234562 天前
Roaring Bitmap
java·开发语言·mybatis
Wang's Blog2 天前
JavaWeb快速入门: MyBatis入门与实战
java·mybatis
前端炒粉3 天前
马克思主义基本原理在MyBatis框架中的指导作用探析
mybatis·马克思主义
.Hypocritical.3 天前
MyBatis-Plus笔记
mybatis·mybatisplus
折哥的程序人生 · 物流技术专研3 天前
Java面试通关⑩:MyBatis核心源码全集
mybatis·校招·java面试·orm框架·源码解析·数据库交互·社招
SeeYa-J4 天前
MyBatis(数据持久层,❗ “接口 = SQL执行器”)
mybatis
骑士雄师4 天前
java面试题:jvm ,mybatis
java·jvm·mybatis
风中芦苇啊4 天前
Java MyBatis 实战:如何通过 SQL 查询返回 List<Map> 数据格式
java·sql·mybatis
脑子运行超载5 天前
Jackson处理和mybatis的xml转换问题
xml·jackson·mybatis·javatype
杨运交5 天前
[042][数据模块]Mybatis Plus 数据库级租户:基于多数据源路由的动态隔离实现
数据库·oracle·mybatis