MyBatis杂记(3) Spring中Mybatis怎么扫描Mapper接口的?

Spring中Mybatis怎么扫描Mapper接口的?

package org.mybatis.spring.annotation;

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

@MapperScan注解上标识@Import(MapperScannerRegistrar.class)

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

  void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {

    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
    .
    .   
    .

    builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));

    registry.registerBeanDefinition(beanName, builder.getBeanDefinition());

  }
}

MapperScannerRegistrar 实现了ImportBeanDefinitionRegistrar接口 spring启动时会执行registerBeanDefinitions注册MapperScannerConfigurer的BeanDefinition并将basePackage设置到propertyValues; 

package org.mybatis.spring.mapper;

public class MapperScannerConfigurer
    implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {

  @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();
    scanner.scan(
        StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }
}

MapperConfigurer实现了BeanDefinitionRegistryPostProcessor,   invokeBeanFactoryPostProcessors(beanFactory)时调用到

postProcessBeanDefinitionRegistry创建ClassPathMapperScanner 扫描器,scanner.scan()扫描Mapper。

Mybatis中@Mapper注解需要 MapperScannerConfigurer 中annotationClass设置为Mapper.class。

如果MapperScan定义basepackage 范围大于mapper范围并且没有指定要扫描的注解:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): cn.net.immortal.user.service.command.AccountCmdService.login

在SpringBoot中不自定义MapperScan,则MybatisAutoConfiguration 自动配置AutoConfiguredMapperScannerRegistrar

basepackage为MainClass包,扫描Mapper注解。

最后

当@ConditionalOnMissingBean不满足条件时@Import也失效,原因:

推论@Condition不满足时@Import失效。

发布了16 篇原创文章 · 获赞 4 · 访问量 2028

猜你喜欢

转载自blog.csdn.net/qq_36592473/article/details/104092885