Как получить basePackages @ComponentScan программно во время выполнения? - PullRequest
0 голосов
/ 12 июня 2018

scanBasePackages @SpringBootApplication настроен следующим образом:

package com.xxx.boot.sample;

@SpringBootApplication(scanBasePackages = { "com.xxx.boot.sample", "com.xxx.boot.service" })
public class DemoApplication {

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }

}

Требуется, чтобы мы хотели интегрировать Apache Dubbo компонентное сканирование аннотаций с Spring Boot путем программирования во время выполнения для нулевых свойствконфигурация, а не по аннотации.

@Configuration
@ConditionalOnClass({ EnableDubboConfig.class, AbstractConfig.class })
@ConditionalOnProperty(prefix = "dubbo", name = "enabled", havingValue = "true", matchIfMissing = true)
public class DubboAutoConfiguration {

  /// Dubbo配置

  @Configuration
  @EnableDubboConfig
  @ConditionalOnProperty(prefix = "dubbo.config", name = "enabled", havingValue = "true", matchIfMissing = true)
  @EnableConfigurationProperties(DubboProperties.class)
  public static class DubboConfigConfiguration {

  }

  /// Dubbo注解扫描

  @Configuration
  @ConditionalOnClass({ Service.class, Reference.class })
  @ConditionalOnProperty(prefix = "dubbo.annotation", name = "enabled", havingValue = "true", matchIfMissing = true)
  public static class DubboAnnotationConfiguration {

    @Bean(name = "serviceAnnotationBeanPostProcessor")
    @ConditionalOnMissingBean
    public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor(BeanFactory beanFactory) {
      // 获取 Spring Boot 主入口类所在的包路径
      List<String> packagesToScan = AutoConfigurationPackages.get(beanFactory);
      if (packagesToScan == null) {
        packagesToScan = Collections.emptyList();
      }
      return new ServiceAnnotationBeanPostProcessor(packagesToScan);
    }

    @Bean(name = ReferenceAnnotationBeanPostProcessor.BEAN_NAME)
    @ConditionalOnMissingBean
    public ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor() {
      return new ReferenceAnnotationBeanPostProcessor();
    }

  }

}

Но AutoConfigurationPackages#get(BeanFactory) возвращает только "com.xxx.boot.sample", не включая "com.xxx.boot.service".Я надеюсь вернуть все значения scanBasePackages.

При отладке я обнаружил, что экземпляр @SpringBootApplication является экземпляром прокси-класса.Я пытаюсь получить аннотацию, используя Class#getAnnotations, затем получаю поле scanBasePackages по отражению.Но не успех.

Вопрос:

Как получить scanBasePackages of @SpringBootApplication или basePackages of @ComponentScan программно?

1 Ответ

0 голосов
/ 12 июня 2018

Не рекомендуется пытаться повторно использовать атрибуты scanBasePackages для своих собственных целей.Если вы посмотрите на источник @SpringBootApplication, то увидите следующее:

@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};

@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};

Это говорит о том, что эти атрибуты являются псевдонимом для @ComponentScan.Поскольку эту аннотацию можно использовать в любом классе @Configuration, на самом деле их много.

Аннотация @ComponentScan запускает сканирование с помощью ConfigurationClassParser.Посмотрите на метод doProcessConfigurationClass для всех кровавых подробностей.

Если вы действительно хотите найти атрибуты аннотации самостоятельно, вы можете сделать следующее:

applicationContext.getBeansWithAnnotation(ComponentScan.class).forEach((name, instance) -> {
    Set<ComponentScan> scans = AnnotatedElementUtils.getMergedRepeatableAnnotations(instance.getClass(), ComponentScan.class);
    for (ComponentScan scan : scans) {
        System.out.println(Arrays.toString(scan.basePackageClasses()));
        System.out.println(Arrays.toString(scan.basePackages()));
    }
});

Это просто даст вам тедва значения.Вы по-прежнему не рассматриваете аннотации @Condition или какие-либо фильтры включения / исключения.Вы также не будете иметь дело с @ComponentScan(), что означает сканирование из текущего пакета вниз.

Что Spring Boot имеет тенденцию делать в этих обстоятельствах, так это определить новую аннотацию для конкретной цели.Например, вы можете использовать @EntityScan, чтобы определить, где находятся объекты JPA.Затем мы используем AutoConfigurationPackages в качестве значения по умолчанию, если вы не указали переопределение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...