Mybatis源码分析(一)

mybatis源码

1、回顾JDBC

1.1 jdbc执行流程

Mybatis源码分析(一)
实现代码:

/*第一步,获取连接*/
Connection connection = DriverManager.getConnection(JDBC.URL,JDBC.USER,JDBC.PASSWORD);
/*第二步,预编译SQL*/
PreparedStatement statement = connection.prepareStatment("SELECT * FROM USER");
/*第三步,执行SQL*/
ResultSet resultSet = statement.executeQuery(statement);
/*第四步,获取结果集*/
readResultSet(resultSet);

1.2 SqlSessionFactory & SqlSession

1.2.1 获取SqlSession

Mybatis源码分析(一)

1.2.1.1 源码解析

  1. SqlSessionFactoryBuilder.build();

public class SqlSessionFactoryBuilder {

  public SqlSessionFactory build(Reader reader) {
    /**调用内部build方法*/
    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);
  }
}
  1. SqlSessionFactoryBuilder内部build()一个DefaultSqlSessionFactory
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      /**解析XML解析器*/
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      /**parser.parse() 获取Configuration,build一个DefaultSqlSessionFactory*/ 
      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(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }
}
  1. 获取到SqlSessionFactory后通过SqlSessionFactory获取SqlSession对象
/**SqlSessionFactory对象中的openSession方法最终都会调用openSessionFromDataSource方法*/
 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      //通过Configuration获取mybatis的配置信息
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      //结合JDBC的执行流程来看 与数据库相互是statement对象,实际上executor是对于statement的封装,也就是说executor是statement的一个执行器
      final Executor executor = configuration.newExecutor(tx, execType);
      // 重点!!   创建了一个DefaultSqlSession对象
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } 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();
    }
  }
  1. 通过以上步骤,我们已经获取到了一个SqlSession,按照JDBC的步骤来说我们应该去执行sql了,结合以下Demo理解
SqlSessionFactory sqlSessionFactory = new SqlSessionFactory();
String resource = "classpath:mybatis-config.xml"
try{
	//SqlSessionFactoryBuilder读取配置文件
	sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource));
} catch(IOException e){
	e.printStackTrace();  
}
//获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession()

1.3 MapperProxy

  1. 到目前为止我们写的.mapper文件还没有使用!!!,下面介绍 MapperPorxy
    Mybatis源码分析(一)
    在mybatis中我的写的dao层的接口其实是MapperProxy在代理,也就是说我们在执行dao层中的方法是,其实是在执行MapperProxy
  2. 我们通过SqlSession从Configuration中找到一个getMapper方法
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  	// mapperRegistry是什么?见名知意 应该是mapper注册机之类的东西,接着往下走看看这个mapperRegister是什么
    return mapperRegistry.getMapper(type, sqlSession);
  }
  1. 我们看下MapperRegistry是什么
// MapperRegistry实际上就是一个注册机用来调用MapperProxyFactory工厂的
public class MapperRegistry {
	
  private final Configuration config;
  //
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();

  public MapperRegistry(Configuration config) {
    this.config = config;
  }

  @SuppressWarnings("unchecked")
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // 这里定了一个MapperProxyFactory的工厂
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      //代理工厂的实例 返回了一个mapper的代理对象工厂的实例,这是不是就是我们想要的dao层对象呢?我们继续往下看MapperProxyFactory
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
}
  1. MapperProxyFactory的作用是什么
/**部分代码*/
public class MapperProxyFactory<T> {
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();

  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  public Class<T> getMapperInterface() {
    return mapperInterface;
  }

  public Map<Method, MapperMethodInvoker> getMethodCache() {
    return methodCache;
  }

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    //!!!重点来了 这里代理到了我们写的Dao层接口
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

}

通过以上的动态代理就可以获取到我们的Dao层

//获取Dao对象
TestDao dao = sqlSession.getMapper(TestDao.class);
有个疑问,我们定义的Dao是接口(Interface),按理说接口是不能实例对象的,那我们这个对象是怎么得到的呢?
	答:建议补习java的动态道理,划重点-->Proxy.newProxyInstance()  AOP也是基于动态代理实现的!

1.4 Excutor

  1. 到这里我们获取到了SqlSession 和 我们的mapper接口,那接下来应该做什么呢? 没错! 执行SQL ,我们去看下真正的SQL执行流程

源码交流群 8671577531

下节讲

上一篇:SSM-Mybatis-生命周期


下一篇:mybatis多数据源配置