行为性模式-中介者模式

中介者模式

简单模拟mybatis框架操作数据库核心逻辑来理解中介者模式

核心流程

中介者模式.drawio

技术点

  1. Resource 读取mybatis数据源配置文件生成输入流

    使用多个类加载器(系统类加载器和当前线程上下文类加载器)读取文件

    public static InputStream getResourceAsReader(String resource) throws IOException{
        ClassLoader[] classLoaders = getClassLoader();
        for (ClassLoader classLoader : classLoaders) {
            InputStream inputStream = classLoader.getResourceAsStream(resource);
            if (null != inputStream) {
                return inputStream;
            }
        }
        throw new IOException("Could not find resource " + resource);
    }
    public  static ClassLoader[] getClassLoader() {
        return new ClassLoader[] {
            ClassLoader.getSystemClassLoader(),
            Thread.currentThread().getContextClassLoader()
        };
    }
    
  2. SqlSessionFactoryBuilder 生成 SqlSessionFactory

    使用XMLMapperEntityResolver类解析xml文件

    public SqlSessionFactory build(Reader reader) throws DocumentException, ClassNotFoundException, SQLException, IOException {
        SAXReader saxReader = new SAXReader();
        saxReader.setEntityResolver(new XMLMapperEntityResolver());
        Document document = saxReader.read(reader);
        Configuration configuration = parseConfiguration(document.getRootElement());
        return new DefaultSqlSessionFactory(configuration);
    }
    

    使用正则表达式替换mapper.xml中sql的param为 “?” 号

    String sql = selectElement.getText();
    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,"?");
    }
    
  3. Preparedment 对简单参数、对象参数设置值(使用反射获取对象参数的属性)

    // 简单参数
    if (parameter instanceof Integer) {
        for (int i = 1; i <= size; i++) {
            preparedStatement.setInt(i, Integer.parseInt(parameter.toString()));
            return;
        }
    }
    if (parameter instanceof Long) {
        for (int i = 1; i <= size; i++) {
            preparedStatement.setLong(i, Long.parseLong(parameter.toString()));
            return;
        }
    }
    if (parameter instanceof String) {
        for (int i = 1; i <= size; i++) {
            preparedStatement.setString(i, parameter.toString());
            return;
        }
    }
    
    // 对象参数
    Field[] fields = parameter.getClass().getDeclaredFields();
    /*fieldMap:
     *{
     * id:null,
     * name:null,
     * age:10,
     * createTime:null,
     * updateTime:null
     * }
     * */
    /*parameterMap:
     *{
     * 0:age
     * }
     * */
    Map<String, Object> fieldMap = new HashMap<>();
    for (Field field : fields) {
        String name = field.getName();
        field.setAccessible(true);
        Object obj = field.get(parameter);
        field.setAccessible(false);
        fieldMap.put(name, obj);
    }
    for (int i = 1; i <= size; i++) {
        String paramDefine = parameterMap.get(i);
        Object obj = fieldMap.get(paramDefine);
        if (obj instanceof Short) {
            preparedStatement.setShort(i, Short.parseShort(obj.toString()));
            continue;
        }
        if (obj instanceof Integer) {
            preparedStatement.setInt(i, Integer.parseInt(obj.toString()));
            continue;
        }
        if (obj instanceof Long) {
            preparedStatement.setLong(i, Long.parseLong(obj.toString()));
            continue;
        }
        if (obj instanceof String) {
            preparedStatement.setString(i, obj.toString());
            continue;
        }
        // 将java.util.Date 转化为 java.sql.Date
        if (obj instanceof Date) {
            preparedStatement.setDate(i, (java.sql.Date) obj);
        }
    }
    
  4. 将ResultSet对象转为实际返回对象(使用反射调用对象的set方法)

    获取ResultSet元数据、列个数拼接成set + 列名(首字母大写)

    private <T> List<T> resultSet2Obj(ResultSet resultSet, Class<?> clazz) {
        List<T> resultList = new ArrayList<>();
        try {
            ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
            int columnCount = resultSetMetaData.getColumnCount();
            while (resultSet.next()) {
                T object = (T) clazz.newInstance();
                for (int i = 1; i <= columnCount; i++) {
                    Object value = resultSet.getObject(i);
                    String columnName = resultSetMetaData.getColumnName(i);
                    String setMethod = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
                    Method method;
                    if (value instanceof Date) {
                        method = clazz.getMethod(setMethod, Date.class);
                    } else {
                        method = clazz.getMethod(setMethod, value.getClass());
                    }
                    method.invoke(object, value);
                }
                resultList.add(object);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultList;
    }
    

    效果

    @Test
    public void test1() {
        try {
            Reader reader = Resource.parseXmlAsReader("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            User user = sqlSession.selectOne("cn.leilei.IDao.IUserDAO.queryUserInfo");
            logger.info("测试结果:" + JSON.toJSONString(user));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    @Test
    public void test2() {
        try {
            Reader reader = Resource.parseXmlAsReader("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            User user = sqlSession.selectOne("cn.leilei.IDao.IUserDAO.queryUserInfoById",2L);
            logger.info("测试结果:" + JSON.toJSONString(user));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    15:43:23.392 [main] INFO  cn.leilei.ApiTest - 测试结果:{"age":18,"createTime":"2019-12-22T00:00:00","id":1,"name":"水水","updateTime":"2019-12-22T00:00:00"}
    
    Process finished with exit code 0
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值