• Mybatis为何接口不做实现也能执行sql?


    //创建sqlsession以后获取mapper调用方法执行sql
    EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
                List<Employee> all = employeeMapper.getAll();
    

    但是上面的Mapper接口并没有实现类,那么为何最终能获取到结果呢,其实挺明显就是动态代理,接下来debug看代理类的生成和调用过程

    DefaultSqlSession.class
    
     public <T> T getMapper(Class<T> type) {
            return this.configuration.getMapper(type, this);
        }
    
    Configuration.class
    
      public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return mapperRegistry.getMapper(type, sqlSession);
      }
      
    MapperRegistry.class
    
      public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
      //检查是否扫描到了该接口,所以要注意<mapper namespace="mapper.EmployeeMapper">中内容,特别注意package名也加上
        final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
        if (mapperProxyFactory == null) {
          throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        }
        try {
          //最终是代理工厂创建mapper
          return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception e) {
          throw new BindingException("Error getting mapper instance. Cause: " + e, e);
        }
      }
      
      //创建代理类
        public T newInstance(SqlSession sqlSession) {
        final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
        return newInstance(mapperProxy);
      }
    

    从名字也可以看出来,MapperProxy就是mapper接口的代理类,点进去果不其然

    //JDK动态代理
    public class MapperProxy<T> implements InvocationHandler, Serializable {
    
      private static final long serialVersionUID = -6424540398559729838L;
      private final SqlSession sqlSession;
      private final Class<T> mapperInterface;
      //缓存MapperMethod,这是封装sql操作的类
      private final Map<Method, MapperMethod> methodCache;
    
    ...
    
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //Object类的方法直接调
        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);
      }
    
      private MapperMethod cachedMapperMethod(Method method) {
        MapperMethod mapperMethod = methodCache.get(method);
        if (mapperMethod == null) {
          //如果还没调用过,生成MapperMethod并且缓存
          mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
          methodCache.put(method, mapperMethod);
        }
        return mapperMethod;
      }
      
      接下来就是command执行过程
    MapperMethod.class
       public Object execute(SqlSession sqlSession, Object[] args) {
    
    DefaultSqlSession
        selectOne/selectMap...对应方法
    Executor
         ...对应方法
    
    

    总结:
    mybatis先扫描配置类和mapper接口文件,生成保存配置和mapper信息的Configuration和MapperRegistry,在实际调用中利用jdk动态代理把执行交给 SqlSession对应方法。

  • 相关阅读:
    sql2005新特性 for xml , outer apply ,多行转成单列方法
    数据库备份还原到指定时间
    在 64 位版本的 Windows 上,如何在 32 位版本的 ASP.NET 1.1 和 64 位版本的 ASP.NET 2.0 之间切换
    人事管理系统的一般功能需求
    转支持非主键排序的SQL存储过程
    正则表达式删除指定的HTML 标签
    PAZU 4Fang WEB 打印控件
    ASP.NET木马及Webshell安全解决方案
    vue3+element 父组件子组件传值
    彻底理解01背包问题
  • 原文地址:https://www.cnblogs.com/CodeSpike/p/13729958.html
Copyright © 2020-2023  润新知