MyBatis Spring 集成源码解析

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

1、Mybatis使用简介

1) SqlSessionFactory
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。

    String resource = "org/mybatis/example/mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

2)SqlSession
从 SqlSessionFactory 中获取 SqlSession,既然有了 SqlSessionFactory ,顾名思义,我们就可以从中获得 SqlSession 的实例了。SqlSession 完全包含了面向数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如:

    SqlSession session = sqlSessionFactory.openSession();
    try {
      Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
    } finally {
      session.close();
    }

诚然这种方式能够正常工作,并且对于使用旧版本 MyBatis 的用户来说也比较熟悉,不过现在有了一种更直白的方式。使用对于给定语句能够合理描述参数和返回值的接口(比如说BlogMapper.class),你现在不但可以执行更清晰和类型安全的代码,而且还不用担心易错的字符串字面值以及强制类型转换。

例如:

    SqlSession session = sqlSessionFactory.openSession();
    try {
      BlogMapper mapper = session.getMapper(BlogMapper.class);
      Blog blog = mapper.selectBlog(101);
    } finally {
      session.close();
    }

以上方法是单独使用Mybatis的方法。下面我们就来探究一下如何与Spring集成起来使用。

2、集成Spring配置

    <?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:component-scan base-package="com.spring.framework.carl" />

        <!-- Data Source -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="com.mysql.jdbc.Driver"/>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/>
            <property name="user" value="root"/>
            <property name="password" value="ilovemysql^^^"/>

            <property name="maxPoolSize" value="150"/>
            <property name="minPoolSize" value="10"/>
            <property name="initialPoolSize" value="20"/>
            <property name="maxIdleTime" value="3600"/>
            <property name="acquireIncrement" value="10"/>
            <property name="idleConnectionTestPeriod" value="1800"/>
        </bean>

        <!-- 扫描对应的XML Mapper -->
        <bean id="userSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource"/>
            <property name="mapperLocations">
                <list>
                    <value>classpath:com.spring.framework.carl.user.mapper/*.xml</value>
                </list>
            </property>
        </bean>

        <!-- 扫描对应的Java Mapper -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.spring.framework.carl.*.mapper"/>
            <property name="sqlSessionFactoryBeanName" value="userSqlSessionFactory"/>
        </bean>

    </beans>

以上就是Spring与MyBatis集成的基本文件了。当然有更多配置比如DataSource用数据库连接用properties文件,配置更多的MyBatis属性,如分页插件等等。上面的配置文件只是做讲解使用。

3、集成Spring原理解析

与Spring集成可以分为3个步骤.

  1. 把Java类对应的Mapper接口类纳入Spring中的IOC容器管理。
  2. 把Java类对应的XML命名空间添加到Mybatis中的Configuration类中的mapperRegistry(用于管理Mybatis的Mapper).
  3. 使用Spring中的IOC容器扩展FactoryBean获取到Mapper的实例。(第一步纳入Spring只是接口)

1.纳入SpringIOC容器管理

20191017100243\_1.png

上面时序图的主要步骤:

利用Spring的扩展BeanFactoryPostProcessor,扫描指定包下面的Mapper类,把类转换成Spring中IOC的Bean对象BeanDefinition,然后注册到IOC容器。并把BeanDefinition的BeanClass替换为MapperFactoryBean.class,这是一个Spring中的FactoryBean.这就和后面第三步的获取Mapper实例结合起来了。具体的代码如下:

      private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
        GenericBeanDefinition definition;
        for (BeanDefinitionHolder holder : beanDefinitions) {
          definition = (GenericBeanDefinition) holder.getBeanDefinition();

          if (logger.isDebugEnabled()) {
            logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() 
              + "' and '" + definition.getBeanClassName() + "' mapperInterface");
          }

          // the mapper interface is the original class of the bean
          // but, the actual class of the bean is MapperFactoryBean
          definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());
          definition.setBeanClass(this.mapperFactoryBean.getClass());

          definition.getPropertyValues().add("addToConfig", this.addToConfig);

          boolean explicitFactoryUsed = false;
          if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
            definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
            explicitFactoryUsed = true;
          } else if (this.sqlSessionFactory != null) {
            definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
            explicitFactoryUsed = true;
          }

          if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
            if (explicitFactoryUsed) {
              logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
            }
            definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
            explicitFactoryUsed = true;
          } else if (this.sqlSessionTemplate != null) {
            if (explicitFactoryUsed) {
              logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
            }
            definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
            explicitFactoryUsed = true;
          }

          if (!explicitFactoryUsed) {
            if (logger.isDebugEnabled()) {
              logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
            }
            definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
          }
        }
      }

重点代码如下:

    definition.setBeanClass(this.mapperFactoryBean.getClass());

2.初始化Mybatis中的Configuration

20191017100243\_2.png

上面时序图的主要步骤:

利用Spring的扩展InitializingBean,在IOC容器初始化之前,BeanDefinition设置Properties之后初始化Mybatis的Configuration。把XML的命名空间,也就是步骤一对应的Mapper类注册到Configuration中。

3.获取Mapper实例

20191017100243\_3.png

上面时序图的主要步骤:

利用Spring的扩展FactoryBean可以见之前的Blog – Spring bean 之 FactoryBean,来进行实例化Mapper。时间是我们的Service中依赖注入Mapper的时候。

4、调用MyBatis中的Mapper

熟悉Spring MVC的朋友都知道其中有一个DispatcherServlet用来分发HTTP的请求。那么MyBatis中也有一个分发(一家之言,嘻嘻),MapperProxy,这个类是实现了InvocationHandler。加上与Spring集成的时候生成实例是Proxy。没有错,就是Java的动态代理,可以参看我之前的Blog – Java JDK 动态代理,本文就到这,希望能成大家起到抛砖引玉的效果。

参考文章:Mybatis官网


来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » MyBatis Spring 集成源码解析

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏