ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Mybatis整合到spring原理

2021-09-12 12:03:24  阅读:204  来源: 互联网

标签:Mapper sqlSessionFactory SqlSessionTemplate definition spring 整合 Mybatis MapperF


Mybatis整合到spring

SqlSessionTemplate整合

spring提供SqlSessionTemplate类,用于在spring中注入该类实例进行sql操作。该类实现了SqlSession接口,直接调用sqlSession的方法用于执行sql,该类持有SqlSessionFactory类,每次执行方法都会创建新的sqlSession。

  • SqlSessionTemplate类结构如下图。其中SqlSessionInterceptor是内部动态代理类,sqlSessionProxy代理对象执行的是内部类SqlSessionInterceptor的invoke方法。
    SqlSessionTemplate类结构
  • sqlSessionProxy是实现了SqlSession接口的动态代理类,SqlSessionTemplate的selectOne等方法执行的实际是代理类的invoke方法
this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor());
  • 代理类SqlSessionInterceptor每次执行invoke时都会生成新的SqlSession对象。就是通过这里保证每次sqlSession线程安全的。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//每次获取新的sqlSession
   SqlSession sqlSession = 
   SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
	...
}
  • 在使用时,需要每次都注入SqlSessionTemplate,为了方便,可以通过继承SqlSessionDaoSupport类。该类持有SqlSessionTemplate实例。

MapperScanConfiguration自动注入整合

通过上述SqlSessionTemplate方式还是不方便,可以通过定义Mapper接口,直接用@Autowired方式注入后直接使用。通过这个方式是怎么得到代理对象,怎么执行对应的sql的呢?

  • MapperScanConfiguration类实现了BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,在方法中扫描了Mapper类,封装成BeanDefinition,得到所有Mapper的BeanDefinition后执行BeanDefinition的setBeanClass方法,把beanClass修改为MapperFacotryBean.class,所以最终注册在BeanDefinition容器中的是MapperFacotryBean类。每个MapperFactoryBean还持有对应的Mapper类。这一步可以把无法实例化的Mapper接口变为可以实例化的MapperFactoryBean,也把对应的Mapper与后续创建的代理对象关联起来了。
//执行路径postProcessBeanDefinitionRegistry#ClassPathMapperScanner#doScan#processBeanDefinitions

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
    GenericBeanDefinition definition;
    for (BeanDefinitionHolder holder : beanDefinitions) {
      definition = (GenericBeanDefinition) holder.getBeanDefinition();
      String beanClassName = definition.getBeanClassName();
      LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName
          + "' mapperInterface");

      // the mapper interface is the original class of the bean
      // but, the actual class of the bean is MapperFactoryBean
      definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
//把获得的对应的Mapper接口类的BeanDefinition的类类型修改为MapperFactoryBean类型。
      definition.setBeanClass(this.mapperFactoryBeanClass);

      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) {
        LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
      }
      definition.setLazyInit(lazyInitialization);
    }
  }
  • MapperFactoryBean实现了FactoryBean接口,所以在spring容器实例化阶段,实例化的bean是从getObject方法返回的对象。MapperFactoryBean继承了SqlSessionDaoSupport,可以拿到SqlSession,参看前面的Mybatis执行流程可以得到Mapper的代理对象,所以注册到IoC容器的其实是MapperProxy生成的Mapper代理对象。
 @Override
  public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }
  • 在使用时,spring会注入对应的Mapper的代理对象,执行MapperProxy的invoke方法对sq进行操作。

标签:Mapper,sqlSessionFactory,SqlSessionTemplate,definition,spring,整合,Mybatis,MapperF
来源: https://blog.csdn.net/scnliu/article/details/120247762

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有