MyBatis上层接口使用简单工厂模式,核心接口为org.apache.ibatis.session.SqlSession。其中定义了与数据相关的所有操作,以及和MyBatis本身相关的几个方法,比如getConfiguration和getMapper。下图列出了部分常用方法:
从上面的类图中可以看出,SqlSession已经覆盖了DAO模式中的所有方法。因为是ORM框架,所以都是包装方法。但如果在特殊情况下,一定要用JDBC原始java.sql.Connection接口的话,SqlSession中也提供了getConnection这个方法来获取。可以想象,这只有在很特别的情况下才会用到,因为此后,你对java.sql.Connection所做的任何操作都与MyBatis无关了,它提供的所有功能也因此不再有效,如事务等,都需要自己手动来管理了。
上面提到,MyBatis的上层核心接口是SqlSession,因此,上层的其它接口和类,均围绕它展开。下面从一个中的经典API例子开始,引出这几个重要的类。
- String evironment = "development";
- InputStream is = getClass().getResourceAsStream("/SqlMapperConfig.xml");
- SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
- SqlSessionFactory factory = factoryBulider.bulid(is,evironment);
- SqlSession session = factory.openSession();
- String selectId = "test.foo";
- Object bean = session.selectOne(selectdId);
- session.close;
这是一个简单的查询,涉及到下面这几个类,它们是使用的MyBatis的入口:
- org.apache.ibatis.session.SqlSessionFactoryBuilder : SQL会话工厂的构建类
- org.apache.ibatis.session.SqlSessionFactroy : 打开一个SQL会话的工厂类
- org.apache.ibatis.session.SqlSession : SQL会话本身
- org.apache.ibatis.session.Configuration : 整个MyBatis的配置
似乎有点太简单了
,其实不然,这只是入口。关键的地方是SqlSessionFactory这个接口的实例是如何被创建出来的呢?显然答案就在SqlSessionFactoryBuilder这个默认实用类中。另外,org.apache.ibaits.session.Configuration这个类是怎么冒出来的呢?答案也在SqlSessionFactoryBuilder的实现代码里,那还等什么,源码List出来吧:
- 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 props) {
- try {
- XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, props);
- 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);
- }
- }
从它的类签名和构造方法签名就可以看出,这个类是即用即扔的,正好与
MyBatis源码赏析一中提到的生命周期相吻合。这个类只有一个方法,就是build。build方法被重载(overide)了多次,可分为三组:
- 通过指定org.apache.ibais.session.Configuration来构建DefaultSqlSessionFactory
- 从一个Reader中加载Configuration,并构建SqlSessionFactory
- 从一个Stream中加载Configuration,并构建SqlSessionFactory
2和3又被重载了多次,但最终,这两类build方法的任务都是从不同的源加载配置,而SqlSessionFactory具体的构建过程,则委托给1类这个build方法。由此可见,SqlSessionFactoryBuilder这个类,其实也没做什么,只是从不同的源加载配置,为编程提供入口。而具体的加载过程都委托给了其它类。
从SqlSessionFactoryBuilder中构建出来的工厂实现类,都是DefaultSqlSessionFactory,这是MyBatis默认的SqlSessionFactory接口的实现类,也是唯一一个真实的实现类,在本文的版本中(3.0.6),还有另外一个实现类:SqlSessionManager,但它并不是一个功能上的实现类,而是对SqlSession在实际应用开发过程中的实用工具类。因此,现在的重点落在了DefaultSqlSessionFactory类。SqlSessionFactory的功能是负责打开一个连接会话,该接口只定义了两个方法如下:
- public interface SqlSessionFactory {
- SqlSession openSession();
- SqlSession openSession(boolean autoCommit);
- SqlSession openSession(Connection connection);
- SqlSession openSession(TransactionIsolationLevel level);
- SqlSession openSession(ExecutorType execType);
- SqlSession openSession(ExecutorType execType, boolean autoCommit);
- SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
- SqlSession openSession(ExecutorType execType, Connection connection);
- Configuration getConfiguration();
- }
可以看出,主要就是openSession方法,通过重载多次,来得到不同的会话特性。再看看DefaultSqlSessionFactory是如何实现openSession这个方法的。这儿就不贴出源码了,所有的openSession方法最终通过转调两个方法来实现的,分别是openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level,
boolean autoCommit)和openSessionFromConnection(ExecutorType execType, Connection connection),这样做显然是因为SqlSessionFactory接口的openSession方法签名就被这样分成了两类,FromDataSource这一类的,显然是通过DataSource来获取java.sql.Connection的,FromConnection则是直接指定Connection的。这里我们可以看出,这样做的目的在最高层提供了灵活性,也是手工编程的入口。虽然我们实际开发过程中,都是通过配置xml的方式来使用MyBatis的。但了解到这些后,为我们自己扩展MyBatis提供了入口。
现在还剩下一个问题,前面提到的几个高层接口都找到了相应的实现类,那SqlSession呢?它的实现类是什么?当然你用Eclipse或是NetBeans这些高级IDE可以一下子找到,不过,我们这儿另辟溪径。我们知道,一个SqlSession的实例是这样得到的:SqlSessionFactoryBuilder.build(...).openSession(...);而build方法返回的是DefaultSqlSessionFactory实现类,查看一下这它的openSession方法不就知道了么。是的,如前段所述,最终我们可以在openSessionFromDataSource和openSessionFromConnection这两个方法中找到,得到的SqlSession实现类是org.apache.ibatis.session.defaults.DefaultSqlSession。再进入到该类中,在这儿,我们就快要接近真相(我们想知道,SqlSession的CRUD操作是如何实现的)了。其实,具体CRUD操作,都委托给了org.apache.ibaits.executors.Executor接口了。DefaultSqlSession只是为Executor提供执行参数和环境,是一个管理者,下面是它开头的部分源码:
- public class DefaultSqlSession implements SqlSession {
- private Configuration configuration;
- private Executor executor;
- private boolean autoCommit;
- private boolean dirty;
- public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
- this.configuration = configuration;
- this.executor = executor;
- this.autoCommit = autoCommit;
- this.dirty = false;
- }
- ....
- }
可以看出,它主要管理维护两个类实例,分别是Executor和Configuration。顾名思义,前者负责执行,后者负责提供数据,而SqlSession本身则身负将二者关联起来,加以管理。
通过前面的分析,我们大致可以得到MyBatis一个粗略的上层架构类图:
阅读(5137) | 评论(0) | 转发(0) |