mybatis的初始化:
sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(Resources.getResourceAsStream("config.xml"));
sqlSession = sqlSessionFactory.openSession();
1.首先,Resources.getResourceAsStream("config.xml")会读取config.xml得到一个输入流,然后调用SqlSessionFactoryBuilder的build方法,共有9个build方法,最终调用的都是build(Configuration)方法,最终得到SQLSessionFactory的实现类defaultSqlSessionFactory对象;
2.现在来看下初始化资源文件的过程:
/**
* 其他的build方法最终都会调用本方法(或是调用输入流是reader的方法,两个方法一样,只是输入流不同)
* @param inputStream
* @param environment
* @param properties
* @return
*/
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//创建XMLConfigBuilder解析配置文件,解析的配置相关信息都会封装为一个Configuration对象
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//parser.parse()返回一个Configuration对象,调用build(Configuration),返回DefaultSessionFactory对象
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
3.我们看一下XMLConfigBuild对象的结构和我们上面的代码调用的方法:
4.我们可以到XMLConfigBuild对象除了构造方法和前面调用的parse(),其他的都是解析Document对象的的节点的方法(形参是XNode),在调用XMLConfigBuild的私有构造方法时,创建了一个Configuration对象,在创建Configuration对象的时候,注册了一些别名信息,代码如下:
</pre><p></p><p><pre name="code" class="java"> /**
* 还有一个输入流是reader的与之对应的方法,在这个方法中:新建的XPathParser对象会把输入流里的内容,也就是mybatis的配置文件读取到自身的成员变量--->一个Document对象上
* @param inputStream
* @param environment
* @param props
* time 2016年10月10日下午2:12:59
* author:wenyi
*/
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
/**
* 其他的构造方法最终都会调用本方法
* @param parser
* @param environment
* @param props
*
*/
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());//将Configuration对象赋给XMLConfigBuilder对象
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);//为Configuration对象注入java代码的properties对象的信息
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
5.初始化Configuration对象
/**
* 在Configuration初始化的将数据库的一些配置信息类的别名注册到java类的别名管理容器
* 注册信息
* time 2016年10月10日下午4:13:12
* author:wenyi
*/
public Configuration() {
//mybatis有两种事物管理机制:JDBC管理事物,MANAGED(Web容器)管理事物
this.typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class.getName());//注册JDBC事物管理工厂的别名
this.typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class.getName());//注册MANAGED事物管理工厂的别名
//mybatis提供了三种连接数据源工厂 DataSourceFactory
this.typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class.getName());//注册jndi的数据源
this.typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class.getName());//注册非连接池方式数据源UnpooledDataSource
this.typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class.getName());//注册连接池方式的数据源PooledDataSource
//注册缓存信息
this.typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class.getName());
this.typeAliasRegistry.registerAlias("FIFO", FifoCache.class.getName());
this.typeAliasRegistry.registerAlias("LRU", LruCache.class.getName());
this.typeAliasRegistry.registerAlias("SOFT", SoftCache.class.getName());
this.typeAliasRegistry.registerAlias("WEAK", WeakCache.class.getName());
this.typeAliasRegistry.registerAlias("VENDOR", VendorDatabaseIdProvider.class.getName());
}
6.当XMLConfigBuilder初始化完成后,加载的信息都绑定到了XmlConfigBuilder上,然后返回到2,执行XMLConfigBuilder的parse方法,将子标签的配置信息解析后映射到Configuration对象:
/**
* 解析document对象的节点信息,返回成员变量Configuration
* @return
* time 2016年10月10日下午5:44:43
* author:wenyi
*/
public Configuration parse() {
if (this.parsed) {//只能加载一次
throw new BuilderException("Each MapperConfigParser can only be used once.");
}
this.parsed = true;
parseConfiguration(this.parser.evalNode("/configuration"));//this.parser.evalNode("/configuration")得到根节点
return this.configuration;
}
/**
* 解析configuration的子节点信息,将解析后的结果映射到Configuration对象
* @param root
* time 2016年10月10日下午5:48:31
* author:wenyi
*/
private void parseConfiguration(XNode root) {
try {
propertiesElement(root.evalNode("properties"));//properties节点的加载资源文件属性和当前文件属性,properties的resource和url属性不能同时存在
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
settingsElement(root.evalNode("settings"));
environmentsElement(root.evalNode("environments"));
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);
}
}
就这样,初始化解析过程就到这里了,mybatis把配置文件里的信息都加载到Configuration对象里,要用的时候找他要就可以了,关于具体的解析过程,请参阅另一篇文章下面来看看下一步:获取sqlSession并执行CRUD操作的过程,前面说过,调用build方法实际上得到的是SqlSessionfactory的实现类DefaultSqlSessionfactory,先看一下他的代码结构:
我们在openSession的时候,实际上又调用了openSessionFromConnection或openSessionFromDataSource,先是产生了事物管理工厂,然后产生的DefaultSqlSession;
/**
*
* @param execType 执行器类型,默认为SIMPLE,执行器类型只有三种:SIMPLE:普通的执行器;REUSE:执行器会重用预处理语句(prepared statements);BATCH:执行器将重用语句并执行批量更新。
* @param level:定义了事物的隔离级别
* @param autoCommit 是否自动提交,默认为false
* @return
* time 2016年10月11日上午10:11:08
* author:wenyi
*/
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
Executor executor = this.configuration.newExecutor(tx, execType, autoCommit);
return new DefaultSqlSession(this.configuration, executor);
} catch (Exception e) {
closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
/**
*
* @param execType 执行器类型,执行器类型只有三种:SIMPLE:普通的执行器;REUSE:执行器会重用预处理语句(prepared statements);BATCH:执行器将重用语句并执行批量更新。
* @param connection
* @return
* time 2016年10月11日上午10:14:45
* author:wenyi
*/
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
try {
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
Transaction tx = transactionFactory.newTransaction(connection);
Executor executor = this.configuration.newExecutor(tx, execType, connection.getAutoCommit());
return new DefaultSqlSession(this.configuration, executor);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if ((environment == null) || (environment.getTransactionFactory() == null)) {
return new ManagedTransactionFactory();
}
return environment.getTransactionFactory();
}