您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

如何从@ComponentScan软件包获取接口列表

如何从@ComponentScan软件包获取接口列表

最简单的答案是遵循spring子项目(引导,数据…)如何实现这种要求。他们通常定义一个自定义的合成批注,以启用该功能并定义一组要扫描的程序包。

例如,给出以下注释:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import({MyInterfaceScanRegistrar.class})
public @interface MyInterfaceScan {

  String[] value() default {};
}

在哪里value定义要扫描的软件包并@Import启用MyInterfaceScan检测。

然后创建ImportBeanDefinitionRegistrar。此类将能够创建bean定义

由在处理@Configuration类时注册其他bean定义的类型所实现的接口。在bean定义级别(与@Bean方法/实例级别相对)进行操作时很有用,这是必需的或必需的。

public class MyInterfaceScanRegistrar implements ImportBeanDeFinitionRegistrar, EnvironmentAware {
  private Environment environment;

  @Override
  public void setEnvironment(Environment environment) {
    this.environment = environment;
  }

  @Override
  public void registerBeanDeFinitions(AnnotationMetadata Metadata, BeanDeFinitionRegistry registry) {
    // Get the MyInterfaceScan annotation attributes
    Map<String, Object> annotationAttributes = Metadata.getAnnotationAttributes(MyInterfaceScan.class.getCanonicalName());

    if (annotationAttributes != null) {
      String[] basePackages = (String[]) annotationAttributes.get("value");

      if (basePackages.length == 0){
        // If value attribute is not set, fallback to the package of the annotated class
        basePackages = new String[]{((StandardAnnotationMetadata) Metadata).getIntrospectedClass().getPackage().getName()};
      }

      // using these packages, scan for interface annotated with MyCustomBean
      ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false, environment){
        // Override isCandidateComponent to only scan for interface
        @Override
        protected boolean isCandidateComponent(AnnotatedBeanDeFinition beanDeFinition) {
          AnnotationMetadata Metadata = beanDeFinition.getMetadata();
          return Metadata.isIndependent() && Metadata.isInterface();
        }
      };
      provider.addIncludeFilter(new AnnotationTypeFilter(MyCustomBean.class));

      // Scan all packages
      for (String basePackage : basePackages) {
        for (BeanDeFinition beanDeFinition : provider.findCandidateComponents(basePackage)) {
          // Do the stuff about the bean deFinition
          // For example, redefine it as a bean factory with custom atribute... 
          // then register it
          registry.registerBeanDeFinition(generateAName() , beanDeFinition);
          System.out.println(beanDeFinition);
        }
      }
    }
  }
}

这是逻辑的核心。可以将Bean定义作为具有属性的Bean工厂进行操作和重新定义,也可以使用从接口生成的类重新定义。

MyCustomBean一个简单的注释:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCustomBean {

}

可以注释接口:

@MyCustomBean
public interface Class1 {

}

提取软件包定义的代码@ComponentScan将更加复杂。

您应该创建一个BeanDefinitionRegistryPostProcessor并模仿ConfigurationClassPostProcessor

遍历bean注册表以使用具有ComponentScan属性的声明类(例如从中提取ConfigurationClassPostProcessor)来定义bean :

public void postProcessBeanDeFinitionRegistry(BeanDeFinitionRegistry registry) {

List con figCandidates = new ArrayList (); String[] candidateNames = registry.getBeanDe FinitionNames(); for (String beanName : candidateNames) { if (Con figurationClassUtils.checkCon figurationClassCandidate(beanDef, this. MetadataReaderFactory)) { // Extract component scan } } }

像Spring一样提取这些属性

Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
    sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);

然后扫描软件包并像第一个解决方案一样注册Bean定义

其他 2022/1/1 18:18:24 有428人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶