Mybatis面试题

为什么就能直接调用userMapper接口的方法?

测试代码:

package org.apache.ibatis.zytest;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.Reader;

/**
 * <p>Desription: </p>
 *
 * @Author: 罗志远
 * @Date: 2021/8/26 0:31
 * @ProjectName: mybatis
 * @Package: org.apache.ibatis.zytest
 * @ClassName: MyTest
 * @Version: 1.0
 */
public class MyTest {

  private static SqlSessionFactory sqlSessionFactory;

  @Test
  public void test01() throws IOException {
    //1、创建SqlSessionFactory
    String resource = "org/apache/ibatis/zytest/mybatis-config.xml";
    final Reader reader = Resources.getResourceAsReader(resource);
    sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
    reader.close();
    //2、获取sqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //3、获取mapper
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    //4、执行数据库操作,并处理结果集
    User user = mapper.selectById("1", 25);
    System.out.println(user);
  }
}

重点代码:

 //3、获取mapper
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

在这里插入图片描述

问题1:getMapper返回的是个什么对象?
1.首先默认调用的是DefaultSqlSession的getMapper方法。

在这里插入图片描述

2.通过调用Configuration的getMapper方法。

在这里插入图片描述

3.继续调用MapperRegistry的getMapper方法。

在这里插入图片描述

  // 已知的所有映射
  // key:mapperInterface,即dao的数据库接口,不是方法
  // value:MapperProxyFactory,即映射器代理工厂
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();

这里就可以拿到动态代理对象工厂。
往MapperRegistry添加动态代理对象工厂的方法:addMapper
在这里插入图片描述
MapperProxyFactory对象里保存了mapper接口的class对象。

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

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

2.工厂模式getMapper()。

给映射接口类创建动态代理对象是在MapperProxyFactory实现。
在这里插入图片描述

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

在这里插入图片描述

getMapper方法返回的是一个JDK动态代理对象(类型是$Proxy+数字)。这个代理对象会继承Proxy类,实现被代理的接口UserMpper,里面持有了一个MapperProxy类型的触发管理类。
当我们调用UserMpper的方法时候,实质上调用的是MapperProxy的invoke方法。

在这里插入图片描述
为什么要在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类)中就可以完成了,其实也就没有必要在用实现类了。

总结

本文中主要是讲getMapper方法,该方法实质上是获取一个JDK动态代理对象(类型是Proxy+数字),这个代理类会继承MapperProxy类,实现被代理的接口UserMapper,并且里面持有一个MapperProxy类型的触发管理类。这里我们就拿到代理类了,后面我们就可以使用这个代理对象进行方法调用。

问题涉及到的设计模式:

1.代理模式。

2.工厂模式。

3.单例模式。

整个流程图:
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值