从源码的角度来解读spring整合mybatis 您所在的位置:网站首页 spring整合mybatis源码解析 从源码的角度来解读spring整合mybatis

从源码的角度来解读spring整合mybatis

2024-01-27 02:32| 来源: 网络整理| 查看: 265

目录 1、前言2、mybatis2.1 mybatis使用流程2.2 mybatis三个组件2.3 SqlSession2.4 Mapper接口式编程 3、spring整合mybatis3.1 SqlSessionFactoryBean3.3 SqlsessionTemplate3.3 MapperFactoryBean3.4 配置mapperScan 4、mybatis与spring流程小结

1、前言

spring整合mybatis几乎是每个Java开发学习过程中都会接触到的,相信很多人开始学习的时候都和博主一样,跟着视频或者博客把一大堆配置复制粘贴下来,然后运行发现没问题,于是就觉得自己掌握了。

但实际上真要细究spring和mybatis之间的关系时,大多数人都说不出来个所以然。

今天我们就从源码的角度来了解一下,从mybatis到mybatis-spring。

2、mybatis

作为一个半ORM框架,mybatis的流行度已经远超hibernate,毕竟hibernate的HQL学起来真是太伤神了。我们先从一个简单的例子来使用一下mybatis:

mybatis-config.xml

main:

public static void main(String[] args) throws IOException { InputStream fileInputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(fileInputStream); SqlSession sqlSession = factory.openSession(true); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.selectByid(1); System.out.println(user); sqlSession.close(); }

service,mapper什么的这里就不贴了,小白请自行去看入门博客~

2.1 mybatis使用流程

从上面的xml配置文件到主方法使用mapper调用查询方法,我们主要做了以下几件事:

配置DataSource,也就是我们要连接的数据库配置mapper位置,因为mybatis需要将mapper.xml与class联系起来读取主配置文件mybatis-config.xml通过SqlSessionFactoryBuilder构建SqlSessionFactory通过SqlSessionFactory打开一个SqlSession通过SqlSession获取Mapper实例

得到mapper实例对象之后,我们就可以进行相关操作了。

2.2 mybatis三个组件

从上述流程我们可以发现,使用mybatis涉及到了三个组件:

SqlSessionFactoryBuilder: 用于构建会话工厂,基于config.xml构建会话工厂,构建完成后即可丢弃。

SqlSessionFactory: 用于生成会话的工厂,作用于整个应用运行期间,一般不需要构造多个工厂对象

SqlSession: 作用于单次会话,如WEB一次请求期间,不能用作于某个对象属性,也不能在多个线程间共享,因为它是线程不安全的。

2.3 SqlSession

这里单独把SqlSession列出来,是因为这个接口实在是太重要了。它为我们提供了大量操作数据库的接口。

而在Mybatis中,SqlSession的实现类是DefaultSqlSession

在实际应用中,我们可以通过openSession方法拿到session之后,像JDBC那样去操作数据库:

在这里插入图片描述

但是这也太笨重了,如果Mybatis就这的话,还不如使用JDBC。

2.4 Mapper接口式编程

Mybatis通过Mapper接口式编程的方式,巧妙的让SqlSession实现类消失了,取而代之的是通过mapper.xml与mapper接口通过反射建立映射生成代理类的方法,用面向对象的方法来编程。

在DefaultSqlSession中,通过getMapper方法,我们可以得到Mapper的代理类实例:

public T getMapper(Class type, SqlSession sqlSession) { 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); } }

3、spring整合mybatis

我们都知道spring可以抽象为IOC容器,先不说具体流程,我们来思考一下,刚才mybatis的流程中,有哪些是可以交给spring管理的:

数据源DataSourceSqlSessionFactorySqlSessionTemplateMapper

我们通过引入org.mybatis.mybatis-spring包和spring之后,重新来配置一次简单的实例:

spring.xml:

main:

public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); UserMapper userMapper = context.getBean(UserMapper.class); System.out.println(userMapper.selectByid(1)); }

可以看到,spring整合mybatis之后的代码变得清爽了很多。

但是这中间出现了一个我们在之前没见过的东西:SqlSessionTemplate,同时更加令人困惑的是,不仅在配置中没有看到它,就连使用时也没有它,那么它到底是干嘛的呢?

在了解它之前,我们先介绍一下其它的组件。

3.1 SqlSessionFactoryBean

在MyBatis中要构建SqlsessionFactory对象,让它来产生 Sqlsession。在Mybatis-Spring中也不例外。

在一开始的数据源配置肯定是必不可少的,DriverManagerDataSource是spring自带的数据源,当然我们也可以选择配置Druid数据源。

而我们之前的SqlSessionFactory也被SqlSessionFactoryBean所替换,这也很好理解,spring把mybatis的SqlSessionFactory作为一个bean加入到了容器中。

3.3 SqlsessionTemplate

SqlsessionTemplate( org.mybatis.spring.SqlsessionTemplate)是一个模板类,它是SqlSession的一个实现类,通过Sqlsession来完成工作。

在Mybatis中,对应的就是DefaultSqlSession。而在MyBatis-Spring中,实现类就是我们的SqlsessionTemplate。

它为我们提供了大量方法以及对SqlSession生命周期的操作,我们可以通过添加如下配置来使用它:

public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); SqlSessionTemplate sqlSessionTemplate = context.getBean(SqlSessionTemplate.class); sqlSessionTemplate.selectList("……"); }

这个使用过程和DefaultSqlSession的使用没有什么差别?直接使用SqlsessionTemplate显得极为笨重,我们一般不会在代码中使用。

但是我们仍然需要操作SqlSession,在Mybatis中通过DefaultSqlSession的getMapper方法完成了对代理类的实例化,但是Spring明显不会每次还要显示调用getMapper方法。于是添加了MapperFactoryBean组件。

3.3 MapperFactoryBean

熟悉Spring的同学就应该能了解FactoryBean和BeanFactory的区别,这里简要提一下:

一般情况下,Spring通过反射机制利用的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂。

如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。

Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。

从宏观来看,MapperFactoryBean接口的逻辑就是为我们完成了从mapper的接口类到mapper的代理类创建,然后加入到Spring容器中。

3.4 配置mapperScan

假如我们需要第二个mapper时,我们就需要在xml中添加如下配置:

这从使用者的角度来说,简直就是噩梦。还好在mybatis.xml配置mapper时,就已经有包扫描的配置,我们只需要简单的进行如下配置即可:

那么接下来,我先要问你几个问题:

假如指定的包中,存在大量接口类,mybatis会把它们全部扫描进去并创建代理类吗?假如我创建了一个TestMapper接口,但是没有写对应的xml,会报错吗?如果会报错,是在什么时候报错呢?

这两个问题大家可以自行实践去查证,答案将在结尾给出。

4、mybatis与spring流程小结

我们再来做一次小结,对比一下mybatis与spring的差异:

mybatismybatis-springSqlSessionFactory通过SqlSessionFactoryBuilder读取配置文件构建通过SqlSessionFactoryBean的getObject方法获取SqlSession实现类DefaultSqlSessionSqlSessionTemplateMapper实例DefaultSqlSession.getMapper方法通过MapperFactoryBean的getObject方法返回实例,实际上是调用SqlSessionTemplate.getMapper方法

其它宏观或者微观细节大致上没有差异,比如xml解析流程,比如映射器和核心类Configuration,这些我虽然没有去求证过,但是想来不会有多少出入。

不过有需要注意的点是,在Spring中,Mapper是单例对象,但是Mapper与SqlSession是绑定在一起的,那这样一来,岂不是SqlSession也是单例的?为什么我们在实际使用过程中,不会出现线程安全问题呢?关于这个问题,博主会另写一篇博客介绍~

最后回答一下之前的两个问题:

会扫描进去并创建代理类,从而产生大量的无用代理对象,因此我们可以通过配置MapperSacnnerConfigurer来优化启动过程并不会报错,但是使用时会报错,有兴趣的读者可以去了解一下XML解析以及代理方法调用流程


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有