mybatis之MapperFactoryBean源码解读

  在我们使用mybatis开发dao层的时候,我们可以直接写好dao层接口,然后借助MapperFactoryBean直接代理,这样我们就不需要显示的实现dao接口,刚接触到这个技术点的时候就对这个MapperFactoryBean十分感兴趣,所以在了解了背后的实现机制时,就写下我的所见所得。

  先来看看MapperFactoryBean的继承关系

  

     从类的的继承图中可以看出来实现了FactoryBean,这是一个spring提供的工厂接口,其次继承了SqlSessionDaoSupport,SqlSessionSurpport最顶层实现了InitializingBean,InitializingBean接口定义了afterProper'tiesSet()方法,当一个类实现这个接口,spring容器在初始化一个Bean时,在初始化Bean并设置好相关的属性后就会调用这个方法,我们就可以利用这个接口来实现我们的一些初始化工作。

   在DaoSupport中实现afterPropertiesSet()调用了CheckDaoConfig()

    public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
        this.checkDaoConfig();

        try {
            this.initDao();
        } catch (Exception var2) {
            throw new BeanInitializationException("Initialization of DAO failed", var2);
        }
    }
   所以在MapperFactoryBean中重写了afterPropertiesSet()方法

 protected void checkDaoConfig() {
    super.checkDaoConfig();

    notNull(this.mapperInterface, "Property 'mapperInterface' is required");

    Configuration configuration = getSqlSession().getConfiguration();
    if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
      try {
        configuration.addMapper(this.mapperInterface);
      } catch (Exception e) {
        logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
        throw new IllegalArgumentException(e);
      } finally {
        ErrorContext.instance().reset();
      }
    }
  }

  在Configuration类中添加代理的接口,所以在初始化Bean时,spring通过getObject()获得代理的接口。

 @Override
  public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }

  通过SqlSession获得代理类,我们继续在DefaultSqlSession中查看

 public <T> T getMapper(Class<T> type) {
    return configuration.<T>getMapper(type, this);
 }
  在代码中可以按到代理接口通过SqlSession所对应的Configuration获得,Configuration是一个保存XML文件相关信息的类,与SqlSession绑定。

 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
 }
  Configuration是保存mybatis中XML的信息,要获得接口的代理需要通过MapperRegistry获得

  

 @SuppressWarnings("unchecked")
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    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类,从类名中就可以看出来这是一个代理工厂,最终mapperProxyFactory.newInstance()获得接口的代理

 @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);
  }
  newInstance方法通过new 一个MapperProxy,然后通过JDK中Proxy获得接口的代理,我们知道常用的代理有两种,一种是JDK代理,一种是cglib代理,那么mybatis是使用哪种代理呢?我们可以查看MapperProxy类来看看到底是使用哪种代理

public class MapperProxy<T> implements InvocationHandler, Serializable 
  从代码中可以明确看出来是使用JDK动态代理的,到这里我们就分析完了mybatis的接口自动代理了。




  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值