栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【spring】spring集成Mybatis源码分析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【spring】spring集成Mybatis源码分析

spring集成Mybatis简单介绍

本文mybatis以Mybatis-Spring 1.3.2为主!集成的核心思路:成为spring的Bean。集成的实现方式:基于spring的FactoryBean。 Mybatis-Spring 1.3.2集成的思路

通过@MapperScan导入了MapperScannerRegistrar类。MapperScannerRegistrar类实现了importBeanDefinitionRegistrar接口,所以Spring在启动时会调用MapperScannerRegistrar类中的registerBeanDefinitions方法 。在registerBeanDefinitions方法中定义了一个ClassPathMapperScanner对象,用来扫描mapper。设置ClassPathMapperScanner对象可以扫描到接口,因为在Spring中默认是不会扫描接口的。同时因为ClassPathMapperScanner中重写了isCandidateComponent方法,导致isCandidateComponent只会认为接口是备选者Component。我们重写所有的接口不加@Component也可以被扫描到。通过利用Spring的扫描后,会把接口扫描出来并且得到对应的BeanDefinition。把扫描得到的BeanDefinition进行修改,把BeanClass修改为MapperFactoryBean,把AutowireMode修改为byType(用来读取set方法)。扫描完成后,Spring就会基于BeanDefinition去创建Bean了,相当于每个Mapper对应一个FactoryBean。在MapperFactoryBean中的getObject方法中,调用了getSqlSession()去得到一个sqlSession对象,然后根据对应的Mapper接口生成一个Mapper接口代理对象,这个代理对象就成为Spring容器中的Bean。sqlSession对象是Mybatis中的,一个sqlSession对象需要SqlSessionFactory来产生。MapperFactoryBean的AutowireMode为byType,所以Spring会自动调用set方法,有两个set方法,一个setSqlSessionFactory,一个setSqlSessionTemplate,而这两个方法执行的前提是根据方法参数类型能找到对应的bean,所以Spring容器中要存在SqlSessionFactory类型的bean或者SqlSessionTemplate类型的bean。如果你定义的是一个SqlSessionFactory类型的bean,那么最终也会被包装为一个SqlSessionTemplate对象,并且赋值给sqlSession属性 。而在SqlSessionTemplate类中就存在一个getMapper方法,这个方法中就产生一个Mapper接口代理对象 。到这里,有了Mybatis的代理对象,并且通过FactoryBean将其放入到spring的Bean中。 Mybatis-Spring 2.0.6集成的思路

通过@MapperScan导入了MapperScannerRegistrar类。MapperScannerRegistrar类实现了importBeanDefinitionRegistrar接口,所以Spring在启动时会调用MapperScannerRegistrar类中的registerBeanDefinitions方法。在registerBeanDefinitions方法中注册一个MapperScannerConfigurer类型的BeanDefinition。而MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor接口,所以Spring在启动过程中时会调用它的postProcessBeanDefinitionRegistry()方法。在postProcessBeanDefinitionRegistry方法中会生成一个ClassPathMapperScanner对象,然后进行扫描剩余逻辑和1.3.2版本一样。

// 可以通过@Bean的方式注入
@Bean 
public MapperScannerConfigurer mapperScannerConfigurer() {
    erScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
    mapperScannerConfigurer.setbasePackage("com.zhangwei");
    return mapperScannerConfigurer; 
}
源码分析:@MapperScan
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@documented
@import(MapperScannerRegistrar.class) // 导入了MapperScannerRegistrar类
@Repeatable(MapperScans.class)
public @interface MapperScan {

  // 传入的要扫描的包路径
  String[] value() default {};
    
  ......
}
MapperScannerRegistrar源码分析
public class MapperScannerRegistrar implements importBeanDefinitionRegistrar, ResourceLoaderAware {
    // spring启动会调用的方法
  public void registerBeanDefinitions(Annotationmetadata importingClassmetadata, BeanDefinitionRegistry registry) {

    // 得到MapperScan的注解信息
    AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassmetadata.getAnnotationAttributes(MapperScan.class.getName()));
    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);

    ......
    // 默认使用MapperFactoryBean
    Class mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
    if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
      scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
    }
    ......
        
    // 设置被扫描到的都可以成为Bean:IncludeFilter直接返回true
    scanner.registerFilters();
    // 进行扫描。这里面扫描完成后会设置definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);去保证MapperFactoryBean的set方法可以执行。
    // definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());使用构造方法,指定一个参数的!
    // definition.setBeanClass(this.mapperFactoryBean.getClass());设置具体的Beanclass
    scanner.doScan(StringUtils.toStringArray(basePackages));
  }
}
让spring可以扫描接口
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
  // 重新方法,让接口也可以成为Bean
  protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
    return beanDefinition.getmetadata().isInterface() && beanDefinition.getmetadata().isIndependent();
  }
}
MapperFactoryBean源码分析
public class MapperFactoryBean extends SqlSessionDaoSupport implements FactoryBean {

  private Class mapperInterface;

  private boolean addToConfig = true;

  public MapperFactoryBean() {
    //intentionally empty 
  }
  
  // 构造方法传入这个参数
  public MapperFactoryBean(Class mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  ......

  
  @Override
  public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }

  
  @Override
  public Class getObjectType() {
    return this.mapperInterface;
  }

  ......
}
MapperFactoryBean继承的SqlSessionDaoSupport源码分析
public abstract class SqlSessionDaoSupport extends DaoSupport {
  private SqlSession sqlSession;

  public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    if (!this.externalSqlSession) {
      this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
    }
  }

  public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
    this.sqlSession = sqlSessionTemplate;
    this.externalSqlSession = true;
  }
  // 将sqlSession进行依赖注入。之前代码设置为AUTOWIRE_BY_TYPE进行触发。
  public SqlSession getSqlSession() {
    return this.sqlSession;
  }
}   
结束语

获取更多本文的前置知识文章,以及新的有价值的文章,让我们一起成为架构师!关注公众号,可以让你对MySQL、并发编程、spring源码有深入的了解!关注公众号,后续持续高效的学习JVM!这个公众号,无广告!!!每日更新!!!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/756235.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号