MyBatis源码学习笔记(三)
之前学习到
DefaultSqlSessionFactory中的
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { final Environment environment = configuration.getEnvironment(); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); final Executor executor = configuration.newExecutor(tx, execType, autoCommit); return new DefaultSqlSession(configuration, executor); } catch (Exception e) { closeTransaction(tx); // may have fetched a connection so lets call close() throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
在此方法中,TransactionFactory依赖于Environment类,Transaction由Transaction Factory生成,Executor依赖于Transaction,最后DefaultSqlSession到业务层使用。
可见Environment作为获取SqlSession的基础,在现在观察到的代码中,Configuration始终贯穿代码之中。
随之查看Environment的源码,
属性只有
private final String id; private final TransactionFactory transactionFactory; private final DataSource dataSource;
Environment依然使用Builder模式。
由此属性看来,Environment关注的是事务类型,还有就是数据源,id使用与区分,参考文档中介绍了可以通过多个Environment实现多数据库的操作。
跟踪Environment的build方式,是由
XMLConfigBuilder中的
private void parseConfiguration(XNode root) { try { propertiesElement(root.evalNode("properties")); //issue #117 read properties first typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); settingsElement(root.evalNode("settings")); environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631 databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }
方法中的environmentsElement(root.evalNode("environments")); 生成Environment的。
private void environmentsElement(XNode context) throws Exception { if (context != null) { if (environment == null) { environment = context.getStringAttribute("default"); } for (XNode child : context.getChildren()) { String id = child.getStringAttribute("id"); if (isSpecifiedEnvironment(id)) { TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager")); DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); DataSource dataSource = dsFactory.getDataSource(); Environment.Builder environmentBuilder = new Environment.Builder(id) .transactionFactory(txFactory) .dataSource(dataSource); configuration.setEnvironment(environmentBuilder.build()); } } } }
来到此处终于找到参考文档中的基本配置要素了!environments元素,transactionManager元素,dataSource元素。
在SqlSessionFactoryBuilder中,
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); return build(parser.parse());
通过输入流,生成XMLConfigBuilder,XMLConfigBuilder的parse方法调用了
parseConfiguration方法设置Congfiguration并返回,并通过SqlSessionFactoyBuilder生成
DefaultSqlSessionFactory(此时SqlSessionFacoty已生成SqlSession)。
至此就完成了SqlSessionFactory生成SqlSession的源码分析了。
算是解答了我之前想到的几个问题了,SqlSessionFactoryBuilder,SqlSessionFacotyBuilder,基本xml的配置。
之后应该要分析一下在这过程中代码中写得优雅的部分。