当前位置: 首页 > 知识库问答 >
问题:

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

龚跃
2023-03-14

我想实现一些类似于Spring数据的东西。

在spring初始化期间,我需要获得所有接口的列表(适当地注释)<为接口创建动态代理,并将它们注入到需要的地方。

代理创建,创建bean注入就可以了。现在问题来了:

如何找到所有接口的列表?

Reflections reflections = new Reflections("...");
Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(<annotation>);

因此,我需要一个基本包的完整列表,通过Spring扫描在包中找到我的接口(必须快得多)。

在SpringContext中肯定可以获得这些信息。我试图调试并查看basePackages[]是如何初始化的,但是有很多私有类/方法用于初始化,我只是不知道如何从ApplicationContext正确地访问basePackages。

共有1个答案

邢冷勋
2023-03-14

解决方案1:Spring的方式

最简单的答案是了解spring子项目(引导、数据...)实现这种类型的需求。他们通常定义一个自定义的组合注释来启用该特性,并定义一组要扫描的包。

例如,给定以下注释:

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

  String[] value() default {};
}
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);
        }
      }
    }
  }
}

MyCustomBean是一个简单的注释:

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

}

它可以注释接口

@MyCustomBean
public interface Class1 {

}

解决方案2:提取组件扫描

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
  List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();
  String[] candidateNames = registry.getBeanDefinitionNames();
  for (String beanName : candidateNames) {
    if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
      // Extract component scan
    }
  }
}

像Spring那样提取这些属性

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

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

 类似资料:
  • 问题内容: 到目前为止,我使用PyQt类所做的事情: 输出: 使用: 输出: 有没有办法区分它们? 可以使用普通的Python代替PyQt类吗? 如何获得IPv6地址? 问题答案: 您应该使用netifaces。它被设计为跨平台的,并且包含Windows专用代码以及可在不同UNIX / UNIX类平台上工作的各种通用版本。 从netifaces版本0.10.0开始,支持Python3。 使用摘要

  • 问题内容: 我可以想到两种方式: 惯用的方式是什么?也许已经有一个库函数可以完全满足我的需求? 问题答案: 我猜这种方式(或至少是另一种方式)更有效: 由于该函数与完全兼容,因为它需要并返回。不执行自动装箱。 我也在寻找一个等价的,我希望写一个等价的您的方法: 但是他们没有提供这种方法。不知道为什么。

  • 我定义了一个配置,其中包含每个表的列列表,用作dedup键 例如:配置1: 这些列需要用作重复数据消除键。这个列表是动态的,有些表中有1个值,有些表中有2或3个值 我想做的是从这个列表中建立一个键列 我如何使这个动态的列表适用于任意数量的列。我试过这么做 为了实现这一点,我必须将列表转换为Df,列表中的每个值都需要在单独的列中,我无法理解这一点。 试过这么做但没用 欢迎任何意见,谢谢

  • 基本信息 Path: /api/interface/list_menu Method: GET 接口描述: 请求参数 Headers 参数名称 参数值 是否必须 示例 备注 Content-Type application/json 是 Query 参数名称 是否必须 示例 备注 project_id 是 token 是 返回数据 { "errcode": 0, "errmsg": "成功

  • 基本信息 Path: /api/interface/list Method: GET 接口描述: 请求参数 Headers 参数名称 参数值 是否必须 示例 备注 Content-Type application/json 是 Query 参数名称 是否必须 示例 备注 project_id 是 token 是 page 是 1 当前页数 limit 是 10 每页数量,默认为10,如果不想要分页

  • 问题内容: 为了确定给定类型是否使用reflect包实现接口,您需要将reflect.Type传递给reflect.Type.Implements()。您如何获得这些类型之一? 作为一个例子,试图获得未初始化的os.Error(接口)类型的类型并 没有 工作(它恐慌的时候,你要调用它的种类()) 问题答案: 像这样做: 或一行: