mybatis源码分析—— 与spring框架的整合

  mybatis-spring.jar 是mybatis与spring的整合,使用mybatis可以完成访问数据库的操作,通过SqlSession可以拿到Mapper的对象,

SqlSession维护了Configuration对象,缓存了knowMappers,class——MapperProxyFactory的映射,所以如果单纯的使用mybatis可以直接

sqlSession.getMapper手动获取。

一:单纯使用mybatis的方法

1:注册,sqlSessionFactoryBuildler或者SqlSessionFactoryBean创建SqlSessionFactory的时候,会解析mybatis-config.xml,最后一步

会解析mapper.xml文件,其中解析命名空间的时候,会将类型与动态代理工厂绑定。

数据源配置:

##数据源配置
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/study
jdbc.username=root
jdbc.password=root

  

mybatis-config.xml中的配置数据源以及mapper.xml文件

    <environments default="development">
        <!-- 配置环境,id:环境的唯一标识 -->
        <environment >
            <!-- 事务管理器,type:使用jdbc的事务管理器 -->
            <transactionManager type="JDBC" />
            <!-- 数据源,type:池类型的数据源 -->
            <dataSource type="POOLED">
                <!-- 配置连接信息 -->
                <property name="driver" value="${jdbc.driverClass}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>
    <!-- 配置映射文件:用来配置sql语句和结果集类型等 -->
    <mappers>
        <mapper resource="UserMapper.xml" />
    </mappers>

  

解析命名空间并注册绑定:

mybatis源码分析—— 与spring框架的整合

mybatis源码分析—— 与spring框架的整合

 mybatis源码分析—— 与spring框架的整合

2:使用的时候直接通过SqlSession.getMapper(class)获取Mapper对象(代理对象)

mybatis源码分析—— 与spring框架的整合

 mybatis源码分析—— 与spring框架的整合

mybatis源码分析—— 与spring框架的整合

 mybatis源码分析—— 与spring框架的整合

 测试代码:

mybatis源码分析—— 与spring框架的整合

可以正常查询结果:

mybatis源码分析—— 与spring框架的整合

 二:与spring的整合是怎么实现的

在spring-context.xml的文件中加载配置,配置数据源bean,使用SqlSessionFactoryBean创建SqlSessionFactroy

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:property-placeholder location="classpath:application.properties" />

    <!-- 配置数据源 -->
    <bean 
          destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClass}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>

    <!-- 指定数据源和配置文件路径 -->
    <bean >
        <property name="dataSource" ref="dataSource" />
        <!-- 自动扫描mapping.xml文件 -->
        <property name="mapperLocations" value="classpath:UserMapper.xml"></property>
    </bean>

    <!-- 配置单个mapper接口的映射器 -->
    <bean >
        <property name="mapperInterface" value="com.example.mybatis.mapper.UserMapper"></property>
        <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
    </bean>

    <!--<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.example.mybatis.mapper"></property>
    </bean>-->

</beans>

  

这里创建SqlSessionFactory对象的过程与mybatis直接创建有点区别,mybatis是通过SqlSessionFactoryBuilder创建,这里是FactoryBean

mybatis源码分析—— 与spring框架的整合

这个类实现了FactoryBean接口,InitializingBean接口

mybatis源码分析—— 与spring框架的整合

重写afterPropertiesSet,在这里解析mybatis-config.xml文件,生成Configuration对象,封装到SqlSessionFactory中返回。

mybatis源码分析—— 与spring框架的整合

 mybatis源码分析—— 与spring框架的整合

mybatis源码分析—— 与spring框架的整合

 mybatis源码分析—— 与spring框架的整合

解析mapper.xml文件,解析过程可以参考前面章节的mybatis-config.xml的解析。

 mybatis源码分析—— 与spring框架的整合

 上面是解析mapper.xml配置文件,将解析后的信息封装到configuration中,下面看一下如何整合绑定的

mybatis源码分析—— 与spring框架的整合

 mybatis-spring中有个比较重要的类MapperFactoryBean,实例化userMapper对象(代理),是通过创建MapperFactoryBean

这个bean元素下面有两个子元素,一个是mapperInterface,代理的接口,一个是sqlSessionFactory,在创建Bean对象的时候会设置属性

mybatis源码分析—— 与spring框架的整合

mybatis源码分析—— 与spring框架的整合

 设置sqlSessionFactory的时候实际上是把sqlSessionFactory封装到了sqlSessionTemplate中

mybatis源码分析—— 与spring框架的整合

 这个类实现了FactoryBean接口,所以实际上getBean得到的对象是getObject返回的代理对象

mybatis源码分析—— 与spring框架的整合

 这里的sqlSession就是上面再解析自定义标签bean的时候,实例化userMapper时,设置SqlSessionFactory的时候创建的

mybatis源码分析—— 与spring框架的整合

后面的过程就是mybatis中的逻辑,根据类type获取Mapper代理工厂,然后newInstance创建代理对象。

mybatis源码分析—— 与spring框架的整合

 mybatis源码分析—— 与spring框架的整合

来看一下创建sqlSessionTemplate的过程,所有的增删改查的动作都会为他给sqlSessionProxy代理来完成

mybatis源码分析—— 与spring框架的整合

代理增强: 

mybatis源码分析—— 与spring框架的整合

 每次执行增删改查操作都会创建一个SqlSession会话mybatis源码分析—— 与spring框架的整合

这是单个mapper和spring的整合,如果mapper比较多,使用这种配置的方式就比较繁琐了

所以扫描的方式相比效率就搞多了,下面我们来看一下扫描的逻辑:

配置如下:

把上面配置的单个的mapper注释掉,配置通过路径扫描来创建mapper代理:

mybatis源码分析—— 与spring框架的整合

首先来分析一下这个类:

mybatis源码分析—— 与spring框架的整合

 实现了四个接口,我们来复习一下这四个接口的作用:

BeanDefinitionRegistryPostProcessor,这个接口是在spring标准的BeanDefinition注册完成后,可以自定义BeanDefinition完成注册或者修改BeanDefinition的信息,也可以直接注册对象,是在BeanDefinition注册时期

InitializingBean接口,是bean实例化完成后的初始化方法,是在spring的aware接口初始化之后调用的

ApplicationContextAware接口:是在bean实例化完成后,初始化完成BeanNameAware等3个之后,使用BeanPostProcessor完成的初始化

BeanNameAware接口:是在bean实例化后,初始化的时候调用的

初始化顺序:BeanNameAware 早于 ApplicationContextAware 早于 InitializingBean

mybatis源码分析—— 与spring框架的整合

mybatis源码分析—— 与spring框架的整合

扫描并注册BeanDefinition对象,然后修改BeanDefinition对象的属性

mybatis源码分析—— 与spring框架的整合

具体扫描的逻辑:

mybatis源码分析—— 与spring框架的整合

具体设置属性信息,就是将扫描并注册的BeanDefinition,修改属性BeanClass 为MapperFactoryBean

mybatis源码分析—— 与spring框架的整合

mybatis源码分析—— 与spring框架的整合

这样扫描的BeanDefinition对象 ,实例化的时候都是MapperFactoryBean的实例了,不需要每个mapper都去配置xml了。