在使用Mybatis框架时,需要产生SQLSessionFactory类的实例,是通过SQLSessionFactoryBuilder类的实例的build方法来完成。
一、SqlSessions
使用 MyBatis 的主要 Java 接口就是 SqlSession。尽管你可以使用这个接口执行命令,获 取映射器和管理事务。我们会讨论 SqlSession 本身更多,但是首先我们还是要了解如何获取 一个 SqlSession 实例。SqlSessions 是由 SqlSessionFactory 实例创建的。SqlSessionFactory 对 象 包 含 创 建 SqlSession 实 例 的 所 有 方 法 。 而 SqlSessionFactory 本 身 是 由SqlSessionFactoryBuilder 创建的,它可以从 XML 配置,注解或手动配置 Java 来创建 SqlSessionFactory。
二、SqlSessionFactoryBuilder
从图上看SqlSessionFactoryBuilder类负责构建SqlSessionFactory,并且提供了多个build的重载方法,查看源码如下
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}
public SqlSessionFactory build(Reader reader, String environment) {
return build(reader, environment, null);
}
public SqlSessionFactory build(Reader reader, Properties properties) {
return build(reader, null, properties);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment) {
return build(inputStream, environment, null);
}
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return build(inputStream, null, properties);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
分析源码可以看出,配置信息可以分为三种提供给SQLSessionFactory的build方法,分别是InputStream、Reader、 Configuration,由于字节流与字符流都都属于读取配置文件的方法,所以SQLSessionFactoryBuilder可以算是5个Build()方法,每一种都可以从不同的资源中创建一个SqlSession实例。
SqlSessionFactory build(InputStream inputStream) SqlSessionFactory build(InputStream inputStream, String environment) SqlSessionFactory build(InputStream inputStream, Properties properties) SqlSessionFactory build(InputStream inputStream, String env, Properties props) SqlSessionFactory build(Configuration config) |
因此从配置信息的来源可以看出构建一个SQLSessionFactory有两种方式
第一种方法是最常用的使用了一个参照了 XML 文档或上面讨论过的更特定的 mybatis-config.xml 文件的 Reader 实例。 可选的参数是 environment 和 properties。 Environment 决定加载哪种环境,包括数据源和事务管理器。比如
|
如果调用了 一个使用 environment 参数 方 式的 build 方法, 那么 MyBatis 将会使用 configuration 对象来配置这个 environment。 当然, 如果指定了一个不合法的 environment, 你会得到错误提示。 如果调用了其中之一没有 environment 参数的 build 方法, 那么就使用 默认的 environment(在上面的示例中就会指定为 default=”development”)。
如果调用了使用 properties 实例的方法,那么 MyBatis 就会加载那些 properties(属性 配置文件) ,并在配置中可使用它们。那些属性可以用${propName}语法形式多次用在配置文件中。
回想一下,属性可以从 mybatis-config.xml 中被引用,或者直接指定它。因此理解优先 级是很重要的。
如果一个属性存在于这些位置,那么 MyBatis 将会按找下面的顺序来加载它们:
在 properties 元素体中指定的属性首先被读取,
从 properties 元素的类路径 resource 或 url 指定的属性第二个被读取, 可以覆盖已经 指定的重复属性,
作为方法参 数传递 的属性最 后被读 取,可以 覆盖已 经从 properties 元 素体和 resource/url 属性中加载的任意重复属性。
因此,最高优先级的属性是通过方法参数传递的,之后是 resource/url 属性指定的,最 后是在 properties 元素体中指定的属性。
总结一下,前四个方法很大程度上是相同的,但是由于可以覆盖,就允许你可选地指定 environment 和/或 properties。 这里给出一个从 mybatis-config.xml 文件创建 SqlSessionFactory 的示例:
String resource = "org/mybatis/builder/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(inputStream); |
这里使用了Resource工具类,这个类在 org.mybatis.io 包中,Resource类会帮助我们从类路径下、文件系统或一个web URL加载资源文件,看一下这个类,如下简表
URL getResourceURL(String resource) URL getResourceURL(ClassLoader loader, String resource) InputStream getResourceAsStream(String resource) InputStream getResourceAsStream(ClassLoader loader, String resource) Properties getResourceAsProperties(String resource) Properties getResourceAsProperties(ClassLoader loader, String resource) Reader getResourceAsReader(String resource) Reader getResourceAsReader(ClassLoader loader, String resource) File getResourceAsFile(String resource) File getResourceAsFile(ClassLoader loader, String resource) InputStream getUrlAsStream(String urlString) Reader getUrlAsReader(String urlString) Properties getUrlAsProperties(String urlString) Class classForName(String className) |
XML文件构造方式的build方法的源码
|
最后一个 build 方法使用了一个 Configuration 实例。configuration 类包含可能需要了解 SqlSessionFactory 实例的所有内容。Configuration 类对于配置的自查很有用,包含查找和 操作 SQL 映射。手动配置 configuration 实例,然后将它传递给 build()方法来创建 SqlSessionFactory。
DataSource dataSource = BaseDataTest.createBlogDataSource(); TransactionFactory transactionFactory = new JdbcTransactionFactory(); Environment environment = new Environment("development", transactionFactory, dataSource); Configuration configuration = new Configuration(environment); configuration.setLazyLoadingEnabled(true); configuration.setEnhancementEnabled(true); configuration.getTypeAliasRegistry().registerAlias(Blog.class); configuration.getTypeAliasRegistry().registerAlias(Post.class); configuration.getTypeAliasRegistry().registerAlias(Author.class); configuration.addMapper(BoundBlogMapper.class); configuration.addMapper(BoundAuthorMapper.class); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(configuration); |
编写构造方式的build方法源码如下(基于xml的构造方式的build(parser.parse())最终也是调了这个代码)
public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); } |
其实这么看来SqlSessionFactory在mybatis的默认实现类为org.apache.ibatis.session.defaults.DefaultSqlSessionFactory , 其构造过程主要是注入了Configuration的实例对象,Configuration的实例对象即可通过解析xml配置文件产生,也可能通过代码直接构造。