• 手撸mybatis03: xml配置的解析与注册


    在使用mybatis时,都是直接将sql写在xml中,由mybatis去解析后,映射执行,再通过代理模式实现IDao.

    SqlSessionFactoryBuilder

    package com.linnine.mybatis.session;

    /**
     * SqlSessionFactory 建造者工厂
     * 整个mybatis的入口类
     */
    public class SqlSessionFactoryBuilder {
    
        public SqlSessionFactory builder(Reader reader){
            //解析xml文件
            XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder(reader);
            //将解析内容转换成配置信息类
            return builder(xmlConfigBuilder.parse());
        }
    
        public SqlSessionFactory builder(Configuration config){
            return new DefaultSqlSessionFactory(config);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    XMLConfigBuilder

    先引入一下这个依赖

    <dependency>
        <groupId>org.dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>2.1.3</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    xml解析类

    package com.linnine.mybatis.builder;

    /**
     * xml 解析类
     */
    public class XMLConfigBuilder extends BaseBuilder {
    
        private Element root;
    
        public XMLConfigBuilder(Reader reader) {
            super(new Configuration());
            SAXReader saxReader = new SAXReader();
            try {
                Document document = saxReader.read(new InputSource(reader));
                root =document.getRootElement();
            } catch (DocumentException e) {
                e.printStackTrace();
            }
    
        }
    
        public Configuration parse() {
            //解析映射器
            try {
                mapperElement(root.element("mappers"));
            } catch (Exception e) {
                throw new RuntimeException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
            }
            return configuration;
        }
    
        private void mapperElement(Element mappers) throws Exception {
            List<Element> mapperList = mappers.elements("mapper");
            for (Element e : mapperList) {
                String resource = e.attributeValue("resource");
                Reader reader = Resources.getResourceAsReader(resource);
                SAXReader saxReader = new SAXReader();
                Document document = saxReader.read(new InputSource(reader));
                Element root = document.getRootElement();
                String namespace = root.attributeValue("namespace");
                List<Element> selectNodes = root.elements("select");
                for (Element node : selectNodes) {
                    String id = node.attributeValue("id");
                    String parameterType = node.attributeValue("parameterType");
                    String resultType = node.attributeValue("resultType");
                    String sql = node.getText();
                    Map<Integer, String> parameter = new HashMap<>();
                    //匹配参数占位符
                    Pattern pattern = Pattern.compile("(#\\{(.*?)})");
                    Matcher matcher = pattern.matcher(sql);
                    for (int i = 1; matcher.find(); i++) {
                        String g1 = matcher.group(1);
                        String g2 = matcher.group(2);
                        parameter.put(i,g2);
                        sql = sql.replace(g1, "?");
                    }
                    String msId=namespace+"."+id;
                    String nodeName = node.getName();
                    SqlCommandType sqlCommandType=SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
                    //解析处理
                    MappedStatement mappedStatement = new MappedStatement.Builder(configuration,msId,sqlCommandType,parameterType,resultType,sql,parameter).build();
                    //添加解析后的sql
                    configuration.addMappedStatement(mappedStatement);
                }
                configuration.addMapper(Resources.classForName(namespace));
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    BaseBuilder

    管理configuration

    package com.linnine.mybatis.builder;

    public abstract class BaseBuilder {
    
        protected final Configuration configuration;
    
        public BaseBuilder(Configuration configuration) {
            this.configuration = configuration;
        }
    
        public Configuration getConfiguration() {
            return configuration;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Configuration

    配置管理类, 主要是管理mapper的注册,以及statement 也就是sql的相关信息.

    package com.linnine.mybatis.session;

    public class Configuration {
    
        protected MapperRegistry mapperRegistry = new MapperRegistry(this);
    
        protected final Map<String, MappedStatement>  mappedStatements = new HashMap();
    
        public <T> void addMapper(Class<T> type){
            mapperRegistry.addMapper(type);
        }
    
        public <T> T getMapper(Class<T> type,SqlSession sqlSession){
            return mapperRegistry.getMapper(type,sqlSession);
        }
    
    
        public void addMappedStatement(MappedStatement ms) {
            mappedStatements.put(ms.getId(), ms);
        }
    
        public MappedStatement getMappedStatement(String id) {
            return mappedStatements.get(id);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    MapperRegistry

    对映射代理工厂进行管理

    package com.linnine.mybatis.binding;

    /**
     * 再对映射代理工厂进行管理
     */
    public class MapperRegistry {
    
        // 注册 代理映射工厂
        private final Map<Class<?>,MapperProxyFactory<?>> knownMappers = new HashMap<>();
    
        private Configuration configuration;
    
        public MapperRegistry(Configuration configuration) {
            this.configuration=configuration;
        }
    
    
        /**
         * 获取代理类
         * @param type
         * @param sqlSession
         * @param <T>
         * @return
         */
        public <T> T getMapper(Class<T> type, SqlSession sqlSession){
            // 获取代理工厂
            final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
            if (mapperProxyFactory == null){
                throw new RuntimeException("Type " + type + " is not known to the MapperRegistry.");
            }
            try {
                //通过代理工厂生产代理类
                return mapperProxyFactory.newInstance(sqlSession);
            }catch (Exception e){
                throw new RuntimeException("Error getting mapper instance. Cause: " + e, e);
            }
        }
    
        public <T> void addMapper(Class<T> type){
            //只注册接口
            if (type.isInterface()){
                //如果已存在不添加
                if (hasMapper(type)){
                    throw new RuntimeException("Type " + type + " is already known to the MapperRegistry.");
                }
                //根据类型创建一个代理工厂后注册
                knownMappers.put(type,new MapperProxyFactory<>(type));
            }
        }
    
        /**
         * 通过包名扫描添加
         * @param packageName
         */
        public void addMappers(String packageName){
            Set<Class<?>> mapperSet = ClassScanner.scanPackage(packageName);
            for (Class<?> mapperClass : mapperSet) {
                addMapper(mapperClass);
            }
        }
    
        public <T> boolean hasMapper(Class<T> type) {
            return knownMappers.containsKey(type);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    mybatis里好多循环依赖套来套去的 特别是configuration 吐了.

    DefaultSqlSession

    改造一下sql会话
    package com.linnine.mybatis.session;

    public class DefaultSqlSession implements  SqlSession{
    
        private final Configuration configuration;
    
        public DefaultSqlSession(Configuration configuration) {
            this.configuration = configuration;
        }
    
    
        /**
         * 在这个类里统一代理
         * @param statement
         * @param parameter
         * @param <T>
         * @return
         */
        @Override
        public <T> T selectOne(String statement, Object parameter) {
            MappedStatement mappedStatement = configuration.getMappedStatement(statement);
            return (T)("你被代理了!"+"方法:"+statement+",入参:"+parameter+"\n待执行sql: "+ mappedStatement.getSql());
        }
    
        /**
         * 从注册中心拿
         * @param type
         * @param <T>
         * @return
         */
        @Override
        public <T> T getMapper(Class<T> type) {
            //返回代理类,并返回代理方法的处理结果
            return configuration.getMapper(type,this);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    DefaultSqlSessionFactory

    改造一下工厂

    package com.linnine.mybatis.session;

    public class DefaultSqlSessionFactory implements SqlSessionFactory{
    
        private Configuration config;
    
        public DefaultSqlSessionFactory(Configuration config) {
            this.config =config;
        }
    
        @Override
        public SqlSession openSqlSession() {
            return new DefaultSqlSession(config);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    SqlCommandType

    sql操作类型

    package com.linnine.mybatis.binding.mapping;

    public enum SqlCommandType {
        /**
         * 未知
         */
        UNKNOWN,
        /**
         * 插入
         */
        INSERT,
        /**
         * 更新
         */
        UPDATE,
        /**
         * 删除
         */
        DELETE,
        /**
         * 查找
         */
        SELECT;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    mybatis-config-datasource.xml

    xml配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    
    <configuration>
    
        <mappers>
            <mapper resource="mapper/UserMapper.xml"/>
        </mappers>
    
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    UserMapper.xml

    <mapper namespace="com.linnine.mybatis.dao.IUserDao">
    
        <select id="queryUserInfoById" parameterType="java.lang.String" resultType="java.lang.String">
            SELECT id, userId, userHead, createTime
            FROM user
            where id = #{id}
        </select>
    
    </mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    IUserDao

    package com.linnine.mybatis.dao;

    public interface IUserDao {
    String queryUserInfoById(String uId);
    }

    开测

    @Test
    public void testMapperProxyFactory() throws IOException {
        Reader reader = Resources.getResourceAsReader("mybatis-config-datasource.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().builder(reader);
        SqlSession sqlSession = sqlSessionFactory.openSqlSession();
        IUserDao mapper = sqlSession.getMapper(IUserDao.class);
        String user = mapper.queryUserInfoById("10001");
        System.out.println(user);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    这里模拟了方法代理,和sql解析映射,日志打印

  • 相关阅读:
    Springboot毕设项目基于javaweb电费管理系统v39ge(java+VUE+Mybatis+Maven+Mysql)
    Jmeter-实现图片的上传和下载
    SQL注入
    Spring Boot集成JasperReport生成文档
    蓝桥杯备考随手记: 常用的三种排序算法(冒泡排序、插入排序、选择排序)
    在阿里云上配置开放端口的详细教程
    大量数据同步
    Android 9.0 隐藏设置中一级菜单“已连接的设备”
    java的springboot框架中使用logback日志框架使用RabbitHandler注解为什么获取不到消费的traceId信息?
    刷题笔记之九(查找输入整数二进制中1的个数+完全数计算+杨辉三角的变形+计算某字符出现次数)
  • 原文地址:https://blog.csdn.net/weixin_45369440/article/details/125480739