美文网首页
mybatis mapper动态代理原理

mybatis mapper动态代理原理

作者: yk_Kz | 来源:发表于2021-02-26 22:35 被阅读0次

    一:不使用动态代理的情况

        首先看下如果不基于动态代理的mapper(dao)层接口是怎样的,

    dao接口定义:

    public interface SysUserDao {

        public SysUser selectById(Long id);

    }

    impl实现类:

    public class SysUserDaoImpl  implements SysUserDao{

            public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {

            this.sqlSessionFactory = sqlSessionFactory;

        }

        private SqlSessionFactorysqlSessionFactory;

        @Override

        public SysUserselectById(Long id) {

          SqlSession sqlSession =sqlSessionFactory.openSession();

    SysUser user = 

    (SysUser)sqlSession.selectOne("com.wonders.project.system.mapper.SysUserMapper.selectUserById");

    sqlSession.close();

    return user;

        }

    }

    其实就是拿到sqlsession 去调用api。

    demo:

    String resource = "mybatis-configuration.xml";

    Reader reader;

    try {

    reader = Resources.getResourceAsReader(resource);

    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); SysUserDaoImpl sysUserDaoImpl = new SysUserDaoImpl(); sysUserDaoImpl.setSqlSessionFactory(sqlSessionFactory);

    SysUser sysUser = sysUserDaoImpl.selectById(1L);

    System.out.println(sysUser.toString());

    } catch (IOException e) {

    e.printStackTrace();

    }

    二:动态代理的方式

    首先demo的写法:

    String resource = "mybatis-configuration.xml";

    Reader reader;

    try {

    reader = Resources.getResourceAsReader(resource);

    SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);

    SqlSession session = sqlMapper.openSession();

    try {

    SysUserMapper sysUserMapper = session.getMapper(SysUserMapper.class);

    SysUser user = sysUserMapper.selectUserById(1L);

    System.out.println(user.getUserName() + "," + user.getEmail());

    } finally {

    session.close();

    }} catch (IOException e) {

    e.printStackTrace();

    }

    动态代理的实现过程分析

    获取代理对象

    SysUserMapper sysUserMapper = session.getMapper(SysUserMapper.class);

    首先来到:DefaultSqlSession的

    @Override

    public <T> T getMapper(Class<T> type) {

      return configuration.<T>getMapper(type, this);

    }

    交由configuration处理:

    Configuration

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

    再交由MapperRegistry处理

    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); }

    接下来就是熟悉的动态代理创建过程

    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);}

    重点关注MapperProxy的invoke方法

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    try {

    if (Object.class.equals(method.getDeclaringClass())) {

        return method.invoke(this, args);

    } else if (isDefaultMethod(method)) {

    return invokeDefaultMethod(proxy, method, args);

    } } catch (Throwable t) {

    throw ExceptionUtil.unwrapThrowable(t);

    }

    final MapperMethod mapperMethod = cachedMapperMethod(method);

    return mapperMethod.execute(sqlSession, args);

    }

    MapperMethod 的excute方法逻辑主要就是先判断当前方法是执行语句的类型,包括select,update,insert。。。

    然后组装参数,如果是多个参数就放到map中,

    最后执行sqlSession的api方法,组装返回值

    case SELECT:

    if (method.returnsVoid() && method.hasResultHandler()) {

    executeWithResultHandler(sqlSession, args);

    result = null;

    } else if (method.returnsMany()) {

    result = executeForMany(sqlSession, args);

    } else if (method.returnsMap()) {

    result = executeForMap(sqlSession, args);

    } else if (method.returnsCursor()) {

    result = executeForCursor(sqlSession, args);

    } else {

    Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param);

    } break;


    可以看到此处和不使用动态代理的执行逻辑其实是一样的

    以上只是mapper层面动态代理实现过程,具体由这个"com.example.myabtislearn.SysUserMapper.selectUserById" 如何定位到执行sql,我们下次分解

    相关文章

      网友评论

          本文标题:mybatis mapper动态代理原理

          本文链接:https://www.haomeiwen.com/subject/zmfkfltx.html