MapperXML的解析和注册使用
首先需要定义 SqlSessionFactoryBuilder
工厂建造者模式类,通过入口 IO 的方式对 XML 文件进行解析。当前我们主要以解析 SQL 部分为主,并注册映射器,串联出整个核心流程的脉络。
文件解析以后会存放到 Configuration 配置类中,接下来会看到这个配置类会被串联到整个 Mybatis 流程中,所有内容存放和读取都离不开这个类。如我们在 DefaultSqlSession 中获取 Mapper 和执行 selectOne 也同样是需要在 Configuration 配置类中进行读取操作。
SqlSessionFactoryBuilder 作为整个 Mybatis 的入口,提供建造者工厂,包装 XML 解析处理,并返回对应 SqlSessionFactory 处理类。
通过解析把 XML 信息注册到 Configuration 配置类中,再通过传递 Configuration 配置类到各个逻辑处理类里,包括 DefaultSqlSession 中,这样就可以在获取映射器和执行SQL的时候,从配置类中拿到对应的内容了。
构建SqlSessionFactory建造者工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(Reader reader) { XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder(reader); return build(xmlConfigBuilder.parse()); }
private SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); } }
|
- SqlSessionFactoryBuilder 是作为整个 Mybatis 的入口类,通过指定解析XML的IO,引导整个流程的启动。
- 从这个类开始新增加了 XMLConfigBuilder、Configuration 两个处理类,分别用于解析 XML 和串联整个流程的对象保存操作。接下来会分别介绍这些新引入的对象。
XML 解析处理
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
| /** * xml解析处理 * * @author:zzc * @date: 2022/4/11 */ public class XMLConfigBuilder extends BaseBuilder {
private Element root;
public XMLConfigBuilder(Reader reader) { //1、调用父类初始化 super(new Configuration()); //2、dom4j处理xml 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) { e.printStackTrace(); } return configuration; }
private void mapperElement(Element mappers) throws IOException, DocumentException, ClassNotFoundException { List<Element> mapperList = mappers.elements("mapper"); for (Element e : mapperList) { // 解析处理,具体参考源码 //添加解析sql configuration.addMappedStatement(mappedStatement); }
//注册Mapper映射器 configuration.addMapper(Resources.classForName(namespace)); }
} }
|
- XMLConfigBuilder 核心操作在于初始化 Configuration,因为 Configuration 的使用离解析 XML 和存放是最近的操作,所以放在这里比较适合。
- 之后就是具体的 parse() 解析操作,并把解析后的信息,通过 Configuration 配置类进行存放,包括:添加解析 SQL、注册Mapper映射器。
- 解析配置整体包括:类型别名、插件、对象工厂、对象包装工厂、设置、环境、类型转换、映射器,但目前我们还不需要那么多,所以只做一些必要的 SQL 解析处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
public class BaseBuilder {
protected final Configuration configuration;
public BaseBuilder(Configuration configuration) { this.configuration = configuration; }
public Configuration getConfiguration() { return configuration; } }
|
通过配置类包装注册机和SQL语句
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
|
public class Configuration {
protected MapperRegistry mapperRegistry = new MapperRegistry(this);
protected final Map<String, MappedStatement> mappedStatements = new HashMap<>();
public void addMappers(String packageName) { mapperRegistry.addMappers(packageName); }
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 boolean hasMapper(Class<?> type) { return mapperRegistry.hasMapper(type); }
public void addMappedStatement(MappedStatement ms) { mappedStatements.put(ms.getId(), ms); }
public MappedStatement getMappedStatement(String id) { return mappedStatements.get(id); }
}
|
在配置类中添加映射器注册机和映射语句的存放;
- 映射器注册机是我们上一章节实现的内容,用于注册 Mapper 映射器所提供的操作类。
- 另外一个 MappedStatement 是本章节新添加的 SQL 信息记录对象,包括记录:SQL类型、SQL语句、入参类型、出参类型等。
DefaultSqlSession结合配置项获取信息
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
|
public class DefaultSqlSession implements SqlSession {
private Configuration configuration; public DefaultSqlSession(Configuration configuration) { this.configuration = configuration; }
@Override public <T> T selectOne(String statement) { return (T) ("你被代理了!" + statement); }
@Override public <T> T selectOne(String statement, Object parameter) { MappedStatement mappedStatement = configuration.getMappedStatement(statement); return (T) ("你被代理了!" + "\n方法:" + statement + "\n入参:" + parameter + "\n待执行SQL:" + mappedStatement.getSql()); }
@Override public <T> T getMapper(Class<T> type) { return configuration.getMapper(type, this); }
@Override public Configuration getConfiguration() { return configuration; } }
|
- DefaultSqlSession 相对于上一章节,这里把
MapperRegistry mapperRegistry
替换为 Configuration configuration
,这样才能传递更丰富的信息内容,而不只是注册器操作。 - 之后在 DefaultSqlSession#selectOne、DefaultSqlSession#getMapper 两个方法中都使用 configuration 来获取对应的信息。
- 目前 selectOne 方法中只是把获取的信息进行打印,后续将引入 SQL 执行器进行结果查询并返回。
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
public class ApiTest {
private Logger logger = LoggerFactory.getLogger(ApiTest.class);
@Test public void test_MapperProxyFactory() throws IOException { Reader reader = Resources.getResourceAsReader("mybatis-config-datasource.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); SqlSession sqlSession = sqlSessionFactory.openSession(); IUserDao userDao = sqlSession.getMapper(IUserDao.class); String info = userDao.queryUserInfoById("10001"); logger.info("测试结果:{}", info); } }
|