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

相关推荐
book多得1 天前
Redis 大 Key 问题:识别、危害与最优处理方案
java·redis·mybatis
q***18062 天前
十八,Spring Boot 整合 MyBatis-Plus 的详细配置
spring boot·后端·mybatis
⑩-2 天前
苍穹外卖Day(1)
java·数据库·spring boot·spring·java-ee·mybatis
朝新_2 天前
【统一功能处理】从入门到源码:拦截器学习指南(含适配器模式深度解读)
数据库·后端·mybatis·适配器模式·javaee
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ2 天前
MyBatis Plus中执行原生SQL语句方法
python·sql·mybatis
R.lin2 天前
MyBatis 专题深度细化解析
oracle·面试·mybatis
JH30732 天前
MyBatis多表联查返回List仅一条数据?主键冲突BUG排查与解决
bug·mybatis
小坏讲微服务2 天前
Spring Boot整合Redis注解,实战Redis注解使用
spring boot·redis·分布式·后端·spring cloud·微服务·mybatis
xie_pin_an2 天前
MyBatis-Plus 实战:MPJLambdaWrapper 多表联查用法全解析
java·spring boot·spring·mybatis
华仔啊3 天前
MyBatis-Plus 让你开发效率翻倍!新手也能5分钟上手!
java·后端·mybatis