Mapper接口

来源:互联网 发布:万达怎么了 知乎 编辑:程序博客网 时间:2024/05/26 07:30

title:Mapper接口
date:2017年11月25日17:27:07
categories: Mybatis


前言

之前在说到Mybatis插件的时候说以后要好好分析下Mybatis的四大组件,之前一直在为公司忙搭建RocketMQ消息集群的事情,就耽误了一段时间,最近终于有时间来分析下了,要分析四大组件,还是要从一次完整的查询过程说起,把Mybatis的核心源码都过一遍。

从一次查询说起

我们做一次Mybatis的查询测试

    @Test    public void testSelect() {        SqlSession session = null;        try {            session = MybatisUtil.getCurrentSession();            UserDao userDao = session.getMapper(UserDao.class);            List<Integer> list = new ArrayList<Integer>();            list.add(1);            list.add(3);            list.add(25);            List<User> userList = userDao.queryList(list);            System.out.println(JSON.toJSONString(userList));        } catch (Exception e) {            // TODO: handle exception        } finally {            if (session != null)                session.close();        }    }

对应的Mapper配置文件

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.wangcc.mybatis.dao.UserDao"><resultMap type="User" id="UserMapper"><result property="id" column="t_id"/><result property="name" column="t_name"/></resultMap><select id="queryList" resultMap="UserMapper">select * from t_user where t_id in <foreach collection="list" item="uId" index="index" open="(" separator="," close=")">#{uId}</foreach></select><insert id="insert" parameterType="User">insert into t_user (t_name,address) values(#{name},#{address})</insert><insert id="batchInsert" >insert into t_user (t_name,address) values <foreach collection="list" item="user" separator=",">(#{user.name},#{user.address})</foreach></insert></mapper>

如果你是初次使用Mybatis,那么你一定会好奇为什么这里的UserDao都是接口并不是具体的实现类。

而如果你熟悉JDK动态代理,那么一看到这种接口可以直接执行方法的情况,那么肯定是用了代理,那么虽然我们能够知道为什么可以直接执行,但是我们也要了解他具体是怎么实现的。我们就以

            UserDao userDao = session.getMapper(UserDao.class);

为Debug入口。

进入getMapper方法

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

我们发现还是调用了构建SqlSession的最重要的对象Configuration的方法。

DefaultSqlSession对象中保存着Configuration对象的引用。

进入到Configuration中

  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {    return mapperRegistry.getMapper(type, sqlSession);  }

我们发现是调用的MapperRegistry对象(Configuration保存着其引用,在初始化Mybatis的配置文件的时候,就会将所有的Mapper接口注册到MapperRegistry的Map\

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {  //在knownMappers中查找是否已经注册了,如果没有注册直接抛出异常,注册Mapper接口是在初始化Mybatis配置文件时必须就要完成的工作,不能在调用getMapper的时候再动态去注册    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);    }  }

进入newInstance方法

  public T newInstance(SqlSession sqlSession) {    //封装了一个MapperProxy对象,即组合模式,为了解耦,我们一般能不用继承就不用继续,尽量使用组合,这里MapperProxy是实现了InvocationHandler接口的类    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);    return newInstance(mapperProxy);  }

newInstance(mapperProxy) 得到Mapper接口的代理对象

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

到现在,如何得到Mapper接口的代理对象的流程就走完了

原创粉丝点击