当前位置:   article > 正文

mybatis springboot 整合源码分析 - springboot实战电商项目mall4j_mall4j部署

mall4j部署

springboot实战电商项目mall4j (https://gitee.com/gz-yami/mall4j)

java开源商城系统

代码版本

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.0</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

既然是springboot 那么要想知道怎么运行的,有从三个地方入手

  1. xxxAutoConfiguration
  2. yml对应的配置文件(xxxProperties
  3. 配置的注解

我们先来看三个类

1. MybatisAutoConfiguration 构造SqlSession

这个类通过dataSource的配置,构造出SqlSessionFactorySqlSessionTemplate。如果以前使用spring相关的api的话,应该会比较熟悉 jdbcTemplateredisTemplate 之类的。SqlSessionTemplate这个命名,就会让人联想到这个也是类似的功能。而session 这个词很明显就是与服务之间交互保存连接状态的东西。Factory是工厂模式。从而可以得出:SqlSessionFactory是用来创建SqlSession的,SqlSession可以打开或关闭与数据库的连接。SqlSessionTemplate 就是操作这些开关的关键。

@EnableConfigurationProperties(MybatisProperties.class)
public class MybatisAutoConfiguration implements InitializingBean {
   
  @Bean
  @ConditionalOnMissingBean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
   
      // 省略...
  }
  @Bean
  @ConditionalOnMissingBean
  public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
   
      // 省略...
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2. MybatisProperties 读取配置信息

这个类主要是将配置文件里面的配置转成bean映射,配置文件类似这个样子

#mybatis的相关配置
mybatis:
  #mapper配置文件
  mapper-locations: classpath:mapper/*Mapper.xml
  type-aliases-package: com.frozen-watermelon.**.model
  #开启驼峰命名
  configuration:
    map-underscore-to-camel-case: true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
@ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)
public class MybatisProperties {
   
  public static final String MYBATIS_PREFIX = "mybatis";
}
  • 1
  • 2
  • 3
  • 4
  • 5

3. @MapperScan 扫描Mapper接口

我们通常为了确定被扫描的mapper所属的包,都会有这样一个配置

@Configuration
@MapperScan({
    "com.frozen-watermelon.**.mapper" })
public class MybatisConfig {
   
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这里就有这个注解@MapperScan,那么这个注解是如何在源码中运用的呢?

我们先看下这个注解类

@Import(MapperScannerRegistrar.class)
public @interface MapperScan {
   
  String[] value() default {
   };
  String[] basePackages() default {
   };
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这里面@ImportMapperScannerRegistrar.class ,也就是说这个类被实例化了。这个类同时实现了ImportBeanDefinitionRegistrar 接口,也就是说 registerBeanDefinitions()这个方法会被调用

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
   
  @Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
   
    // 获取@MapperScan的配置信息
    AnnotationAttributes mapperScanAttrs = AnnotationAttributes
        .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    if (mapperScanAttrs != null) {
   
      registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,
          generateBaseBeanName(importingClassMetadata, 0));
    }
  }

  void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,
      BeanDefinitionRegistry registry, String beanName) {
   
    // 准备构建MapperScannerConfigurer
    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
    // 省略...
    List<String> basePackages = new ArrayList<>();
	// 获取注解的配置的信息,
    basePackages.addAll(
        Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));

    basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText)
        .collect(Collectors.toList()));
	builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));
    // 构建对象
    registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

从上面的代码可以看出最终构建了一个MapperScannerConfigurer对象。那么MapperScannerConfigurer到底是干嘛用的呢?MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor 接口,也就是说postProcessBeanDefinitionRegistry()这个方法创建完bean之后会被调用

public class MapperScannerConfigurer
    implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
   
  @Override
  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
   
    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    // 省略...
    // 扫描basePackage
    scanner.scan(
        StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

4. 创建mapper代理对象

我们来看下扫描干了啥


                
声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号