@MapperScan и яма @Mapper

исходный код

Решите проблему с большим парнем сегодня. Объект, введенный @Autowired, не соответствует ожиданиям. Результат из-за проблемы со сканированием Mybatis.

@Mapper

Эта аннотация является классом аннотаций, сканируемым по умолчанию при автоматической настройке Mybatis.

image-20200102153553352

MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar#registerBeanDefinitions

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);
          }
        }
				
				// 扫描 @Mapper 注解的类
        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);
      }
    }

@MapperScan

Установите свойства сканирования, для ручного сканирования вы можете установить пакеты сканирования, примечания к сканированию и другую информацию.

image-20200102153856893

MapperScannerRegistrar#registerBeanDefinitions

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

    AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);

    // this check is needed in Spring 3.1
    if (resourceLoader != null) {
      scanner.setResourceLoader(resourceLoader);
    }

    Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
    if (!Annotation.class.equals(annotationClass)) {
      scanner.setAnnotationClass(annotationClass);
    }

    Class<?> markerInterface = annoAttrs.getClass("markerInterface");
    if (!Class.class.equals(markerInterface)) {
      scanner.setMarkerInterface(markerInterface);
    }

    Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
    if (!BeanNameGenerator.class.equals(generatorClass)) {
      scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
    }

    Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
    if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
      scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
    }

    scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
    scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));

    List<String> basePackages = new ArrayList<String>();
    for (String pkg : annoAttrs.getStringArray("value")) {
      if (StringUtils.hasText(pkg)) {
        basePackages.add(pkg);
      }
    }
    for (String pkg : annoAttrs.getStringArray("basePackages")) {
      if (StringUtils.hasText(pkg)) {
        basePackages.add(pkg);
      }
    }
    for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {
      basePackages.add(ClassUtils.getPackageName(clazz));
    }
    scanner.registerFilters();
    scanner.doScan(StringUtils.toStringArray(basePackages));
  }

С помощью приведенного выше кода можно обнаружить, что все пакеты, отсканированные @MapperScan, будут отсканированы (вставлены в MapperFactoryBean).

проблема

Если @MapperScan сканирует все по умолчанию, а @SpringBoot сканирует все, является ли объект в нем MapperFactoryBean или реальным объектом?

image-20200102155310133

MapperFactoryBean просканирован на наличие @service

решать

Опять же, это не проблема дизайна людей, а проблема использования

Почему Mybatis внедряет все классы по пути в отсканированном пакете

Если вас попросят спроектировать, как вы узнаете, является ли отсканированный класс тем классом, который MyBatis должен внедрить?

  1. специальное представительство

    Этот метод уже поддерживается @mapper, и его не нужно отсканировать. Он загружен по умолчанию. Если вы снова используете @Mapperscan, это действительно ненужно.

  2. Сканировать только пакет картографа

    Проблема вот в чем, если дело только в юзере, если не думать об этом, то скорее всего сканируете большой пакет напрямую, потому что лень.

личное предложение

На самом деле, мое личное предложение - делать это автоматически и стараться не делать это вручную.Поскольку автоматический был очень хорошо подготовлен провайдером, проблем не будет, но будут некоторые человеческие упущения или необдуманные или нереализованные проблемы в части ручного управления, в результате чего пользователь умрет, не подозревая об этом.

Так что лично я думаю, что лучший способ - это @Mapper, он будет завершен автоматически.