中介者模式
简单模拟mybatis框架操作数据库核心逻辑来理解中介者模式
核心流程
技术点
-
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() }; }
-
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,"?"); }
-
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); } }
-
将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