首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在运行时程序化获取@ComponentScan的basePackages?

如何在运行时程序化获取@ComponentScan的basePackages?
EN

Stack Overflow用户
提问于 2018-06-12 11:44:58
回答 1查看 2.2K关注 0票数 0

@SpringBootApplication的scanBasePackages配置如下:

代码语言:javascript
运行
复制
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集成在一起,而不是通过注释。

代码语言:javascript
运行
复制
@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 @SpringBootApplicationbasePackages of @ComponentScan

EN

回答 1

Stack Overflow用户

发布于 2018-06-12 14:32:21

为了您自己的目的而重用scanBasePackages属性并不是真正明智的做法。如果您查看@SpringBootApplication的源代码,您将看到以下内容:

代码语言:javascript
运行
复制
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};

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

也就是说,这些属性是@ComponentScan的别名。因为这个注解可以用在任何@Configuration类上,所以拥有很多这样的类实际上是合法的。

@ComponentScan注解触发了ConfigurationClassParser的扫描。看看doProcessConfigurationClass方法中所有血淋淋的细节。

如果您确实希望自己找到注释属性,可以执行以下操作:

代码语言:javascript
运行
复制
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作为默认值。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50808941

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档