mybatis源码解析

Posted 骆宏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis源码解析相关的知识,希望对你有一定的参考价值。

mybatis

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

核心类图

在这里面,我们一般会给出类图,但是要想制作一个类图,对于一个初步阅读源码的同学而言,还是有些难度的,因为难以抓住mybatis的要点,代码量也不小。下面我们换一个方式,使用idea的debug来观察数据。下面我们看一个spring集成mybatis的xml

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="$jdbc.app.driver"/>
        <property name="url" value="$jdbc.app.url"/>
        <property name="username" value="$jdbc.app.username"/>
        <property name="password" value="$jdbc.app.password"/>
        <property name="initialSize" value="$jdbc.app.initialSize"/>
        <property name="maxActive" value="$jdbc.app.maxActive"/>
        <property name="minIdle" value="$jdbc.app.minIdle"/>
        <property name="maxWait" value="$jdbc.app.maxWait"/>
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mapperLocations" value="classpath*:com/ucweb/union/dao/app/*.xml"/>
        <property name="plugins">
            <list>
                <ref bean="sqlInterceptor"/>
            </list>
        </property>
    </bean>


    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager" />

在上面的xml中,我们发现,SqlSessiontionFactoryBean是集成spring的入口类,理所当然的,我们会先去观察下该类的接口,我们只观察该类的属性,以及方法签名即可。

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> 

  private static final Log LOGGER = LogFactory.getLog(SqlSessionFactoryBean.class);

  private Resource configLocation;

  private Configuration configuration;

  private Resource[] mapperLocations;

  private DataSource dataSource;

  private TransactionFactory transactionFactory;

  private Properties configurationProperties;

  private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

  private SqlSessionFactory sqlSessionFactory;

  //EnvironmentAware requires spring 3.1
  private String environment = SqlSessionFactoryBean.class.getSimpleName();

  private boolean failFast;

  private Interceptor[] plugins;

  private TypeHandler<?>[] typeHandlers;

  private String typeHandlersPackage;

  private Class<?>[] typeAliases;

  private String typeAliasesPackage;

  private Class<?> typeAliasesSuperType;

  //issue #19. No default provider.
  private DatabaseIdProvider databaseIdProvider;

  private Class<? extends VFS> vfs;

  private Cache cache;

  private ObjectFactory objectFactory;

  private ObjectWrapperFactory objectWrapperFactory;

  public void setObjectFactory(ObjectFactory objectFactory)

  public void setObjectWrapperFactory(ObjectWrapperFactory objectWrapperFactory)

  public DatabaseIdProvider getDatabaseIdProvider()

  public void setDatabaseIdProvider(DatabaseIdProvider databaseIdProvider)

  public Class<? extends VFS> getVfs()

  public void setVfs(Class<? extends VFS> vfs)

  public Cache getCache()

  public void setCache(Cache cache)

  public void setPlugins(Interceptor[] plugins)

  public void setTypeAliasesPackage(String typeAliasesPackage)

  public void setTypeAliasesSuperType(Class<?> typeAliasesSuperType)

  public void setTypeHandlersPackage(String typeHandlersPackage)

  public void setTypeHandlers(TypeHandler<?>[] typeHandlers)

  public void setTypeAliases(Class<?>[] typeAliases)

  public void setFailFast(boolean failFast)

  public void setConfigLocation(Resource configLocation)

  public void setConfiguration(Configuration configuration)

  
  public void setMapperLocations(Resource[] mapperLocations)

  public void setConfigurationProperties(Properties sqlSessionFactoryProperties)

  public void setDataSource(DataSource dataSource)

  public void setSqlSessionFactoryBuilder(SqlSessionFactoryBuilder sqlSessionFactoryBuilder)

  public void setTransactionFactory(TransactionFactory transactionFactory)

  public void setEnvironment(String environment)

  public void afterPropertiesSet() throws Exception

  public SqlSessionFactory getObject() throws Exception;

  public Class<? extends SqlSessionFactory> getObjectType();

  public boolean isSingleton();

  public void onApplicationEvent(ApplicationEvent event);

从这里面,我们粗略的看了下,可以发现该类其实做的工作就是在根据参数,来进行mybatis的配置,包括:mapper,mapper.xml,事务管理等。然后沿着这几个特性,我们一一展开,即可逐步探究mybatis的内部机制了。该篇文章只是抛砖引玉,从Configuration出发,来看看mybatis的内部秘密。为了缩短篇幅,我们直接启动程序,使用debug模式,找到任何一个mabatis执行的地方,打个断点,观察下Configuration类。如下图所示


篇幅有限,就不一一截图了,从图中的属性我们可以看到,Configuration类包含了非常多的信息,比如:Mapper,MappedStatement,Interceptor,ResultMap,SqlFragment。这些概念其实就是我们对应平时使用Mybatis最常接触到的部分,下面根据对应关系,简单的过一下

  • Mapper,对应平时的Mapper类
  • MappedStatement,就是mapper.xml中的<select>,<update>,<insert>,<delete>
  • Interceptor,也就是myabtis的拦截器,比如常用的分页拦截器
  • ResultMap,也就是mapper.xml中的<resultMap>
  • SqlFragment,也就是mapper.xml中的dynamic sql部分,比如<if>,<where>,<foreach>等

从上面的列表可以看出,mybatis的封装很容易理解,有了上面的几个核心概念,接下来就是如何将mybatis的流程串起来,形成完整的调用过程了。由于这个模块,网上已经有很多作者写了不错的博客了,这里面我就不再细说,给个链接,有兴趣的朋友可以去查阅下,mybatis源码解析

总结

阅读源码,需要非常良好的耐心以及找到核心要点。比如在阅读mybatis源码时,如果没有把握好方式,我们很可能陷入了一行一行的细节代码,而不得要义,大蛇还得打七寸,虽然使用了mybatis有一段时间了,经过这次的系统化学习,也算是对mybatis有了更加熟练的掌握。

 

延伸与扩展

  • mybatis代码生成器的应用
  • mybatis自定义拦截器的应用
  • mybatis缓存的应用

以上是关于mybatis源码解析的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis源码解析-mybatis-spring原理解析

MyBatis源码解析SqlSession运行

Mybatis源码解析

mybatis插件机制源码解析

MyBatis 3源码解析

MyBatis 源码解析:SQL 语句的执行机制