在使用 MyBatis 时,第一步要做的事情一般是根据配置文件构建 SqlSessionFactory对象。
1 2 3 4
| String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
|
们首先会使用 MyBatis 提供的工具类 Resources加载配置文件,得到一个输入流。然后再通过 SqlSessionFactoryBuilder 对象的 build 方法构建 SqlSessionFactory对象。这里的 build 方法是我们分析配置文件解析过程的入口方法。
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
| // -☆- SqlSessionFactoryBuilder public SqlSessionFactory build(InputStream inputStream) { // 调用重载方法 return build(inputStream, null, null); }
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { // 创建配置文件解析器 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); // 调用 parse 方法解析配置文件,生成 Configuration 对象 return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("……", e); } finally { ErrorContext.instance().reset(); try { inputStream.close(); } catch (IOException e) {……} } }
public SqlSessionFactory build(Configuration config) { // 创建 DefaultSqlSessionFactory return new DefaultSqlSessionFactory(config); }
|
大致可以猜出 MyBatis 配置文件是通过 XMLConfigBuilder 进行解析的
parse 方法
1 2 3 4 5 6 7 8 9 10
| // -☆- XMLConfigBuilder public Configuration parse() { if (parsed) { throw new BuilderException("……"); } parsed = true; // 解析配置 parseConfiguration(parser.evalNode("/configuration")); return configuration; }
|
注意一个 xpath 表达式—— /configuration。这个表达式代表的是 MyBatis 配置文件的 节点,这里通过 xpath 选中这个节点,并传递给 parseConfiguration 方法。
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
| private void parseConfiguration(XNode root) { try { // 解析 properties 配置 propertiesElement(root.evalNode("properties")); // 解析 settings 配置,并将其转换为 Properties 对象 Properties settings = settingsAsProperties(root.evalNode("settings")); // 加载 vfs loadCustomVfs(settings); // 解析 typeAliases 配置 typeAliasesElement(root.evalNode("typeAliases")); // 解析 plugins 配置 pluginElement(root.evalNode("plugins")); // 解析 objectFactory 配置 objectFactoryElement(root.evalNode("objectFactory")); // 解析 objectWrapperFactory 配置 objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); // 解析 reflectorFactory 配置 reflectorFactoryElement(root.evalNode("reflectorFactory")); // settings 中的信息设置到 Configuration 对象中 settingsElement(settings); // 解析 environments 配置 environmentsElement(root.evalNode("environments")); // 解析 databaseIdProvider,获取并设置 databaseId 到 Configuration 对象 databaseIdProviderElement(root.evalNode("databaseIdProvider")); // 解析 typeHandlers 配置 typeHandlerElement(root.evalNode("typeHandlers")); // 解析 mappers 配置 mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("……"); } }
|
到此,一个完整的配置解析过程就呈现出来了,每个节点的的解析逻辑均封装在了相应的方法中。我在分析这些方法时,并不会按照上面代码中所呈现的解析顺序进行分析,而是做了一定的调整。