源码-mybatis-01-SqlSessionFactory创建
0.总概
1.SqlSessionFactory在mybatis只要创建一次;
import com.suntek.vdm.gw.util.AESEncipher; import org.apache.commons.lang.StringUtils; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.*; import java.util.Properties; /** * @author Binglong */ public class MybatisUtils { private static SqlSessionFactory factory=null; /** * 获取SqlSessionFactory,只创建一次 * @return SqlSessionFactory */ private static SqlSessionFactory getSqlSessionFactory() { if (null != factory){ return factory; } synchronized (SqlSessionFactory.class){ factory = getFactory(); } return factory; } private static SqlSessionFactory getFactory() { try { //读取配置文件 Reader reader= Resources.getResourceAsReader("mybatis.xml"); //创建SQLSessionFactory return new SqlSessionFactoryBuilder().build(reader); } catch (Exception e) { e.printStackTrace(); } return null; } }
classpath路径下的mybatis.xml配置文件(以后详解配置文件)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--引入配置--> <properties resource="conf/db.properties"/> <!--sql打印 --> <!--<settings>--> <!--<setting name="logImpl" value="STDOUT_LOGGING"/>--> <!--</settings>--> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="net.sourceforge.jtds.jdbc.Driver"/> <!--<property name="driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>--> <property name="url" value="${url}"/> <!--<property name="username" value="${username}"/>--> <!--<property name="password" value="${password}"/>--> <!--poolMaximumIdleConnections是空闲连接数,就是没有处理请求的连接,默认是5--> <property name="poolMaximumIdleConnections" value="5"/> <!--poolMaximumActiveConnections是最大的活动连接数,活动连接,就是正在与数据库交互的连接,默认是10--> <property name="poolMaximumActiveConnections" value="50"/> <!--<property name="poolPingQuery" value="SELECT 1 FROM VDM_VR_NODE" />--> <!--<property name="poolPingEnabled" value="true" />--> </dataSource> </environment> </environments> <mappers> <mapper resource="com/ned/gw/mapping/UserMapper.xml"></mapper> </mappers> </configuration>
2.SqlSessionFactoryBuilder构建
从上面可以看到,SqlSessionFactory主要是由SqlSessionFactoryBuilder创建,而SqlSessionFactoryBuilder提供了两种方法创建,一种基于Reader,另一种基于InputStream;两种方式都是把配置封装成XMLConfigBuilder,然后通过 new DefaultSqlSessionFactory(config)创建;
有构造方法可以看,也要传入Properties 配置;
package org.apache.ibatis.session; import java.io.*; import java.util.Properties; import org.apache.ibatis.builder.xml.XMLConfigBuilder; import org.apache.ibatis.exceptions.ExceptionFactory; import org.apache.ibatis.executor.ErrorContext; import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory; public class SqlSessionFactoryBuilder { public SqlSessionFactoryBuilder() { } public SqlSessionFactory build(Reader reader, String environment, Properties properties) { SqlSessionFactory var5; try { XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); var5 = this.build(parser.parse()); } catch (Exception var14) { throw ExceptionFactory.wrapException("Error building SqlSession.", var14); } finally { ErrorContext.instance().reset(); try { reader.close(); } catch (IOException var13) { } } return var5; } public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { SqlSessionFactory var5; try { XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); var5 = this.build(parser.parse()); } catch (Exception var14) { throw ExceptionFactory.wrapException("Error building SqlSession.", var14); } finally { ErrorContext.instance().reset(); try { inputStream.close(); } catch (IOException var13) { } } return var5; } public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); } }
3.XMLConfigBuilder解析
a.而XMLConfigBuilder最终把Reader和InputStream都封装成一个XPathParser(从字面上看估计是一个路径解析器);
b.获取到XMLConfigBuilder,还调用了其parse()方法,也就是解析配置文件(解析详情以后分析);
c.最终把所有配置封装在Configuration中,而这个Configuration正是SqlSessioFactory实现类DefaultSqlSessioFactory的重要属性;
值得关注的是这里XMLConfigBuilder创建时Properties props参数
public class XMLConfigBuilder extends BaseBuilder { private boolean parsed; private XPathParser parser; private String environment; private XMLConfigBuilder(XPathParser parser, String environment, Properties props) { super(new Configuration()); ErrorContext.instance().resource("SQL Mapper Configuration"); this.configuration.setVariables(props); this.parsed = false; this.environment = environment; this.parser = parser; } //解析 public Configuration parse() { if (this.parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } else { this.parsed = true; //从配置文件configuration节点作为根节点开始 this.parseConfiguration(this.parser.evalNode("/configuration")); return this.configuration; } } //从这里可以看到,解析是按顺序解析,也就是平时配置文件的标签顺序 private void parseConfiguration(XNode root) { try { this.propertiesElement(root.evalNode("properties")); this.typeAliasesElement(root.evalNode("typeAliases")); this.pluginElement(root.evalNode("plugins")); this.objectFactoryElement(root.evalNode("objectFactory")); this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); this.settingsElement(root.evalNode("settings")); this.environmentsElement(root.evalNode("environments")); this.databaseIdProviderElement(root.evalNode("databaseIdProvider")); this.typeHandlerElement(root.evalNode("typeHandlers")); this.mapperElement(root.evalNode("mappers")); } catch (Exception var3) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3); } } }
public class XPathParser {
private Document document ;
private boolean validation; //是否开启验证
private EntityResolver entityResolver ; //用于加载本地D T D 文件
private Properties variables ; // mybatis.xml 中<propteries> 标签定义的键位对集合
private XPath xpath ; // XPath 对象
}
public class DefaultSqlSessionFactory implements SqlSessionFactory { private final Configuration configuration; ………… }
4.总结
SqlSessionFactory创建过程是把配置文件通过InputStream或Reader两种方式传到SqlSessionFactoryBuilder,然后SqlSessionFactoryBuilder创建一个XMLConfigBuilder,把配置信息放到XMLConfigBuilder中然后调用parse方法进行一系列解析,最终生成一个Configuration,而这个Configuration正式DefaultSqlSessionFactory的唯一属性,也就是把Configuration传入new一个DefaultSqlSessionFactory;
遗留问题
mybaitis.xml解析解析细节;
Configuration类;