MyBatis Spring 集成源码解析

来源:互联网 发布:js判断ios是否安装app 编辑:程序博客网 时间:2024/06/06 09:05

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容器管理

这里写图片描述

上面时序图的主要步骤:

利用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

这里写图片描述

上面时序图的主要步骤:

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

3.获取Mapper实例

这里写图片描述

上面时序图的主要步骤:

利用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 1
原创粉丝点击