zoukankan      html  css  js  c++  java
  • SpringBoot源码分析(三)整合MyBatis

    一、前言

    ​ SpringBoot中是没有MyBatis的,可以通过在使用SpringBoot时如果我们要用MyBatis的话,需要相比普通引用MyBatis需要多做哪些工作?来反推出整合自动配置的原理

    二、对比SpringBoot中使用MyBatis区别

    1.pom方面

    相比平时不一样的是,引用的是starter:

    <dependency>
    		<groupId>org.mybatis.spring.boot</groupId>
    		<artifactId>mybatis-spring-boot-starter</artifactId>
    		<version>1.3.2</version>
    </dependency>  
    

    2.注解

    在启动类打上了@MapperScan("top.yejian123.springbootM.mapper")

    3.配置文件

    application.properties

    # Mybatis相关配置
    mybatis:
        #核心配置文件路径
        config-location: classpath:mybatis/mybatis-config.xml
        #映射配置文件路径
        mapper-locations: classpath:mybatis/mapper/*.xml
    

    三、逐个分析

    3.1 跟进打开pom:

    <dependencies>
        <!--SpringBoot-->
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!--jdbc-->
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--autoconfigure-->
        <dependency>
          <groupId>org.mybatis.spring.boot</groupId>
          <artifactId>mybatis-spring-boot-autoconfigure</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
        </dependency>
        <!--mybatis-spring整合-->
        <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis-spring</artifactId>
        </dependency>
    </dependencies>
    

    引入了一堆依赖,实际上看下来,相比以前新花样只有mybatis-spring-boot-autoconfigure

    打开这个jar包看:

    mybatis-spring-boot-autoconfigure

    就四个文件,看到了MybatisProperties,源码:

    @ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)
    public class MybatisProperties {
    
      public static final String MYBATIS_PREFIX = "mybatis";
      
      //省略以下代码
    
    }	
    

    看到了@ConfigurationProperties,这也理解 application.properties 里配置的东西了,在这处理的

    3.2 @MapperScan("com.**.mapper")

    打开源码:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Documented
    @Import(MapperScannerRegistrar.class)
    public @interface MapperScan {
    	//...
    }
    

    导入了MapperScannerRegistrar,是spring和mybatis整合的时候扫描注册用的,监听相关事件通知完成扫描Mapper注册

    最终会发现主要是mybatis-spring-boot-autoconfigure,核心类是MybatisAutoConfiguration

    四、MybatisAutoConfiguration

    查看源码

    package org.mybatis.spring.boot.autoconfigure;
    
    @org.springframework.context.annotation.Configuration
    @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
    @ConditionalOnBean(DataSource.class)
    @EnableConfigurationProperties(MybatisProperties.class)
    @AutoConfigureAfter(DataSourceAutoConfiguration.class)
    public class MybatisAutoConfiguration {
    
      private final MybatisProperties properties;
    
      private final Interceptor[] interceptors;
    
      private final ResourceLoader resourceLoader;
    
      private final DatabaseIdProvider databaseIdProvider;
    
      private final List<ConfigurationCustomizer> configurationCustomizers;
    
      public MybatisAutoConfiguration(MybatisProperties properties,
                                      ObjectProvider<Interceptor[]> interceptorsProvider,
                                      ResourceLoader resourceLoader,
                                      ObjectProvider<DatabaseIdProvider> databaseIdProvider,
                                      ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) {
        this.properties = properties;
        this.interceptors = interceptorsProvider.getIfAvailable();
        this.resourceLoader = resourceLoader;
        this.databaseIdProvider = databaseIdProvider.getIfAvailable();
        this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();
      }
    
      @PostConstruct
      public void checkConfigFileExists() {
        if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) {
          Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());
          Assert.state(resource.exists(), "Cannot find config location: " + resource
              + " (please add config file or check your Mybatis configuration)");
        }
      }
    
      @Bean
      @ConditionalOnMissingBean
      public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class);
        if (StringUtils.hasText(this.properties.getConfigLocation())) {
          factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
        }
        Configuration configuration = this.properties.getConfiguration();
        if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
          configuration = new Configuration();
        }
        if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
          for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
            customizer.customize(configuration);
          }
        }
        factory.setConfiguration(configuration);
        if (this.properties.getConfigurationProperties() != null) {
          factory.setConfigurationProperties(this.properties.getConfigurationProperties());
        }
        if (!ObjectUtils.isEmpty(this.interceptors)) {
          factory.setPlugins(this.interceptors);
        }
        if (this.databaseIdProvider != null) {
          factory.setDatabaseIdProvider(this.databaseIdProvider);
        }
        if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
          factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
        }
        if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
          factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
        }
        if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
          factory.setMapperLocations(this.properties.resolveMapperLocations());
        }
    
        return factory.getObject();
      }
    
      @Bean
      @ConditionalOnMissingBean
      public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        ExecutorType executorType = this.properties.getExecutorType();
        if (executorType != null) {
          return new SqlSessionTemplate(sqlSessionFactory, executorType);
        } else {
          return new SqlSessionTemplate(sqlSessionFactory);
        }
      }
    
      public static class AutoConfiguredMapperScannerRegistrar
          implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware {
    
        private BeanFactory beanFactory;
    
        private ResourceLoader resourceLoader;
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
          logger.debug("Searching for mappers annotated with @Mapper");
    
          ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    
          try {
            if (this.resourceLoader != null) {
              scanner.setResourceLoader(this.resourceLoader);
            }
    
            List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
            if (logger.isDebugEnabled()) {
              for (String pkg : packages) {
                logger.debug("Using auto-configuration base package '{}'", pkg);
              }
            }
    
            scanner.setAnnotationClass(Mapper.class);
            scanner.registerFilters();
            scanner.doScan(StringUtils.toStringArray(packages));
          } catch (IllegalStateException ex) {
            logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex);
          }
        }
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
          this.beanFactory = beanFactory;
        }
    
        @Override
        public void setResourceLoader(ResourceLoader resourceLoader) {
          this.resourceLoader = resourceLoader;
        }
      }
    
      @org.springframework.context.annotation.Configuration
      @Import({ AutoConfiguredMapperScannerRegistrar.class })
      @ConditionalOnMissingBean(MapperFactoryBean.class)
      public static class MapperScannerRegistrarNotFoundConfiguration {
    
        @PostConstruct
        public void afterPropertiesSet() {
          logger.debug("No {} found.", MapperFactoryBean.class.getName());
        }
      }
    
    }
    
    

    会发现,

    ① : 导入了SqlSessionFactory
    ②:导入了sqlSessionTemplate
    ③:导入了mapperScanner

    Spring Boot启动时,会去实例化jar包mybatis-spring-boot-autoconfigure-starter中MybatisAutoConfiguration中的配置bean,包括SqlSessionFactory、SqlSessionTemplate。流程图如下:

    img

  • 相关阅读:
    Async/await 和 Promises 区别
    javaScript 如何使用js追加字符串呢?
    JavaScript深入之继承的多种方式和优缺点
    在原生JavaScript中创建不可变对象
    websocket的用途/场景
    爬虫新宠requests_html 带你甄别2019虚假大学 #华为云·寻找黑马程序员#
    #华为云·寻找黑马程序员#微服务-你真的懂 Yaml 吗?
    #华为云·寻找黑马程序员#【代码重构之路】使用Pattern的正确姿势
    Python-Excel 模块哪家强 #华为云·寻找黑马程序员#
    多元算力加持,华为云鲲鹏大数据服务公测上线
  • 原文地址:https://www.cnblogs.com/chz-blogs/p/13270200.html
Copyright © 2011-2022 走看看