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

前端之家收集整理的这篇文章主要介绍了java – 如何从@ComponentScan包获取接口列表前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

我想实现类似于Spring Data的东西.

开发人员可以定义一些接口,向接口添加自定义注释以标记它们(我的代码将为接口创建代理实例)并通过@Autowire将它们用于必要的服务.

在spring初始化期间,我需要获得所有接口的列表(正确注释)<为接口创建动态代理并将它们注入必要的位置. 代理创建,创建bean注入很好.现在的问题是: 如何查找所有接口的列表? 它们可以放在任何包装中(或者甚至放在一个单独的罐子里)并且有任何名称.扫描类路径上存在的所有类需要太多时间. 我找到了the question,但它需要基础包才能启动.

试过一个基于思考的解决方案,但它再次需要基础包或者从root开始需要非常大的时间来扫描所有可用的类.

  1. Reflections reflections = new Reflections("...");
  2. Set

所以我需要一个完整的基础包列表Spring扫描在包中找到我的接口(必须要快得多).

信息在SpringContext中绝对可用.我试图调试并看看basePackages []是如何初始化的,但是有很多私有类/方法用于初始化,我只是没有看到如何从ApplicationContext正确访问basePackages.

最佳答案
解决方案1:春天的方式

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

例如,给出这个注释:

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Import({MyInterfaceScanRegistrar.class})
  4. public @interface MyInterfaceScan {
  5. String[] value() default {};
  6. }

其中value定义要扫描的包,而@Import启用MyInterfaceScan检测.

然后创建ImportBeanDefinitionRegistrar.这个类将能够创建bean定义

Interface to be implemented by types that register additional bean
definitions when processing @Configuration classes. Useful when
operating at the bean definition level (as opposed to @Bean
method/instance level) is desired or necessary.

  1. public class MyInterfaceScanRegistrar implements ImportBeanDefinitionRegistrar,EnvironmentAware {
  2. private Environment environment;
  3. @Override
  4. public void setEnvironment(Environment environment) {
  5. this.environment = environment;
  6. }
  7. @Override
  8. public void registerBeanDefinitions(AnnotationMetadata Metadata,BeanDefinitionRegistry registry) {
  9. // Get the MyInterfaceScan annotation attributes
  10. MapMetadata.getAnnotationAttributes(MyInterfaceScan.class.getCanonicalName());
  11. if (annotationAttributes != null) {
  12. String[] basePackages = (String[]) annotationAttributes.get("value");
  13. if (basePackages.length == 0){
  14. // If value attribute is not set,fallback to the package of the annotated class
  15. basePackages = new String[]{((StandardAnnotationMetadata) Metadata).getIntrospectedClass().getPackage().getName()};
  16. }
  17. // using these packages,scan for interface annotated with MyCustomBean
  18. ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false,environment){
  19. // Override isCandidateComponent to only scan for interface
  20. @Override
  21. protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
  22. AnnotationMetadata Metadata = beanDefinition.getMetadata();
  23. return Metadata.isIndependent() && Metadata.isInterface();
  24. }
  25. };
  26. provider.addIncludeFilter(new AnnotationTypeFilter(MyCustomBean.class));
  27. // Scan all packages
  28. for (String basePackage : basePackages) {
  29. for (BeanDefinition beanDefinition : provider.findCandidateComponents(basePackage)) {
  30. // Do the stuff about the bean definition
  31. // For example,redefine it as a bean factory with custom atribute...
  32. // then register it
  33. registry.registerBeanDefinition(generateAName(),beanDefinition);
  34. System.out.println(beanDefinition);
  35. }
  36. }
  37. }
  38. }
  39. }

这是逻辑的核心. bean定义可以被操作并重新定义为具有属性的bean工厂,或者使用来自接口的生成类重新定义.

MyCustomBean是一个简单的注释:

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface MyCustomBean {
  4. }

哪个可以注释一个接口:

  1. @MyCustomBean
  2. public interface Class1 {
  3. }

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

提取@ComponentScan中定义的包的代码会更复杂.

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

>使用具有ComponentScan属性的声明类(例如,从ConfigurationClassPostProcessor中提取)迭代bean注册表以获取bean定义:

  1. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
  2. ListMetadataReaderFactory)) {
  3. // Extract component scan
  4. }
  5. }
  6. }

>像Spring一样提取这些属性

  1. SetMetadata(),ComponentScans.class,ComponentScan.class);

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

猜你在找的Spring相关文章