Mybatis整合springboot原理分析,MybatisAutoConfiguration,AutoConfiguredMapperScannerRegistrar

本章需要参考之前的两篇博客:

  • Mybatis整合spring原理分析,SqlSessionFactoryBean,MapperScan,MapperScannerRegistrar,MapperScannerConfigurer
  • springboot自动装配原理,底层源码分析,条件注解实现机制

从之前springboot自动装配原理,在资源目录下应该存在META-INF/spring.factories文件,查看mybatis-spring-boot-autoconfigure模块,其下该文件内容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

其中,MybatisLanguageDriverAutoConfiguration内容如下:

// MybatisLanguageDriverAutoConfiguration.java
@Configuration
@ConditionalOnClass(LanguageDriver.class)
public class MybatisLanguageDriverAutoConfiguration {
     

  private static final String CONFIGURATION_PROPERTY_PREFIX = "mybatis.scripting-language-driver";

  /**
   * Configuration class for mybatis-freemarker 1.1.x or under.
   */
  @Configuration
  @ConditionalOnClass(FreeMarkerLanguageDriver.class)
  @ConditionalOnMissingClass("org.mybatis.scripting.freemarker.FreeMarkerLanguageDriverConfig")
  public static class LegacyFreeMarkerConfiguration {
     
    @Bean
    @ConditionalOnMissingBean
    FreeMarkerLanguageDriver freeMarkerLanguageDriver() {
     
      return new FreeMarkerLanguageDriver();
    }
  }

  /**
   * Configuration class for mybatis-freemarker 1.2.x or above.
   */
  @Configuration
  @ConditionalOnClass({
      FreeMarkerLanguageDriver.class, FreeMarkerLanguageDriverConfig.class })
  public static class FreeMarkerConfiguration {
     
    @Bean
    @ConditionalOnMissingBean
    FreeMarkerLanguageDriver freeMarkerLanguageDriver(FreeMarkerLanguageDriverConfig config) {
     
      return new FreeMarkerLanguageDriver(config);
    }

    @Bean
    @ConditionalOnMissingBean
    @ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".freemarker")
    public FreeMarkerLanguageDriverConfig freeMarkerLanguageDriverConfig() {
     
      return FreeMarkerLanguageDriverConfig.newInstance();
    }
  }

  /**
   * Configuration class for mybatis-velocity 2.0 or under.
   */
  @Configuration
  @ConditionalOnClass(org.mybatis.scripting.velocity.Driver.class)
  @ConditionalOnMissingClass("org.mybatis.scripting.velocity.VelocityLanguageDriverConfig")
  @SuppressWarnings("deprecation")
  public static class LegacyVelocityConfiguration {
     
    @Bean
    @ConditionalOnMissingBean
    org.mybatis.scripting.velocity.Driver velocityLanguageDriver() {
     
      return new org.mybatis.scripting.velocity.Driver();
    }
  }

  /**
   * Configuration class for mybatis-velocity 2.1.x or above.
   */
  @Configuration
  @ConditionalOnClass({
      VelocityLanguageDriver.class, VelocityLanguageDriverConfig.class })
  public static class VelocityConfiguration {
     
    @Bean
    @ConditionalOnMissingBean
    VelocityLanguageDriver velocityLanguageDriver(VelocityLanguageDriverConfig config) {
     
      return new VelocityLanguageDriver(config);
    }

    @Bean
    @ConditionalOnMissingBean
    @ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".velocity")
    public VelocityLanguageDriverConfig velocityLanguageDriverConfig() {
     
      return VelocityLanguageDriverConfig.newInstance();
    }
  }

  @Configuration
  @ConditionalOnClass(ThymeleafLanguageDriver.class)
  public static class ThymeleafConfiguration {
     
    @Bean
    @ConditionalOnMissingBean
    ThymeleafLanguageDriver thymeleafLanguageDriver(ThymeleafLanguageDriverConfig config) {
     
      return new ThymeleafLanguageDriver(config);
    }

    @Bean
    @ConditionalOnMissingBean
    @ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".thymeleaf")
    public ThymeleafLanguageDriverConfig thymeleafLanguageDriverConfig() {
     
      return ThymeleafLanguageDriverConfig.newInstance();
    }
   }

可以看到,这个类主要就是注入一个LanguageDriver实现,主要逻辑在MybatisAutoConfiguration:

// MybatisAutoConfiguration.java
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({
      SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter({
      DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration implements InitializingBean {
     
...
@Bean
  @ConditionalOnMissingBean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
     
	....
	}
@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);
    }
  }
@org.springframework.context.annotation.Configuration
  @Import(AutoConfiguredMapperScannerRegistrar.class)
  @ConditionalOnMissingBean({
      MapperFactoryBean.class, MapperScannerConfigurer.class })
  public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
     

    @Override
    public void afterPropertiesSet() {
     
      logger.debug(
          "Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");
    }

  }
public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar {
     

    private BeanFactory beanFactory;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
     

      if (!AutoConfigurationPackages.has(this.beanFactory)) {
     
        logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");
        return;
      }

      logger.debug("Searching for mappers annotated with @Mapper");

      List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
      if (logger.isDebugEnabled()) {
     
        packages.forEach(pkg -> logger.debug("Using auto-configuration base package '{}'", pkg));
      }

      BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
      builder.addPropertyValue("processPropertyPlaceHolders", true);
      builder.addPropertyValue("annotationClass", Mapper.class);
      builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));
      BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class);
      Set<String> propertyNames = Stream.of(beanWrapper.getPropertyDescriptors()).map(PropertyDescriptor::getName)
          .collect(Collectors.toSet());
      if (propertyNames.contains("lazyInitialization")) {
     
        // Need to mybatis-spring 2.0.2+
        builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}");
      }
      if (propertyNames.contains("defaultScope")) {
     
        // Need to mybatis-spring 2.0.6+
        builder.addPropertyValue("defaultScope", "${mybatis.mapper-default-scope:}");
      }
      registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
     
      this.beanFactory = beanFactory;
    }

  }

下面我们逐一说明。

  1. 首先是该Enable起作用是当前环境下存在SqlSessionFactory.class, SqlSessionFactoryBean.class这两个类,还记得之前分析mybatis和spring整合的,就是通过SqlSessionFactoryBean,这就表示需要引入mybatis-spring依赖,而SqlSessionFactory则是mybatis本身的依赖,即pom需要引入mybatismybatis-spring这两个依赖MybatisAutoConfiguration才会起作用
  2. 获取SqlSessionFactory,如果当前IOC容器没有SqlSessionFactory类型的bean,则这里会创建一个
  3. 创建SqlSessionTemplate,如果当前IOC容器没有SqlSessionTemplate类型bean,则这里会创建一个
  4. 如果当前IOC容器没有MapperFactoryBean.class, MapperScannerConfigurer.class这两个bean,则会通过:
org.springframework.context.annotation.Configuration
  @Import(AutoConfiguredMapperScannerRegistrar.class)
  @ConditionalOnMissingBean({
      MapperFactoryBean.class, MapperScannerConfigurer.class })
  public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean 

通过AutoConfiguredMapperScannerRegistrar导入,其通过实现registerBeanDefinitions方法,将MapperScannerConfigurer这个类注入到了IOC容器中,还记得之前mybatis整合spring的时候怎么用到这个类的吗?这个就是众多的Mapper转成MapperFactory注入到了IOC容器中,至此,借助mybatis-spring,mybatis-springboot将SqlSessionFactoryBean和众多的Mapper都注入到IOC容器中,大家就可以愉快的使用了。

是不是感觉很简单,其实如果看了前面的两篇,这块理解起来就没什么难度了。

你可能感兴趣的:(MyBatis)