Mybatis只有接口没有实现类的原理

一、问题背景

mybaits相对于Ibatis的一大区别就是,不用自己写接口实现类。Ibatis的实现类十几年来做着重复的工作,拼接statementId,然后执行sql。十分没有营养的代码。mybaits干脆不用手工写实现类了,框架帮我们完成了这件事情。

二、实现原理

mybatis使用了动态代理技术生成实现类。动态代理的具体手段有两种:jdk自带和cglib。

动态代理技术对比 jdk自带 cglib
是否需要声明接口 需要 不需要
是否需要实现类 不需要 需要

虽然都是生成字节码新类,但是cglib的字节码新类需要继承实现类。对于mybatis只有接口的场景,当然选择jdk自带的动态代理。

三、源码分析

mybatis动态代理两个核心类

org.apache.ibatis.binding.MapperProxy
org.apache.ibatis.binding.MapperProxyFactory
  • MapperProxy作用
public class MapperProxy<T> implements InvocationHandler, Serializable {
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    ... ...
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }
}

这个类实现了代理拦截器方法,也就意味着,新生成的所有代理类的方法都会走这个invoke方法里的逻辑。invoke方法最后一行做了什么呢?

  1. 拼接statementID
  2. 执行sql
  3. 返回结果

这不正是之前写Ibatis接口实现类的时候,天天重复写的代码吗?

  • MapperProxyFactory 作用
public class MapperProxyFactory<T> {

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

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

}

MapperProxyFactory是代理工厂类,根据传入的DAO的接口,生成对应实现的动态代理类。每个接口一个动态代理实现类,于是乎,再也不用写Ibatis的那些冗余的。

四、结语

mybatis设计的很巧妙,把重复的实现用一个动态代理的拦截器进行去重。很高级的duplicate code重构技巧。一个好的架构,可以节省开发同学的时间。

你可能感兴趣的:(Java框架,DataBase)