千家信息网

直接调用userMapper接口的方法是什么

发表于:2026-11-04 作者:千家信息网编辑
千家信息网最后更新 2026年11月04日,本篇内容主要讲解"直接调用userMapper接口的方法是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"直接调用userMapper接口的方法是什么"
千家信息网最后更新 2026年11月04日直接调用userMapper接口的方法是什么

本篇内容主要讲解"直接调用userMapper接口的方法是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"直接调用userMapper接口的方法是什么"吧!

老规矩,先上案例代码,这样大家可以更加熟悉是如何使用的,看过Mybatis系列的小伙伴,对这段代码差不多都可以背下来了。

哈哈~,有点夸张吗?不夸张的,就这行代码。

public class MybatisApplication {         public static final String URL = "jdbc:mysql://localhost:3306/mblog";         public static final String USER = "root";         public static final String PASSWORD = "123456";              public static void main(String[] args) {             String resource = "mybatis-config.xml";             InputStream inputStream = null;             SqlSession sqlSession = null;             try {                 inputStream = Resources.getResourceAsStream(resource);                 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);                 sqlSession = sqlSessionFactory.openSession();                 //今天主要这行代码                 UserMapper userMapper = sqlSession.getMapper(UserMapper.class);                 System.out.println(userMapper.selectById(1));                  } catch (Exception e) {                 e.printStackTrace();             } finally {                 try {                     inputStream.close();                 } catch (IOException e) {                     e.printStackTrace();                 }                 sqlSession.close();             }         }

看源码有什么用?

通过源码的学习,我们可以收获Mybatis的核心思想和框架设计,另外还可以收获设计模式的应用。

前两篇文章我们已经Mybatis配置文件解析到获取SqlSession,下面我们来分析从SqlSession到userMapper:

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

前面那篇文章已经知道了这里的sqlSession使用的是默认实现类DefaultSqlSession。所以我们直接进入DefaultSqlSession的getMapper方法。

//DefaultSqlSession中   private final Configuration configuration; //type=UserMapper.class @Override public  T getMapper(Class type) {   return configuration.getMapper(type, this); }

这里有三个问题:

问题1:getMapper返回的是个什么对象?

上面可以看出,getMapper方法调用的是Configuration中的getMapper方法。然后我们进入Configuration中

//Configuration中   protected final MapperRegistry mapperRegistry = new MapperRegistry(this); ////type=UserMapper.class public  T getMapper(Class type, SqlSession sqlSession) {     return mapperRegistry.getMapper(type, sqlSession); }

这里也没做什么,继续调用MapperRegistry中的getMapper:

//MapperRegistry中 public class MapperRegistry {   //主要是存放配置信息   private final Configuration config;   //MapperProxyFactory 的映射   private final Map, MapperProxyFactory> knownMappers = new HashMap<>();    //获得 Mapper Proxy 对象   //type=UserMapper.class,session为当前会话   public  T getMapper(Class type, SqlSession sqlSession) {     //这里是get,那就有add或者put     final MapperProxyFactory mapperProxyFactory = (MapperProxyFactory) 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);     }   }      //解析配置文件的时候就会调用这个方法,   //type=UserMapper.class   public  void addMapper(Class type) {     // 判断 type 必须是接口,也就是说 Mapper 接口。     if (type.isInterface()) {         //已经添加过,则抛出 BindingException 异常         if (hasMapper(type)) {             throw new BindingException("Type " + type + " is already known to the MapperRegistry.");         }         boolean loadCompleted = false;         try {             //添加到 knownMappers 中             knownMappers.put(type, new MapperProxyFactory<>(type));             //创建 MapperAnnotationBuilder 对象,解析 Mapper 的注解配置             MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);             parser.parse();             //标记加载完成             loadCompleted = true;         } finally {             //若加载未完成,从 knownMappers 中移除             if (!loadCompleted) {                 knownMappers.remove(type);             }         }     } } }

MapperProxyFactory对象里保存了mapper接口的class对象,就是一个普通的类,没有什么逻辑。

在MapperProxyFactory类中使用了两种设计模式:

  1. 鸿蒙官方战略合作共建--HarmonyOS技术社区

  2. 单例模式methodCache(注册式单例模式)。

  3. 工厂模式getMapper()。

继续看MapperProxyFactory中的newInstance方法。

public class MapperProxyFactory {       private final Class mapperInterface;       private final Map methodCache = new ConcurrentHashMap<>();            public MapperProxyFactory(Class mapperInterface) {         this.mapperInterface = mapperInterface;       }      public T newInstance(SqlSession sqlSession) {       //创建MapperProxy对象       final MapperProxy mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);       return newInstance(mapperProxy);     }     //最终以JDK动态代理创建对象并返回      protected T newInstance(MapperProxy mapperProxy) {         return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);     }     }

从代码中可以看出,依然是稳稳的基于 JDK Proxy 实现的,而 InvocationHandler 参数是 MapperProxy 对象。

//UserMapper 的类加载器 //接口是UserMapper //h是mapperProxy对象 public static Object newProxyInstance(ClassLoader loader,                                           Class[] interfaces,                                        InvocationHandler h){ }

问题2:为什么就可以调用他的方法?

上面调用newInstance方法时候创建了MapperProxy对象,并且是当做newProxyInstance的第三个参数,所以MapperProxy类肯定实现了InvocationHandler。

进入MapperProxy类中:

//果然实现了InvocationHandler接口   public class MapperProxy implements InvocationHandler, Serializable {        private static final long serialVersionUID = -6424540398559729838L;     private final SqlSession sqlSession;     private final Class mapperInterface;     private final Map methodCache;        public MapperProxy(SqlSession sqlSession, Class mapperInterface, Map methodCache) {       this.sqlSession = sqlSession;       this.mapperInterface = mapperInterface;       this.methodCache = methodCache;     }     //调用userMapper.selectById()实质上是调用这个invoke方法     @Override     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {       try {         //如果是Object的方法toString()、hashCode()等方法           if (Object.class.equals(method.getDeclaringClass())) {           return method.invoke(this, args);         } else if (method.isDefault()) {           //JDK8以后的接口默认实现方法             return invokeDefaultMethod(proxy, method, args);         }       } catch (Throwable t) {         throw ExceptionUtil.unwrapThrowable(t);       }       //创建MapperMethod对象       final MapperMethod mapperMethod = cachedMapperMethod(method);       //下一篇再聊       return mapperMethod.execute(sqlSession, args);     }   }

也就是说,getMapper方法返回的是一个JDK动态代理对象(类型是$Proxy+数字)。这个代理对象会继承Proxy类,实现被代理的接口UserMpper,里面持有了一个MapperProxy类型的触发管理类。

当我们调用UserMpper的方法时候,实质上调用的是MapperProxy的invoke方法。

userMapper=$Proxy6@2355。

为什么要在MapperRegistry中保存一个工厂类?

原来他是用来创建并返回代理类的。这里是代理模式的一个非常经典的应用。

MapperProxy如何实现对接口的代理?

JDK动态代理

我们知道,JDK动态代理有三个核心角色:

  • 被代理类(即就是实现类)

  • 接口

  • 实现了InvocationHanndler的触发管理类,用来生成代理对象。

被代理类必须实现接口,因为要通过接口获取方法,而且代理类也要实现这个接口。

而Mybatis中并没有Mapper接口的实现类,怎么被代理呢?它忽略了实现类,直接对Mapper接口进行代理。

MyBatis动态代理:

在Mybatis中,JDK动态代理为什么不需要实现类呢?

这里我们的目的其实就是根据一个可以执行的方法,直接找到Mapper.xml中statement ID ,方便调用。

最后返回的userMapper就是MapperProxyFactory的创建的代理对象,然后这个对象中包含了MapperProxy对象,

问题3:到底是怎么根据Mapper.java找到Mapper.xml的?

最后我们调用userMapper.selectUserById(),本质上调用的是MapperProxy的invoke()方法。

请看下面这张图:

如果根据(接口+方法名找到Statement ID ),这个逻辑在InvocationHandler子类(MapperProxy类)中就可以完成了,其实也就没有必要在用实现类了。

到此,相信大家对"直接调用userMapper接口的方法是什么"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

方法 代理 接口 对象 动态 模式 代码 就是 问题 配置 三个 时候 学习 设计 也就是 也就是说 内容 参数 实质 工厂 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 上海睿民互联网科技有限公司 重生之互联网科技帝国 互联网科技深圳 互联网科技会 互联网扶贫科技 互联网科技作文 互联网科技小额贷款 郑州华宇互联网科技 互联网科技有限公司 翻译 互联网汽车科技小镇 新华互联网科技2019 佛山市翊博互联网络科技有限公司 为客找房互联网科技公司怎么样 滨湖区互联网智能科技产品有哪些 梅州GM互联网络科技有限公司 图游互联网科技 互联网科技包装股份有限公司上市 互联网科技企业商标注意事项 第三届互联网大会安防黑科技 互联网高科技绘画 苏州找大状互联网科技有限公司 互联网科技英文翻译 开启互联网科技时代小说 新兴科技互联网创新大赛颁奖典礼 互联网科技和信息 华夏恒生互联网科技013171 企晟互联网信息科技有限公司 云南互联网科技学费 玉溪新华互联网科技怎么选 武汉亿视互联网科技有限公司
0