mybatis-spring原理解析

mybatis-spring简化了Mybatis在Spring中的操作,通过SqlSessionFactoryBean初始化,MapperScannerConfigurer扫描并注册Mapper,FactoryBean创建Mapper实例。在执行过程中,SqlSessionTemplate作为SqlSession代理,与Spring事务对接,实现事务管理。主要涉及SqlSessionFactory初始化、Mapper扫描注册、SqlSession与事务处理。
摘要由CSDN通过智能技术生成

mybatis-spring解析

概述

mybatis-spring让mybatis和Spring无缝对接,无需再关心mybatis中的Configuration、SqlSessionFactory、SqlSession,自动为Mapper创建实例注册到SpringIoc容器中, 并由Spring事务管理。在使用spring的前提下更加简化了Mybatis的操作,使用过程不用关心任何mybatis的相关概念。

 

Mybatis-spring主要做的内容包含:

  1. mybatis相关类 “Spring”化,都注册到Spring 容器中,对mapper额外提供批量扫描功能。

  2. 事务对接Spring,SqlSession交由Spring事务管理。

我们从使用过程到执行过程分步讲解原理。

 

一、初始化过程

入口:SqlSessionFactoryBean

使用Mybatis-spring,需要主动配置SqlSessionFactoryBean,所以配置初始化的流程从这里开始。

 

SqlSessionFactoryBean顾名思义是用于获取SqlSessionFactory,因此其实现了FactoryBean,用于自定义Bean实例化逻辑。

  • FactoryBean,用于自定义Bean实例化逻辑,并注册到Spring容器。SqlSessionFactory是一个很重的类,实例的化的过程比较复杂繁琐。

  • ApplicationListener,监听的是ContextRefreshedEvent事件,配置了快速失败时检查MapperedStatement是否加载完毕。

  • InitializingBean,真正开始实例化的时机,开始构建SqlSessionFactory。

 

1.1 SqlSessionFactory初始化 

@Override
public void afterPropertiesSet() throws Exception {
  notNull(dataSource, "Property 'dataSource' is required");
  notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
  state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
      "Property 'configuration' and 'configLocation' can not specified with together");

  // 开始构造
  this.sqlSessionFactory = buildSqlSessionFactory();
}
构造过程:

至此,
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {

  final Configuration targetConfiguration;

  XMLConfigBuilder xmlConfigBuilder = null;
    // 指定了mybatis-config.xml的路径时
    else if (this.configLocation != null) {
      // 构造xml解析器
      xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
      targetConfiguration = xmlConfigBuilder.getConfiguration();
    }
    // 啥都没指定,直接实例化Configuration,使用默认配置
    else {
      LOGGER.debug(
          () -> "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
      targetConfiguration = new Configuration();
      Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);
    }

  // 默认配置设置
  Optional.ofNullable(this.objectFactory).ifPresent(targetConfiguration::setObjectFactory);
  Optional.ofNullable(this.objectWrapperFactory).ifPresent(targetConfiguration::setObjectWrapperFactory);
  Optional.ofNullable(this.vfs).ifPresent(targetConfiguration::setVfsImpl);

  if (hasLength(this.typeAliasesPackage)) {
    scanClasses(this.typeAliasesPackage, this.typeAliasesSuperType).stream()
        .filter(clazz -> !clazz.isAnonymousClass()).filter(clazz -> !clazz.isInterface())
        .filter(clazz -> !clazz.isMemberClass()).forEach(targetConfiguration.getTypeAliasRegistry()::registerAlias);
  }

  // 别名注册
  if (!isEmpty(this.typeAliases)) {
    Stream.of(this.typeAliases).forEach(typeAlias -> {
      targetConfiguration.getTypeAliasRegistry().registerAlias(typeAlias);
      LOGGER.debug(() -> "Registered type alias: '" + typeAlias + "'");
    });
  }

  // 插件注册
  if (!isEmpty(this.plugins)) {
    Stream.of(this.plugins).forEach(plugin -> {
      targetConfiguration.addInterceptor(plugin);
      LOGGER.debug(() -> "Registered plugin: '" + plugin + "'");
    });
  }

  // 自定义类型处理器注册
  if (hasLength(this.typeHandlersPackage)) {
    scanClasses(this.typeHandlersPackage, TypeHandler.class).stream().filter(clazz -> !clazz.isAnonymousClass())
        .filter(clazz -> !clazz.isInterface()).filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()))
        .forEach(targetConfiguration.getTypeHandlerRegistry()::register);
  }

  if (!isEmpty(this.typeHandlers)) {
    Stream.of(this.typeHandlers).forEach(typeHandler -> {
      targetConfiguration.getTypeHandlerRegistry().register(typeHandler);
      LOGGER.debug(() -> "Registered type handler: '" + typeHandler + "'");
    });
  }

  if (!isEmpty(this.scriptingLanguageDrivers)) {
    Stream.of(this.scriptingLanguageDrivers).forEach(languageDriver -> {
      targetConfiguration.getLanguageRegistry().register(languageDriver);
      LOGGER.debug(() -> "Registered scripting language driver: '" + languageDriver + "'");
    });
  }
  Optional.ofNullable(this.defaultScriptingLanguageDriver)
      .ifPresent(targetConfiguration::setDefaultScriptingLanguage);

  if (this.databaseIdProvider != null) {// fix #64 set databaseId before parse mapper xmls
    try {
      targetConfiguration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
    } catch (SQLException e) {
      throw new NestedIOException("Failed getting a databaseId", e);
    }
  }

  Optional.ofNullable(this
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值