MyBatis原理

引子


MyBatis是优秀的半自动ORM框架。

其工作的步骤可以大致分为以下步骤:

  1. 读取配置文件并返回InputStream流对象
  2. 依据InputStream对象,解析出Configuration对象,然后创建SqlSessionFactory工厂对象
  3. 从SqlSessionFactory对象中创建SqlSession
  4. 从SqlSession中调用Excutor执行数据库操作,生成具体的SQL语句
  5. 对执行结果进行处理、封装
  6. 提交事务

以上步骤是初学MyBatis框架时就耳熟能详的,也不是本文的探讨的重点。

本文探讨的是:Dao接口是如何和Mapper文件对应上的呢?

解析


Dao接口没有实现类,那我们执行的时候,它最终是怎样执行SQL语句的呢?

如果了解过Spring代理,就基本上能猜出MyBatis是基于动态代理的。

秘密就在sqlSession.getMapper()中:

//DefaultSqlSession中的getMapper
public <T> T getMapper(Class<T> type) {
    return configuration.<T>getMapper(type, this);
}

//configuration中的给getMapper
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
}

//MapperRegistry中的getMapper
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
	//从MapperRegistry中的HashMap中拿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 {
      // 通过动态代理工厂生成示例。
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
}

//MapperProxyFactory类中的newInstance方法
 public T newInstance(SqlSession sqlSession) {
 	// 创建了JDK动态代理的Handler类
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    // 调用了重载方法
    return newInstance(mapperProxy);
  }

//MapperProxy类,实现了InvocationHandler接口
public class MapperProxy<T> implements InvocationHandler, Serializable {
  
  //省略部分源码	

  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;
  
  // 构造,传入了SqlSession,说明每个session中的代理对象的不同的!
  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }
  
  //省略部分源码
}

//重载的方法,由动态代理创建新示例返回。
protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
 }

简单来说,它就是通过JDK动态代理,返回了一个Dao接口的代理对象,这个代理对象的处理器是MapperProxy对象。所有,我们通过@Autowired注入Dao接口的时候,注入的就是这个代理对象,我们调用到Dao接口的方法时,则会调用到MapperProxy对象的invoke方法。

总结


动态代理返回示例后,我们就可以调用DAO接口中的方法了。

当我们调用Dao接口的方法时候,实际上是调用了动态代理返回的对象invoke方法。

MyBatis通过全限定名+方法名拿到MapperStatement对象,然后通过执行器Executor去执行具体SQL并返回。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值