mybatis系列之mapper接口

简介: hello~各位读者好,我是鸭血粉丝(大家可以称呼我为「阿粉」)。今天,阿粉带着大家来了解一下 mybatis 接口的创建。

1.上期回顾

首先,我们还是回顾一下上篇文件的类容。先看下这个测试类,大家还有印象吗:

public class MybatisTest {
    @Test
    public void testSelect() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = sqlSessionFactory.openSession();
        try {
            FruitMapper mapper = session.getMapper(FruitMapper.class);
            Fruit fruit = mapper.findById(1L);
            System.out.println(fruit);
        } finally {
            session.close();
        }
    }
}

上篇源码分析讲了 mybatis 一级缓存的实现原理。这次,我们来了解下 mybatis 接口的创建。

2. mapper接口的创建流程

2.1 SqlSession的getMapper()

首先,我们来看下 FruitMapper mapper = session.getMapper(FruitMapper.class); 这段代码,意思很简单,根据传入的class 获取这个对象的实例。这个流程有点复杂,阿粉带着大家来跟下源码:

首先还是ctrl + 左键点击 getMapper 方法,然后会进入到 SqlSessiongetMapper() 方法。然后之前阿粉也带着大家了解了, SqlSession 的默认实现类是 DefaultSqlSession ,所以我们直接看下 getMapper()DefaultSqlSession 里面的实现:

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

2.2  Configuration 的getMapper()

这里从 configuration 里面去获取, configuration 是全局配置对象,也就是上下文。参数 this 是当前的SqlSession 对象,继续跟进去看下:

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

2.3  MapperRegistry  的getMapper()

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

这里就不好看懂了,需要先看下了解下 MapperRegistry 这个类,我们一步一步来,跟着阿粉的思路走:

public class MapperRegistry {
  private final Configuration config;
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
  public MapperRegistry(Configuration config) {
    this.config = config;
  }
    ...
}

了解一个类,首先看下成员变量和构造方法。这里 config 不用多说了吧,主要的是 knownMappers 这个成员变量。这就是个map 对象,只是这个 map 对象的 value值是个对象,所以又要去看下 MapperProxyFactory 这个对象,点进去:

public class MapperProxyFactory<T> {
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>();
  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }
    ...
}public class MapperProxyFactory<T> {
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>();
  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }
    ...
}

首先,单独看下这个类名  MapperProxyFactory ,取名是很有学问的,好的名字让你一下就知道是干啥的。所以一看   MapperProxyFactory ,首先就会联想到工厂模式,工厂模式是干啥的?创建对象的,创建什么对象呢?创建 MapperProxy 对象的。MapperProxy 也是有玄机的,Proxy 的是什么?看到这个一般都是使用代理模式来创建代理对象的。所以就很清楚了,  MapperProxyFactory 这个类就是个工厂,创建的是 mapper 的代理对象。

然后这个类里面存的是 mapper 的接口和接口里面的方法。

最后,我们回到 MapperRegistry  类里面的 getMapper() 方法。现在是不是要清楚一些,通过 mapper 接口去 map 里面获取工厂类  MapperProxyFactory ,然后通过工厂类去创建我们的 mapper 代理对象。然后在看下  getMapper()  方法里面的 mapperProxyFactory.newInstance(sqlSession); 这段代码,继续点进去:

public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
}

你看,阿粉猜测对不对,MapperProxy 对象是不是出来了。然后看 newInstance() 这个方法:

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

两个 newInstance() 方法都在MapperProxyFactory 这个类里面,这里就很明显嘛。典型的 JDK 代理对象的创建。

好了,到这里我们的 mapper对象就获取到了。大家可以想一想,为什么获取一个 mapper 对象会那么复杂?或者说 mapper 对象有什么作用?其实就是为了通过 mapper 接口的方法获取到 mapper.xml 里面的 sql,具体怎么获取的,请允许阿粉卖个关子,请听阿粉下回分解。

3.总结

最后,阿粉以一个时序图来结束本篇文章,喜欢的话,记得点个赞哦。么么哒~

10.jpg

相关文章
|
2月前
|
SQL Java 数据库连接
Mybatis系列之 Error parsing SQL Mapper Configuration. Could not find resource com/zyz/mybatis/mapper/
文章讲述了在使用Mybatis时遇到的资源文件找不到的问题,并提供了通过修改Maven配置来解决资源文件编译到target目录下的方法。
Mybatis系列之 Error parsing SQL Mapper Configuration. Could not find resource com/zyz/mybatis/mapper/
|
1月前
|
SQL XML Java
mybatis :sqlmapconfig.xml配置 ++++Mapper XML 文件(sql/insert/delete/update/select)(增删改查)用法
当然,这些仅是MyBatis功能的初步介绍。MyBatis还提供了高级特性,如动态SQL、类型处理器、插件等,可以进一步提供对数据库交互的强大支持和灵活性。希望上述内容对您理解MyBatis的基本操作有所帮助。在实际使用中,您可能还需要根据具体的业务要求调整和优化SQL语句和配置。
30 1
|
2月前
|
XML Java 数据库连接
MyBatis中的接口代理机制及其使用
【8月更文挑战第5天】MyBatis的接口代理机制是其核心功能之一,允许通过定义接口并在运行时生成代理对象来操作数据库。开发者声明一个带有`@Mapper`注解的接口,MyBatis则依据接口方法、映射配置(XML或注解)及数据库信息动态生成代理类。此机制分为四步:创建接口、配置映射文件或使用注解、最后在业务逻辑中注入并使用代理对象。这种方式简化了数据库操作,提高了代码的可读性和可维护性。例如,在电商系统中可通过`OrderMapper`处理订单数据,在社交应用中利用`MessageMapper`管理消息,实现高效且清晰的数据库交互。
|
2月前
|
XML Java 数据库连接
Mybatis 模块拆份带来的 Mapper 扫描问题
Mybatis 模块拆份带来的 Mapper 扫描问题
33 0
|
3月前
|
Java 数据库连接 Maven
文本,使用SpringBoot工程创建一个Mybatis-plus项目,Mybatis-plus在编写数据层接口,用extends BaseMapper<User>继承实体类
文本,使用SpringBoot工程创建一个Mybatis-plus项目,Mybatis-plus在编写数据层接口,用extends BaseMapper<User>继承实体类
|
3月前
|
SQL
自定义SQL,可以利用MyBatisPlus的Wrapper来构建复杂的Where条件,如何自定义SQL呢?利用MyBatisPlus的Wrapper来构建Wh,在mapper方法参数中用Param注
自定义SQL,可以利用MyBatisPlus的Wrapper来构建复杂的Where条件,如何自定义SQL呢?利用MyBatisPlus的Wrapper来构建Wh,在mapper方法参数中用Param注
MybatisPlus--IService接口基本用法,MP提供了Service接口,save(T) 这里的意思是新增了一个T, saveBatch 是批量新增的意思,saveOrUpdate是增或改
MybatisPlus--IService接口基本用法,MP提供了Service接口,save(T) 这里的意思是新增了一个T, saveBatch 是批量新增的意思,saveOrUpdate是增或改
|
3月前
|
XML Java 数据格式
支付系统----微信支付20---创建案例项目--集成Mybatis-plus的补充,target下只有接口的编译文件,xml文件了,添加日志的写法
支付系统----微信支付20---创建案例项目--集成Mybatis-plus的补充,target下只有接口的编译文件,xml文件了,添加日志的写法
接口模板,文本常用的接口Controller层,常用的controller层模板,Mybatisplus的相关配置
接口模板,文本常用的接口Controller层,常用的controller层模板,Mybatisplus的相关配置
|
3月前
|
Java 数据库连接 Maven
Private method ‘getVideoList()‘ is never used,mybatis必须指定Mapper文件和实体目录,在参考其他人写的代码,要认真分析别人的代码,不要丢失
Private method ‘getVideoList()‘ is never used,mybatis必须指定Mapper文件和实体目录,在参考其他人写的代码,要认真分析别人的代码,不要丢失