• mybatis源码分析(三) mybatis-spring整合源码分析


    mybatis源码分析(三) mybatis-spring整合源码分析

    一丶mybatis与springboot整合例子

      项目例子代码地址

     

    二丶springboot自动装配的关键配置代码

      

      org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

      1) 实例化SqlSessionFactory, 注意的是, SqlSessionFactoryBean是一个工厂Bean, 最后调用SqlSessionFactoryBean#getObject()生成对应的SqlSessionFacatory

      @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()));
        }
        applyConfiguration(factory);
        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 (this.properties.getTypeAliasesSuperType() != null) {
          factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
        }
        if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
          factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
        }
        if (!ObjectUtils.isEmpty(this.typeHandlers)) {
          factory.setTypeHandlers(this.typeHandlers);
        }
        if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
          factory.setMapperLocations(this.properties.resolveMapperLocations());
        }
        Set<String> factoryPropertyNames = Stream
            .of(new BeanWrapperImpl(SqlSessionFactoryBean.class).getPropertyDescriptors()).map(PropertyDescriptor::getName)
            .collect(Collectors.toSet());
        Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
        if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {
          // Need to mybatis-spring 2.0.2+
          factory.setScriptingLanguageDrivers(this.languageDrivers);
          if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {
            defaultLanguageDriver = this.languageDrivers[0].getClass();
          }
        }
        if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
          // Need to mybatis-spring 2.0.2+
          factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
        }
    
        return factory.getObject();
      }

       2) 生成SqlSessionTemplate

    @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);
        }
      }

       3)扫描Mapper类文件

       在配置@MapperScan注解之后,会调用MapperScannerRegistrar,会创建MapperScannerConfigurer bean定义及对象,然后根据MapperScan中的值,创建Mapper接口对应的MapperFactoryBean,在交由Spring管理的同时,可以生成对应的Mapper类,即使用SqlSession获取对应的Mapper对象.

    /**
       * This will just scan the same base package as Spring Boot does. If you want more power, you can explicitly use
       * {@link org.mybatis.spring.annotation.MapperScan} but this will get typed mappers working correctly, out-of-the-box,
       * similar to using Spring Data JPA repositories.
       */
      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);
          Stream.of(beanWrapper.getPropertyDescriptors())
              // Need to mybatis-spring 2.0.2+
              .filter(x -> x.getName().equals("lazyInitialization")).findAny()
              .ifPresent(x -> builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}"));
          registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());
        }
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) {
          this.beanFactory = beanFactory;
        }
    
      }

       

      

      MapperScannerConfigurer#postProcessBeanDefinitionRegistry()

    @Override
      public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        if (this.processPropertyPlaceHolders) {
          processPropertyPlaceHolders();
        }
    
        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        scanner.setAddToConfig(this.addToConfig);
        scanner.setAnnotationClass(this.annotationClass);
        scanner.setMarkerInterface(this.markerInterface);
        scanner.setSqlSessionFactory(this.sqlSessionFactory);
        scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
        scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
        scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
        scanner.setResourceLoader(this.applicationContext);
        scanner.setBeanNameGenerator(this.nameGenerator);
        scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
        if (StringUtils.hasText(lazyInitialization)) {
          scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
        }
        scanner.registerFilters();
      //委派给ClassPathMapperScanner#doScan()处理 scanner.scan( StringUtils.tokenizeToStringArray(
    this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); }

      ClassPathMapperScanner#doScan()

    /**
       * Calls the parent search that will search and register all the candidates. Then the registered objects are post
       * processed to set them as MapperFactoryBeans
       */
      @Override
      public Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
    
        if (beanDefinitions.isEmpty()) {
          LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages)
              + "' package. Please check your configuration.");
        } else {
          processBeanDefinitions(beanDefinitions);
        }
    
        return beanDefinitions;
      }
    
      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
          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);
        }
      }

      

     三丶思考

      Mybatis和Spring的整合, 即是在符合Spring的规则下, 使用Mybatis.

      如, 使用Mybatis的最主要的两个步骤, 一, 构建对应的SqlSessionFactory  二, 获取对应的Mapper对象. 这分别对应的MybatisAutoConfiguration的两个配置, sqlSessionFactory(DataSource dataSource), 和 AutoConfiguredMapperScannerRegistrar

      方法sqlSessionFactory(DataSource dataSource)生成的sqlSessionFactory,该实体类交由Spring管理

      使用@MapperScan指定了mapper接口之后, 触发调用AutoConfiguredMapperScannerRegistrar, 注册MapperScannerConfigurer Bean 定义之后, 委派ClassPathMapperScanner将扫描的mapper接口, 注册成MapperFactoryBean, 最后由MapperFactoryBean生成mapper对象.

     

     

     

    人生没有彩排,每一天都是现场直播
  • 相关阅读:
    three.js详解
    Javascript的原型
    Transform? Transition? Animation?
    Backbone源码分析Backbone架构+流程图
    对象是引用的注意原型中的属性改变
    MySQL+ JSP+Tomcat開發指引
    MySQL應用分析
    SQL 日期
    MySQL安裝
    MSE错误应对分享
  • 原文地址:https://www.cnblogs.com/timfruit/p/11489395.html
Copyright © 2020-2023  润新知