Mybatis整合Spring

1,使用配置


1.1 引入mybatis整合spring的jar包

        <!--mybatis 和Spring整合 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>${mybatis-spring.version}</version>
        </dependency>

        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}</version>
        </dependency>

1.2,在spring的applicationContext.xml中配置SqlSessionFactoryBean,它是用来帮助我们创建会话的。同时配置需要扫描Mapper接口的路径。

    <!-- 在Spring启动时创建 sqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <property name="mapperLocations" value="classpath:mapper/*.xml"></property>
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.gupaoedu.crud.dao"/>
    </bean>

2,创建会话工厂


    我们在spring配置文件中配置了SqlSessionFactoryBean,我们来看下这个类。
    它实现了InitializingBean接口,所以要实现afterPropertiesSet()方法,这个方法会在bean的属性值设置完的时候被调用。
    又实现了FactoryBean接口,所以它初始化的时候,实际上是调用getObject()方法,它里面调用的也是afterPropertiesSet()方法。
    在afterPropertiesSet()方法中,我们实际上执行的还是mybatis那一步来创建初始化configuration对象和解析mapper文件,把接口和对应的MapperProxyFactory注册到mapperRegistry中。
    最后调用sqlSessionFactoryBuilder.build(targetConfiguration)返回一个DefaultSqlSessionFactory。

3,创建SqlSession


3.1,可以直接使用DefaultSqlSessionFactory创建吗?
    不能,它是不安全的,Spring用SqlSessionTemplate对SqlSession进行了包装。在编程式的开发中,我们会在每次请求的时候创建一个SqlSession,但是Spring中只有一个SqlSessionTemplate。SqlSessionTemplate中有SqlSession中的所有方法,不过它都是通过一个代理类对象实现的,这个代理对象是在构造方法里面通过一个代理类创建的。

    this.sqlSessionProxy = (SqlSession) newProxyInstance(
        SqlSessionFactory.class.getClassLoader(),
        new Class[] { SqlSession.class },
        new SqlSessionInterceptor());
    所有的方法都会先走到内部代理类SqlSessionInterceptor的invoke方法,

3.2,怎么拿到一个SqlSessionTemplate?
    Dao继承Mybatis提供的SqlSessionDaoSupport,就可以获得。
    为了减少代码量我们可以建立一个BaseDao继承SqlSessionDaoSupport拿到SqlSessionTemplate对象,然后定义一些基本的操作,其它的Dao都继承它。

3.3,有没有更好的方法拿到SqlSessionTemplate?
    3.2的方式,需要我们的每一个Dao层的接口想拿到SqlSessionTemplate对象,都需要去继承BaseDao编写一个实现类,工作量并不小,另一个我们调用方法的时候其实还是会使用硬编码的方式,MapperProxy根本用不上。那怎么解决呢?我们使用接口的扫描注册。

4,接口的扫描注册


    在Service层使用@Autowired自动注入Mapper接口,需要保存在BeanFactory中,也就是说接口肯定在Spring启动的时候就被扫描了,注册过的。

4.1,MapperScannerConfigurer是BeanFactoryPostProcessor的子类,可以通过编码的方式修改,新增或者删除某些Bean的定义。我们只需要重写postProcessBeanDefinitionRegistry()方法,在这里面操作Bean就行了。


4.2,ClassPathMapperScanner中的doScan方法调用了processBeanDefinitions()方法,在该方法中,注册beanDefinitions的时候,BeanClass被修改为MapperFactoryBean ?为什么要把它修改为MapperFactoryBean呢,因为MapperFactoryBean继承了SqlSessionDaoSupport,可以拿到SqlSessionTemplate。

5,接口注入使用


    我们使用Mapper的时候,只需要在加了Service注解的类里面使用@Autowired注入Mapper接口就好了。


    我们启动Spring去实例化EmployeeService的时候,发现它依赖了employeeMapper,这时候我们要根据它的名字去BeanFactory中获取它的BeanDefinition,再从BeanDefinition中获取他的BeanClass,上面已经知道这时候的BeanClass是MapperFactoryBean,因为它实现了FactoryBean接口,同样是调用getObject方法,





    通过调用SqlSessionDaoSupport中的getSqlSession拿到SqlSessionTemplate。接着调用mapperRegistry的getMapper方法,然后通过MapperProxyFactory新建一个MappProxy代理对象,最后调用Mapper接口的方法,也是执行MapperProxy的invoke方法。

    SqlSessionTemplate:Spring中SqlSession的替代品,线程安全的,通过代理的方式调用DefaultSqlSession的方法。
    SqlSessionInterceptor(内部类):代理对象,用来代理DefaultSqlSession对象,在SqlSessionTemplate中使用。
    SqlSessionDaoSupport:用于获取SqlSessionTemplate,只需要继承它就行,
    MapperFactoryBean:注册到IOC容器中替换接口类,它继承SqlSessionDaoSupport用于获取SqlSessionTemplate。
    SqlSessionHolder:控制SqlSession和事务。

6,设计模式总结

    工厂:SqlSessionFactory,MapperProxyFactory
    建造者:XMLConfigBuilder
    单例模式:SqlSessionFactory,Configuration
    代理:
        MapperProxy代理Mapper接口
        Plugin 插件
    模板:BaseExecutor与子类SimpleExecutor,BatchExecutor和ReuseExecutor
    装饰器:CachingExecutor对其他Executor额装饰。
    责任链:InterceptorChain
                    




相关推荐